head.s

  • 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)
    重新加载gdt后,应该将各个寄存器重新赋值,以刷新影子寄存器的内容。0.12中没有使用jmp指令刷新CS段寄存器,谨记,修改gdt表后要重新加载相关寄存器
  • 测试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()以外返回时的返回地址,让其死循环。

你可能感兴趣的:(head.s)