80386是x86系列的32位处理器,其复杂性要比8086大得多。但如果要去看懂支持X86平台的操作系统内核(如linux、skelix等),对i386特别是其保护模式的认识是无法绕过的。本文尝试记录当前个人对i386 CPU体系的认识,自我感觉对这块还不清晰,后续补充完善此文。
PS:记得当时啃linux 0.11版本操作系统源码,最难过的入门坎有三个:AT&T的内联汇编,i386的保护模式和软盘硬盘的底层机制;
个人理解如果把386看成是8086的升级,那么其基于以下四点提升,而在体系结构上做出了改变:
- 为提升至32位的地址总线、数据总线,引入段描述符概念;但之前的CS、DS等段寄存器还是要继承,因此段寄存器里保存的是段选择子,通过选择子中的索引获取段描述符;
- 为在硬件上支持多任务,引入了全局描述符表(GDT)、局部描述符表(LDT)和中断描述符表(IDT);其中LDT存在多个,是每个任务都自有的;同时引入任务状态段(TSS)来保存任务上下文;
- 为满足多任务之间的隔离,因此在内存管理中引入分段机制,同时给段赋予了特权级实现同一个进程内部的内核态、用户态共存;
- 为能够支持虚拟内存机制,在内存管理中又引入分页机制,通过页故障使得程序不在需要在一开始就把所有的逻辑地址空间导入主存;
80386芯片分为三个部件:
- 中央处理器部分(CPU):由指令部件和执行部件组成
- 存储管理器部分(MMU):由分段部件和分页部件组成
- 总线接口部分(BIU):
80386的描述符分类(相当于为了支持多任务,原有8086的段寄存器基址被细化):
- 第一类:代码段描述符、数据段描述
- 第二类:
- 特种段描述符:(存放在GDT中)
- 局部描述符表:
- 任务状态段表:
- 控制(门)描述符:
- 调用门:程序调用
- 任务门:任务切换
- 中断门:外部中断
- 陷阱们:异常处理
- 特种段描述符:(存放在GDT中)
80386芯片的寄存器7类32个寄存器,包括:
- 通用寄存器:EAX、EBX、ECX、EDX
- 段寄存器:CS(代码段)、SS(堆栈段)、D\E\F\GS(数据段)
- 指令指针和标志寄存器:IP、EFLAG
- 控制寄存器:CR0(机器控制)、CR1(保留)、CR2(页故障线性地址)、CR3(页目录表基地址)
- 系统地址寄存器:GDTR、IDTR、LDTR、TR
- 排错寄存器:DR0/1/2/3(断点的线性地址)、DR4/5(保留)、DR6(断点状态)、DR7(断点控制)
- 测试寄存器:TR0/1/2(保留),TR3/4/5(CACHE测试),TR6(命令测试寄存器),TR7(测试数据寄存器)
/**********************************************************
80386的内存管理
分页机制的使用:
- 主存被划分为相同大小的存储块-页帧(例1K Byte),系统以页帧为单位分配主存给进程;
- 进程将自身的逻辑地址也按照页帧为大小划分并编号,同一时刻只有一部分页被导入主存;其状态由每个进程自己保存的页表(PMT)保存;后续若调用到时,通过页故障将需要的页帧换入;
- 通过不同的逻辑页指向相同的物理页帧实现进程间的共享;
分段机制的使用:
- 将一维的线性地址空间(分页机制中)划分段,成为段号+段内偏移的二维地址空间;
- 系统为每个进程建立一个段映像表(SMT),实现跳转;