1:功能
setup在获取一些硬件参数,启动保护模式后,就会进入head.s代码中执行。
head.s中会进行:
1)设置中断表
2)设置GDT表
3)设置页表
4)跳转到main函数
2:代码实现
2.1 设置中断表
重新设置中断描述符idt,共256项,并使各个表项均指向一个只报错误的哑中断程序
setup_idt:
lea ignore_int,%edx
movl $0x00080000,%eax
movw %dx,%ax /* selector = 0x0008 = cs */
movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
lea idt,%edi
mov $256,%ecx
rp_sidt:
movl %eax,(%edi)
movl %edx,4(%edi)
addl $8,%edi
dec %ecx
jne rp_sidt
lidt idt_descr
ret
2.2 设置GDT表
虽然在setup中设置了gdt表,但是是为了临时执行“jumpi 0,8”,现在需要重新建立
setup_gdt:
lgdt gdt_descr
ret
gdt_descr:
.word 256*8-1 # so does gdt (not that that's any
.long gdt # magic number, but it works for me :^)
.align 8
idt: .fill 256,8,0 # idt is uninitialized
gdt: .quad 0x0000000000000000 /* NULL descriptor */
.quad 0x00c09a0000000fff /* 16Mb */
.quad 0x00c0920000000fff /* 16Mb */
.quad 0x0000000000000000 /* TEMPORARY - don't use */
.fill 252,8,0 /* space for LDT's and TSS's etc */
2.3 设置页表
.align 2
setup_paging:
movl $1024*5,%ecx /* 5 pages - pg_dir+4 page tables */
..................
2.4 跳转到main函数
pushl $L6作为模拟调用main.c程序时返回地址作为入栈操作,如果main真的退出是,就会进入死循环
将main.c压人栈中,这样分页处理介绍后执行ret,就会进入main函数
after_page_tables:
pushl $0 # These are the parameters to main :-)
pushl $0
pushl $0
pushl $L6 # return address for main, if it decides to.
pushl $main
jmp setup_paging
L6:
jmp L6
3:总结
head.s执行结束后,整个内存映像如下