内核第一阶段初始化

初始化阶段1包括从内核入口1MB处的startup_32到公共的start_kernel函数

=============================== arch/i386/kernel/head.S =================================
 50 /*
 51  * 32-bit kernel entrypoint; only used by the boot CPU.  On entry,
 52  * %esi points to the real-mode code as a 32-bit pointer.
 53  * CS and DS must be 4 GB flat segments, but we don't depend on
 54  * any particular GDT layout, because we load our own as soon as we
 55  * can.
 56  */
 57 ENTRY(startup_32)
 58 
 59 /*
 60  * Set segments to known values.
 61  */
 62     cld
 63     lgdt boot_gdt_descr - __PAGE_OFFSET
 64     movl $(__BOOT_DS),%eax
 65     movl %eax,%ds
 66     movl %eax,%es
 67     movl %eax,%fs
 68     movl %eax,%gs

在内核的链接脚本中指定了startup_32是程序入口而且代码段从__PAGE_OFFSET + 0x100000处开始,所以代码中的符号地址都是高地址(3GB+1MB以上),而内核代码运行时被加载到低地址1MB,此时是实模式,代码中访问的地址要用物理地址。所以lgdt要在符号地址boot_gdt_descr上减去__PAGE_OFFSET

=============================== arch/i386/kernel/head.S =================================
450 boot_gdt_descr:
451     .word __BOOT_DS+7
452     .long boot_gdt_table - __PAGE_OFFSET

boot_gdt_descr处是要存放到gdtr的值,第一个.word表示gdt的长度-1,接下来的.long表示gdt的起始地址。

================================ include/asm/segment.h ==================================
 83 /* Simple and small GDT entries for booting only */
 84 
 85 #define GDT_ENTRY_BOOT_CS       2                                                                                                                                       
 86 #define __BOOT_CS   (GDT_ENTRY_BOOT_CS * 8)
 87 
 88 #define GDT_ENTRY_BOOT_DS       (GDT_ENTRY_BOOT_CS + 1)
 89 #define __BOOT_DS   (GDT_ENTRY_BOOT_DS * 8)

CS段描述符在第2条,DS在第3条,__BOOT_DS的值为24,所以bootgdt的大小就是24+7。

=============================== arch/i386/kernel/head.S =================================
471     .align L1_CACHE_BYTES
472 ENTRY(boot_gdt_table)
473     .fill GDT_ENTRY_BOOT_CS,8,0
474     .quad 0x00cf9a000000ffff    /* kernel 4GB code at 0x00000000 */
475     .quad 0x00cf92000000ffff    /* kernel 4GB data at 0x00000000 */

段描述符表的内容。.fill标记的意思是产生GDT_ENTRY_BOOT_CS条(2条)长度为8内容为0的条目。boot gdt总共4条,CSDS都是4G范围的平坦映射。

接着回到startup_32,把__BOOT_DS段选择子赋给dsesfsgs(没有ss),它们会刷新自己的影子寄存器。

=============================== arch/i386/kernel/head.S =================================
 70 /*
 71  * Clear BSS first so that there are no surprises...
 72  * No need to cld as DF is already clear from cld above...
 73  */
 74     xorl %eax,%eax
 75     movl $__bss_start - __PAGE_OFFSET,%edi
 76     movl $__bss_stop - __PAGE_OFFSET,%ecx
 77     subl %edi,%ecx
 78     shrl $2,%ecx
 79     rep ; stosl

清除内存上.bss段所指的范围。bss段是未初始化的全局变量和初始值为0的全局变量,它们在elf文件中只需要存放相应的符号名称,不存放那些0(初始值不为0的变量当然需要在二进制文件中存放它的初始值)。在加载的时候要分配空间给这些变量,并初始化为0

=============================== arch/i386/kernel/head.S =================================
 81 /*
 82  * Initialize page tables.  This creates a PDE and a set of page
 83  * tables, which are located immediately beyond _end.  The variable
 84  * init_pg_tables_end is set up to point to the first "safe" location.
 85  * Mappings are created both at virtual address 0 (identity mapping)
 86  * and PAGE_OFFSET for up to _end+sizeof(page tables)+INIT_MAP_BEYOND_END.
 87  *
 88  * Warning: don't use %esi or the stack in this code.  However, %esp
 89  * can be used as a GPR if you really need it...
 90  */
 91 page_pde_offset = (__PAGE_OFFSET >> 20);
 92 
 93     movl $(pg0 - __PAGE_OFFSET), %edi
 94     movl $(swapper_pg_dir - __PAGE_OFFSET), %edx
 95     movl $0x007, %eax           /* 0x007 = PRESENT+RW+USER */
 96 10:
 97     leal 0x007(%edi),%ecx           /* Create PDE entry */
 98     movl %ecx,(%edx)            /* Store identity PDE entry */
 99     movl %ecx,page_pde_offset(%edx)     /* Store kernel PDE entry */
100     addl $4,%edx
101     movl $1024, %ecx
102 11:
103     stosl
104     addl $0x1000,%eax
105     loop 11b
106     /* End condition: we must map up to and including INIT_MAP_BEYOND_END */
107     /* bytes beyond the end of our own page tables; the +0x007 is the attribute bits */
108     leal (INIT_MAP_BEYOND_END+0x007)(%edi),%ebp
109     cmpl %ebp,%eax
110     jb 10b
111     movl %edi,(init_pg_tables_end - __PAGE_OFFSET)

va右移20位就是该地址在页目录表中表项偏移,page_pde_offset就是内核代码高地址空间的起始页目录项偏移。
pg0是在下面的链接脚本中定义,是bss段之后的第一个页地址,链接

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值