续上篇博客Linux内核完全注释:第三章 内核引导启动程序-setup.s讲解
功能描述
- head.s编译后,被连接成system模块的最前面开始部分。
- 这部分采用AT&T格式编写,赋值方向与之前相反
- 首先加载各个段寄存器,重新设置中断描述符表,共256项,并使各个表项均指向一个只报错误的哑中断程序。
- 重新设置全局描述符表,对比物理地址0与1M开始处的内容是否相同,如果相同那么没有开启A20地址线,进入死循环。
- 测试PC机是否含有数据协处理器芯片,并在控制寄存器CR0中设置相应的标志位
- 设置管理内存的分页处理机制,将页目录表放在绝对物理地址0开始处。
- 紧随其后放置共可寻址16MB内存的4个页表,并分别设置它们的表项。
- 最后利用返回指令将预先放置在堆栈中的/init/main.c程序的入口地址弹出,运行main()程序。
源码解析
-
程序开始的数据、符号声明部分:
/* * linux/boot/head.s * * (C) 1991 Linus Torvalds */ /* * 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. */ .text .globl idt,gdt,pg_dir,tmp_floppy_area pg_dir: .globl startup_32
这里需要注意的是:pg_dir,这是页表目录地址,后面会用到。
-
程序开始部分,设置寄存器值。
startup_32: movl $0x10,%eax # 这里是段选择符,而不是地址,0001 0000,表示特权级0,全局描述符表,第2个表项 mov %ax,%ds # 关于表项内容可以回去看setup.s程序中的定义,第2个表项刚好是数据段描述符表项 mov %ax,%es mov %ax,%fs mov %ax,%gs lss stack_start,%esp # stack_start应是编译程序生成的存放堆栈信息的地方 call setup_idt # 设置中断描述符表 call setup_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
这部分程序有疑问的可能就是0x10那里了,在代码后面我进行了详细的注解。
讲解两个子程序:setup_idt, setup_gdt,笔者在读的时候遇到的难点都写在注释里了,直接看代码及注释即可。
/* * setup_idt * * sets up a idt w