linux-0.11中保护模式建立过程的分析[2]

来源:互联网 发布:交通数据 编辑:程序博客网 时间:2024/05/01 02:34

setup.s代码中没有重新设置栈寄存器,所以在setup.s中使用的栈是在bootsect.s中设置好的栈。程序开始的代码重新设置段寄存器ds,因为现在的CS段值是0x9020,而代码的数据段是与代码段重叠的,所以要重新段寄存器ds,让它等于CS的段值。

36         mov     ax,#INITSEG ! this is done in bootsect already, but...
37         mov     ds,ax

然后setup.s就利用BIOS中断,得到一些与硬件相关的信息,并把这些参数放到某个固定的位置(0x9000:0x0000)以提供给后来的程序使用。在使用完BIOS中断后,那么BIOS的中断描述符表就可以被覆盖了,所以接着setup.s就把system模块搬运绝对地址0x00000处。接下来就是setup.s代码一个很重的任务,为CPU进入32位保护模式运行设置好IDT表和GDT表。与IDT表和GDT表有着密切关系的寄存器是IDTRGDTR寄存器,它们分别存放着IDT表和GDT表的基地址。

133         lidt    idt_48          ! load idt with 0,0
134         lgdt    gdt_48          ! load gdt with whatever 
! appropriate
205 gdt:
206         .word   0,0,0,0         ! dummy
207 
208         .word   0x07FF          ! 8Mb - limit=2047 (2048*4096=8Mb)
209         .word   0x0000          ! base address=0
210         .word   0x9A00          ! code read/exec
211         .word   0x00C0          ! granularity=4096, 386
212 
213         .word   0x07FF          ! 8Mb - limit=2047 (2048*4096=8Mb)
214         .word   0x0000          ! base address=0
215         .word   0x9200          ! data read/write
216         .word   0x00C0          ! granularity=4096, 386
217 
218 idt_48:
219         .word   0                       ! idt limit=0
220         .word   0,0                     ! idt base=0L
221 
222 gdt_48:
223         .word   0x800           ! gdt limit=2048, 256 GDT entries
224         .word   512+gdt,0x9     ! gdt base = 0X9xxxx

关于在32位模式的寻址方式可以查阅相关的资料,在这里不多说。我比较关心的是CPU是如何从实模式过度到保护模式的。要进入保护模式就要置位寄存器CR0PE位。Linux是通过下面的代码做到的:

191         mov     ax,#0x0001      ! protected mode (PE) bit
192         lmsw    ax              ! This is it!
193         jmpi    0,8             ! jmp offset 0 of segment 8 (cs)

也许你会问:在执行完指令 lmsw   ax  后,CPU就进入了32位的保护模式,那么紧接着的指令jmpi  0,8在保护模式下不就没办法准确寻址了吗?其实在这里要归功于预取指令的作用,当执行指令lmsw  ax时,指令jmpi   0,8已经在实模式下被预先取得。所以说在设置寄存器CR0PE位后下一条指令必须是段间跳转指令,用来更新CS寄存器的内容,并使得CPU预先取得的指令无效,这样就可以让CPU在进入32位保护模式时可以正确的取指令和寻址。在这里要注意jmpi 0,8这条指令,指令中的偏移地址是0,而段值8已经是保护模式下的段选择子。段值80b0000,0000,0000,1000)表示请求特权级0,使用全局描述表中的第一项,该项指出代码的基地址是0。因为在之前,linux已经把SYSTEM模块搬运到0x00000地址处,所以该指令的结果就是让CPU开始去运行SYSTEM模块的代码。到此为止,CPU开始工作在32位的保护模式,但是还没有开启地址的页变换管理。执行完这条跳转指令以后,CPU各寄存器的值如图4

总结一下,setup.s利用BIOS中断得到了一些硬件信息,并把他们放在指定的位置供内核使用。在不在使用BIOS中断的情况下把system模块搬到0x00000处,然后在设置好IDT表和GDT表的情况下开启了保护模式,为system模块的运行提供了基本的环境。

4:刚进入32位保护模式时各CPU的值

原创粉丝点击