head.s 通过编译链接的处理,同时被 boot.s 加载到保护模式零地址开始运行,在最后会调用 main 函数。
代码:
/* * head.s contains the 32-bit startup code. * * NOTE!!! Startup happens at absolute address 0x00000000, which is also where * the page directory will exist. The startup code will be overwritten by * the page directory. * 注意:启动程序在 0x00000000,同时这个地址也是页表的地址,在这个启动完成后,这里的程序与数据会被页表覆盖。 */ .code32 .text .globl idt, gdt, pg_dir, startup_32 pg_dir: startup_32: movl $0x10,%eax # 已经处于32 位保护模式,$0x10 是全局描述符表项的选择符 mov %ax,%ds mov %ax,%es mov %ax,%fs mov %ax,%gs lss stack_start,%esp # 设置系统堆栈:ss,esp,stack_start 在 kernel/sched.c, 40 行 call setup_idt # 设置中断描述符表 call setup_gdt # 设置全局描述符表 # 因为修改了gdt,所以需要重新装载所有的段寄存器 movl $0x10,%eax # reload all the segment registers mov %ax,%ds # after changing gdt. CS was already mov %ax,%es # reloaded in 'setup_gdt' mov %ax,%fs mov %ax,%gs lss stack_start,%esp xorl %eax,%eax # 测试A20 地址线是否已经开启,如果没有开启,内核无法使用大于 1M 的内存 # 采用的方法是向内存地址0x000000 处写入任意数值, # 检查 0x100000(1M) 处是否也是这个数值。 1: incl %eax # check that A20 really IS enabled movl %eax,0x000000 cmpl %eax,0x100000 je 1b # 向后寻找标号 # CR0 : http://en.wikipedia.org/wiki/Control_register movl %cr0,%eax # check math chip andl $0x80000011,%eax # Save PG,ET,PE testl $0x10,%eax # test MP 位 jne 1f # ET is set - 387 is present orl $4,%eax # else set emulate bit, EM 位 1: movl %eax,%cr0 jmp after_page_tables /*********************************setup_idt*******************************/ /* * setup_idt * * sets up a idt with 256 entries pointing to * ignore_i