启动总结

1. 在bootloader加载grub到0×07c00地方,grub把实模式代码setup放到0×90000处,把vmlinux放在0×100000即1M的地方。

2. 在boot/head.s中,跳转到setup的入口处_start地方开始执行,然后短跳转到start_of_setup处执行,其功能为:

(1) 复位硬盘

(2) 在_end后建立512的堆栈

(3) 比对签名

(4) 清空bss

(5) Call main

3. 进入boot/main.c中,执行以下主要函数 copy_boot_params(),init_heap(),设置硬件,go_to_protected_mode();

4. 在boot/pm.c中,go_to_protected_mode()其功能为:

(1) Mask_all_interrupts()关中断

(2) Setup_idt 初始化中断表

(3) Setup_gdt初始化gdt全局描述符表,gdt在主存中的地址和大小存放在gdtr寄存器中。

(4) Protected_mode_jmp 跳转到保护模式

5. Boot/pmjump.s中,go_to_protected_mode主要功能:

(1) 开启CRO的PE位

(2) Jmpl codestart_32,进入了bzimage的vmlinux即1M的地方开始执行

6. 跳转到Compressed/head_32.S中解压内核然后跳转到

kernel/head_32.S中的startup_32处执行。

Startup_32

(1) 初始化段寄存器

(2) 建立进程0的内核堆栈

(3) Setup_idt

(4) 拷贝系统参数

(5) 识别处理器

(6) GDT、IDT

(7) Start_kernel

X86的寻址机制:

逻辑地址(段+偏移)->线性地址->物理地址

但是在linux中,已经不再使用分段机制,所以第一步由逻辑地址到线性地址转化为直接转化,即逻辑地址和线性地址是一致的,即逻辑地址的偏移量字段的值与相应的线性地址的值总是一致的。

逻辑地址:

这个是针对X86烦人的分段机制使用的,因为在linux中不再使用分段,但是为了与X86硬件的一致,还必须不能绕开这个机制。

逻辑地址:16(index+TI) + 32(offset)

clip_image002

因为我们要求逻辑地址与线性地址一致,为了达到这个要求,在gdt中各段的起始地址都是0即可以满足,通过这种方法我们就可以避免使用X86的分段机制。

clip_image004

线性地址

分页单元把线性地址转化为物理地址,其中关键的任务就是把所请求的访问类型与线性地址的访问权限相比较,如果这次内存访问是无效的,就产生一个缺页异常。

开启分页通过CR0寄存器的PG标志启用。

注意:CR3存放当前进程页全局目录的地址

32位的线性地址被分成三个域。

DIRECTORY TABLE OFFSET

clip_image006

每个进程必须有一个分配给它的页目录,所以在进行进程切换的时候,必须切换页目录,将页目录加载到CR3,CR3保存在进程的描述符中。

我们知道cache缓存了内存中的数据以行为单位,但是并没有反映到线性地址与物理地址上,所以X86还提供了TLB(转换后援缓冲器),这是用来加快线性地址的转换,当该线性地址第一次被使用时,通过转换计算出对应的物理地址,同时,物理地址将存放在TLB entry中,以便以后同一个线性地址的应用可以快速得到转换后的结果。(龙芯中支持)当cpu的CR3(保存了每个进程的gdt地址)改变时(发生进程切换),将主动使本地TLB中的所有项都无效。

注意:对于cache的控制是通过CR0寄存器CD标志位用来启用或禁用高速缓存电路,这个寄存器的NW标志指明高速缓存是使用通写还是回写策略。Linux对于所有的页框都启用高速缓存,对于写操作总是采用回写策略。

物理内存布局

用户态线性地址与实际内存物理地址转换就是通过缺页异常,然后由内存管理分配物理页,将对应关系填充到进程自己的页表中,并没有简单的对应关系。

内核线性地址与实际内存物理地址的转换比较简单,就是线性地址 – 3G=物理地址

内核页表的建立
clip_image008

1. 临时内核页表

Swapper_pg_dir: 临时页全局目录是在内核编译过程中静态地初始化的

Pgd:临时页表是在startup_32中初始化的。

这些都在_end之后

这一阶段目标就是在实模式和保护模式下都能对8M寻址。

为什么要分成896M两部分?

答:我们知道内核由线性地址访问物理内存最直接的就是减去3G,但是这样顶多能访问1G的物理内存,1G以上的物理内存就没有了线性地址了,那么该怎么办,下面两部分就是介绍如何完成这个任务。

2. RAM小于896M时的最终内核页表

这前896M的最终映射非常简单,规则如下

物理地址(0~896M)=线性地址(3G~3G+896M)—- 3G

此时,前面第一步的临时内核页表可以取消掉了。

3. RAM大小在896M和4096M之间时的最终内核页表。

896M边界以上的页框并不映射在内核线性地址空间的第4个GB,因此内核不能直接访问他们,所以这不适合高端内存。

这是通过返回被分配页框的页描述符的线性地址,内核线性地址空间的最后128M中的一部分专门用来映射高端内存页框。128M的线性地址实现非连续内存分配和固定映射的线性地址。

4. RAM大于4096M时的最终内核页表

PAE机制