I386是Intel的x86系列CUP中一个重要的里程碑。Linux最初就是I386 CPU上实现的。本文介绍Linux内核对I386架构系统进行内存管理,以及从逻辑地址到物理地址的转换方式。对于绝大多数现代的操作系统,例如:Windows NT(包括Windows 2000、Windows XP)在内存管理的实现方式基本上大同小异,通过对Linux分析,也可以加强对非源码开放式操作系统的理解。在I386架构上的现代操作系统,无一例外都需要在保护模式下工作。所以,先来介绍I386在保护模式有别于实模式的特性。
一、 I386 CPU保护模式下的新特性
1. 特权级别
CPU分为4个特权级别,0-3, 0最高,3最低。每条指令有其适用的级别。Linux和各种I386 Unix都 只用到0和3级别,对应Linux/Unix中的系统态和用户态。
2. 增加段寄存器
增加FS,GS段地址寄存器。加上原来的4个段寄存器,I386一共提供6个段寄存器。在保护模式下,以前实模式下的段寄存器还是有用的。不过它不再用来存放段的基址,而是用来存放“段选择子”(段描述项),其实段寄存器的名字也变成了“段选择子寄存器”或“段描述项寄存器”。在访问内存的时候,我们需要给出的是“段选择子”(段描述项),而不是段基址了。在段描述项中包含段基址、权限等信息。
3. 增加段表寄存器
Ø 增加GDTR,LDTR,他们只用特权指令才能访问。配合段寄存器使用。
GDTR——全局段描述表寄存器 global descriptor table regisiter
LDTR——局部段描述表寄存器 local descriptor table regisiter
Ø GDTR或LDTR加载GDT或LDT中的基地址。
GDT——全局地址段描述数据项表。
LDT——局部地址段描述数据项表。
Ø 在Linux中只使用GDT。LDT在做虚拟机时候下才使用。
4. 中断向量
“中断向量”中不仅是程序的入口地址,而类似psw + “入口地址”的方式,但更复杂。把各种中断向量归为4种类型的门。例如:cup在穿越中断门的时候自动关闭中断。 ......,很多说道,归根结底就是为了提供对“进程切换”和“中断响应”的更细致的控制。
5. 中断向量的保存与恢复
每种类型门的中断向量都包含段选择码TSS,它是用于保存任务现场的数据结构。
TSS——任务状态段 Task_state segment。
当前任务(进程)被调度后,当前CPU各个寄存器的数据被保存到上一个任务(进程)的TSS中;当前任务的TSS的内容被装入各种寄存器,完成任务切换。
6. 增加的其他寄存器
Ø 增加IDTR,TR寄存器,只有特权指令才能访问它们。
IDTR——中断向量表指针寄存器
TR——任务寄存器,用于指向当前任务(进程)的TSS。
Ø 增加CR3寄存器,指向页表目录的基地址。页表目录,在有的操作系统教材上也叫做,外层页表。
7. 中断向量表的位置
IDT不再只保存在0开始的位置,可以在内存的任何位置,IDTR指向之。
IDT——中断向量表
IDTR——中断向量表指针寄存器
二、 Linux对I386的内存管理
1. 内存的初始化
1) 由于Linux需要在多种CPU上运行,而且大部分RISC CPU对段式内存管理的支持都很弱,所以在2.2内核以后,Linux基本上采取了绕过段式内存管理的策略。主要通过2个手段:
a) 通过所有进程指向共用两个GDT表项(其实一共四个表项,内核用2个,其他所有进程共用2个),一个代表数据段,一个代表代码段。
b) 并把这两个段基地址都设置为0,长度设置为最大,这就是所谓的平面内存。
2) 启用页式内存管理。初始化页表。
页表项:
0 |
1 |