linux 0.11 源码学习(五)

head.s

head.s 是系统模块的入口,其编译器已经是GNU汇编,但从功能上将仍然属于内核启动阶段,主要的功能是对386 CPU的初始化,如用户堆栈、IDT、GDT和页表。因此从文件夹的归属看,它仍然放在boot文件夹中,与bootsect和setup一块。head.s的核心功能(简单的寄存器初始化不做赘述)如下:

  • 初始化堆栈寄存器:lss stack_start, %esp,其中stack_start定义在sched中,如下:
struct {
    long * a;
    short b;
    } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 };
  • 初始化中断描述符表,256个中断描述符都被挂接一个叫ignore_int的函数,只打印消息不做处理,如下:
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 //设置idt中的256个中断描述符
    mov $256,%ecx
rp_sidt:
    movl %eax,(%edi)
    movl %edx,4(%edi)
    addl $8,%edi
    dec %ecx 
    jne rp_sidt //如果ecs(256) != 0,则跳转
    lidt idt_descr //加载中断描述符表,这里的idt_desscr包含了idt变量(256个中断描述符)
    ret
  • 加载全局描述符表寄存器
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 :^)

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 */
  • 检查A20地址线是否真实开启
  • 初始化软盘缓冲区:tmp_floppy_area:.fill 1024,1,0
  • 初始化页表:

注:在386体系的CPU中支持段页式的内存管理方式,即逻辑地址(基地址+偏移)->通过分段管理->线性地址->通过分页管理->物理地址。针对分页管理386的机制是CR3寄存器指向页表目录,页表目录中的PDE (page Directory Entry)指向一个页表,页表中的PTE(page Table Entry)指向一个物理页。因此386的线性地址实际上是三个偏移量:页目录表偏移量(找到页表)、页表的偏移量(找到物理页)、物理页的偏移量,三者的综合完成具体物理页面的转换。

在linux的页表初始化代码中主要是三块工作:

    • 初始化一个页目录表和四个页表:

 

setup_paging:
    movl $1024*5,%ecx        /* 5 pages - pg_dir+4 page tables */
    xorl %eax,%eax
    xorl %edi,%edi            /* pg_dir is at 0x000 */
    cld;rep;stosl
    movl $pg0+7,pg_dir        /* set present bit/user r/w */ pg_dir的地址是0x000,没搞清楚为什么?
    movl $pg1+7,pg_dir+4        /*  --------- " " --------- */
    movl $pg2+7,pg_dir+8        /*  --------- " " --------- */
    movl $pg3+7,pg_dir+12        /*  --------- " " --------- */
    • 将edi指向最后一个页表的最后一项:movl $pg3+4092, %edi
    • 设置页目录表的地址至CR3寄存器,设置CR0寄存器启动分页机制;
    xorl %eax,%eax        /* pg_dir is at 0x0000 */
    movl %eax,%cr3        /* cr3 - page directory start */ //cr3被设置成0x0000
    movl %cr0,%eax
    orl $0x80000000,%eax
    movl %eax,%cr0        /* set paging (PG) bit */
    ret            /* this also flushes prefetch-queue */
posted @ 2013-05-04 09:27  Fredric_2013  阅读(419)  评论(0编辑  收藏  举报