0%

《linux 0.12内核完全剖析》--启动代码分析

笔记重点:
linux 0.12的启动代码能够给我们分析最新的linux代码给予一定的启示,启动代码虽然只有三个文件,但是对读者分析能力的要求比较高,主要是在对汇编语言以及x86编程体系的理解,以下是对linux 0.12启动代码的简要说明,对分析很重要

  • bootsect.S文件主要的目的是加载setup.S和内核模块
  • setup.S 主要目的是通过biso中断读取机器的系统数据
  • head.s 主要目的是内核初始化之前的环境配置,也就是32位保护模式运行做准备
1. 三段代码都涉及代码的移动

主要目的是为了空间复用,代码是从0x7C00开始执行,第一段代码就将bootsect.S的代码移动到绝对地址0x9000处然后再执行

1
2
3
4
5
6
7
8
9
10
11
12
entry start
start:
mov ax,#BOOTSEG "BOOTSEG为0x7C0
mov ds,ax
mov ax,#INITSEG "0x9000
mov es,ax
mov cx,#256 "512字节
sub si,si "si = 0x0000
sub di,di "di = 0x0000
rep "cx递减1 直到cx为0
movw "移动一个字
jmpi go,INITSEG "跳转到0x9000执行
2. 机器的系统数据都是通过BIOS的功能获取到的,内核初始化的时候都要利用到这些数据
  • 最初读取加载内核代码是使用的BIOS的INT 0x13
  • setup.S中利用BIOS的INT 0x15功能读取内存的大小
  • 其他硬件数据
3. setup.S的主要目的是设置中断向量表述表和全局描述符表,以开启内核的32位保护模式

描述符表的定义是在setup.S的567行开始

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
gdt:
.word 0,0,0,0 ! dummy

.word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
.word 0x0000 ! base address=0
.word 0x9A00 ! code read/exec
.word 0x00C0 ! granularity=4096, 386

.word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
.word 0x0000 ! base address=0
.word 0x9200 ! data read/write
.word 0x00C0 ! granularity=4096, 386

idt_48:
.word 0 ! idt limit=0
.word 0,0 ! idt base=0L

gdt_48:
.word 0x800 ! gdt limit=2048, 256 GDT entries
.word 512+gdt,0x9 ! gdt base = 0X9xxxx

设置GDT寄存器和IDT寄存器是在139行

1
2
lidt idt_48
lgdt gdt_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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
idt_descr:
.word 256*8-1 "idt 包含256项
.long _idt
.align 2
.word 0
gdt_descr:
.word 256*8-1 "gdt 包含256项
.long _gdt "地址为下面的_gdt标记

.align 3
_idt:
.fill 256,8,0 "idt存放的地方

_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 */

结论:通过对linux 0.12启动代码的分析,理解linux启动的三大步骤

  • 首先是通过BIOS提供的功能,加载linux初始化之前的环境初始化代码,setup.S和head.s;
  • setup.S通过BIOS的中断服务获取系统硬件的一些参数并保存,给linux进行初始化提供参考;
  • 通过head.s设置系统的32位保护模式,并开启内存的分页模式