2005年4月28日星期四

head.s 分析[原创]

2005-04-28 BY:LinuxRen
head.s就运行在32位保护模式下面了,这里是名副其实的内核了

GNU 的汇编直接数,比如 0x10,如果前面有$,即$0x10,则表示立即数,在16位实模式下,内存地址由段基地址左移四位加上段内偏移量组成,而在保护模式下,由段选择子 (逻辑地址的高16位 )(由段选择子选择的描述符所决定的段基地址不需要左移,直接加偏移地址就可以形成线性地址)和段内偏移量(逻辑地址的低16位)组成,这里是内存管理中 的段式管理,还有页式管理(以后再说),这里有张图片可以很好地说明段式管理:

如果仅仅是0x10,则表示内存的地址。

这张图片好像有个小问题,右上角的偏移量应该是32位的,这里很容易给人错觉好像偏移量就是逻辑地址的低16位,段选择子时逻辑地址的高16位,可以从intel的手册得到证实 其中的图5-2,呵呵,intel应该不会犯错吧

为什么既有段式内存管理,也有页式内存管理,我想大概是cpu设计的原因,如果cpu加电直接就可以进入32位,那么段式管理就应该报废了。也不知道现在的64位的cpu是怎么处理的,现在64微处理器的资料实在太少了。

head.s 第18行,movl $0x10, %eax 之后eax就相当于段选择子,与gdt表的地址进行运算,就可以定为一个全局描述符,在全局表述符中会给出对应段的段基址,再加上已知的段内 偏移量,就可以将一个逻辑地址转为一个线性地址,这里的0x10仅仅是段选择子。

然后call setup_idt, setup_idt代码在79行,就是将idt中的每一项都设置为指向同一个中断门ignore_int,即打印一段信息“Unknown interrupt”

在这里说一下idt,idt就是中断描述符表,和全剧描述符表是一个等级的,相应的中断描述符表项和全局描述符表项是对应的,中断门ignore_int是和全局描述符表项所表述的段一个等级的,只不过这里的不是一个段,而可以是一段代码,这样就应该容易理解了吧。

接 着call setup_gdt,gdt在前面已经临时设置过了,在这里要重新设置.这里将gdt还是设置成为含有256个全局描述符表项,第0个不用,第一个系统代 码段,第二个系统数据段,值分别是 0x00c09a0000000fff 0x00c09020000000fff,可以对照着张表来看看具体的意思:


这里将系统代码段和系统数据段的段长都设置成为了16M.

后面的252项都填充0,用于以后用户程序使用。

接下来就是检查数学协处理器,还有什么287/387,没看,跳过。

然后就是开启分页管理

这里的分页机制是专门为内核使用的,也就是说以后的应用程序并不适用这里的页表,而是在程序执行的时候自己自动加载自己的页表。

这里的分页比较简单,经过分页之后的物理地址是和分页前的线性地址相同的,这一点是非常重要的。因为在分页启动之前有一句话: pushl $_main
这里是将main函数的地址压栈,当分页启动之后要讲这个地址pop出来,并且跳到main去执行,系统就会跳到以前压入栈的main的地址经过分页映射后的地址去运行,如果物理地址和线性地址不一样的话,那么就会跳到错误的地方,但是这里不会。

没有评论:

发表评论