- stack_start,定义在kernel/sched.c中。使用lss指令加载,所以stack_start为一个结构体,低字节为long*,高位为short。实际48位长地址为0x10:user_stack。user_stack为sched.c中定义的数组。
- 设置idt,256个描述符都指向ignore_int中断例程,显示一句消息,中断门描述符,包含48位长指针
- 设置gdt,与setup中的基本一样,段长变为16M。
- 代码段描述符。特权值0,存在,可读非一致性代码段,段长度(段限长+1)16M,颗粒度G=1(4kb),D=1(32位地址,32位或8位数据)
- 数据段描述符。特权值0,存在,非下扩段,可读可写,未访问,B=1使用32位esp,G=1(4kb),段长度(16M)
- 测试A20地址线是否打开。比较0x000000与0x100000的内容,若果相等,[0x000000]的内容增加1,再循环比较。若果无法寻址则陷入死循环。
- 设置页目录表及对应的页表,设置cr0让cpu进入分页机制。页目录表位于0x00000000;紧接着是4个页表,分别存在于0x00001000,0x00002000,0x00003000,0x00004000。页目录,页表的属性一样:可供任意特权级访问(U/S=1),可读,可写或可执行(R/W=1),存在(P=1)。在为页表建立映射时,使用了一个技巧,从16M-4k开始建立,这样可以根据每次减去1024,判断目的地址是否大于等于0,大于等于0则继续。充分利用标志寄存器的值,注意0标志的作用,而不需像递增时那样再与16M比较。根据已有的条件作判断,不要再做无用功。
- 进入main()函数。通过push传递main的参数,包括main的地址。在after_page_tabes后,ret进入main。在main地址之前压了,envp,arvp指针和argc的值,还有一个当main()以外返回时的返回地址,让其死循环。