笔记重点:
linux 0.12的启动代码能够给我们分析最新的linux代码给予一定的启示,启动代码虽然只有三个文件,但是对读者分析能力的要求比较高,主要是在对汇编语言以及x86编程体系的理解,以下是对linux 0.12启动代码的简要说明,对分析很重要
- bootsect.S文件主要的目的是加载setup.S和内核模块
- setup.S 主要目的是通过biso中断读取机器的系统数据
- head.s 主要目的是内核初始化之前的环境配置,也就是32位保护模式运行做准备
1. 三段代码都涉及代码的移动
主要目的是为了空间复用,代码是从0x7C00开始执行,第一段代码就将bootsect.S的代码移动到绝对地址0x9000处然后再执行
1 | entry start |
2. 机器的系统数据都是通过BIOS的功能获取到的,内核初始化的时候都要利用到这些数据
- 最初读取加载内核代码是使用的BIOS的INT 0x13
- setup.S中利用BIOS的INT 0x15功能读取内存的大小
- 其他硬件数据
3. setup.S的主要目的是设置中断向量表述表和全局描述符表,以开启内核的32位保护模式
描述符表的定义是在setup.S的567行开始
1 | gdt: |
设置GDT寄存器和IDT寄存器是在139行
1 | lidt idt_48 |
idt_48h和gdt_48就是上面定义的
是一个6字节长的数据,前2字节是表的长度,后4字节是表的基地址,设置cr0的第0位为1开启保护模式
4. 这里有非常详细的8259A的编程资料
没有学过微机接口的同学可能对8259A的结构不够了解也是没有关系,了解这些对中断系统的了解比较关键
5. head.s最关键的地方是在32位保护模式下开启内存的分页处理机制
cr3寄存器是记录页目录的基地址,cr0的PG位置1就是开启分页处理,然后重新设置IDT和GDT,第一次设置IDT和GDT是为了head.s运行32位保护模式,设置页目录而临时设置,这个时候还不是分页模式,不能分配内存给GDT和IDT,第一次设置时IDT是空表,GDT只有3个描述符,这次设置GDT的大小是256*8-1,IDT的大小也是256,这是我认为的最主要区别。
1 | idt_descr: |
结论:通过对linux 0.12启动代码的分析,理解linux启动的三大步骤
- 首先是通过BIOS提供的功能,加载linux初始化之前的环境初始化代码,setup.S和head.s;
- setup.S通过BIOS的中断服务获取系统硬件的一些参数并保存,给linux进行初始化提供参考;
- 通过head.s设置系统的32位保护模式,并开启内存的分页模式