一、内存管理 |
内存管理单元MMU
MMU是中央处理器中用来管理虚拟存储器、物理存储器的控制线路,同时负责虚拟地址映射为物理地址;
MMU本质上是一个表格,MMU表格一边是CPU发送指令对应的虚拟地址,一边存储的是物理地址;
虚拟地址转化为物理地址,内存通过物理地址去读取实际的数据。
内存管理单元的基本思路
数据和堆栈的大小总和可以超过物理存储器的大小;
操作系统把当前使用的部分留在内存中,其它的保留在硬盘上。
CPU写过程
CPU控制单元通过一种称为分段单元(segmentation unit)的硬件电路把一个逻辑地址转换成线性地址;
接着,第二个称为分页单元(paging unit)的硬件电路把一个线性地址转换成物理地址。
CPU读取过程
物理地址–>通过分页单元–>线性地址–>通过分段单元–>逻辑地址
二、分段机制 |
最早内存没有抽象,程序直接读写物理内存。在这种情况下,通常同时运行两个程序是不可能的,因为它们很可能同时访问同一个物理地址导致程序崩溃。当Intel 8086处理器出现时,内存寻址迎来第一次飞跃,它引入了一个重要的概念——段,段式内存使得程序地址不再需要静态重定位,支持了更大的地址。8086处理器的数据总线是16位的,但其目标是寻址1MB的内存,这意味着需要20位的地址总线。为了解决这个问题,当时引入了分段的方法。
一个逻辑地址由两部分组成:一个段标识符和一个指定段内相对地址的偏移量。段标识符是一个16 位长的字段,称为段选择符(Segment Selector),而偏移量是一个32 位长的字段。
段寄存器
为了方便找到段选择符,处理器提供6个段寄存器专门用来存放段选择符。它们是cs、ss、ds、es、fs和gs。
- cs位代码段寄存器
- ss为栈段寄存器
- ds为数据段寄存器
其他三个段寄存器作一般用途,6个段寄存器均为16位。
段描述符
每个段由一个8字节的段描述符(segment descriptor)来具体描述。
段描述符放在全局描述符表(Global Descriptor Table ,GDT)或局部描述符表(Local Descriptor Table, LDT)中。
段描述符标被存在一个非编程CPU寄存器中,非编程寄存器对程序员不可见,仅供6个可编程的段寄存器使用。
B31 ~ B24 和 B23 ~ B16分别为基地址的 bit16 ~ bit23 和 bit24 ~ bit31;
L19 ~ L16和L15 ~ L0为段LIMIT的 bit10 ~ bit15 和 bit16 ~ bit19。
4位type域描述了段的类型特征和存取权限,广泛使用如下几种:
- 代码段描述符(描述符代表一个代码段,可以放在GDT或LDT中,S标志位为1)
- 数据段描述符(描述符代表一个数据段,可以放在GDT或LDT中,S标志位为1)
- 任务状态段描述符(代表一个任务状态段(TSS),只能存放在GDT中,S标志位为9或11)
- 局部描述符表描述符(代表一个LDT段,只能存放在GDT中,S标志位为0)
段选择符
之前提到16位的段选择符存放在段寄存器中,它直接指向段描述符。每当一个段选择符被装入段寄存器,相应的段描述符就被装入非编程寄存器。此时CPU只需直接引用段描述符所在寄存器即可,不需访问主存中的GDT或LDT。仅当段寄存器的内容改变时,才有必要访问GDT或LDT。
段选择符包含以下域:
- 13位的索引,指定了段描述符在GDT或LDT中的入口。
- TI标志指明了段描述符是在GDT中(TI = 0)还是在LDT中( TI = 1)。
- 两位RPL(请求特权级)。
逻辑地址到线性地址的转换
分段单元(segmentationunit)执行以下操作:
- 先检查段选择符的TI字段,以决定段描述符保存在哪一个描述符表中。TI字段指明描述符是在GDT中(在这种情况下,分段单元从GDTR寄存器中得到GDT的线性基地址)还是在LDT中(在这种情况下,分段单元从LDTR寄存器中得到LDT的线性基地址)。
- 从段选择符的 index 索引字段计算段描述符的地址,index字段的值乘以8(一个段描述符的大小),这个结果与GDTR或LDTR寄存器中的内容相加。
- 把逻辑地址的偏移量与段描述符基地址域(base)相加,就得到了线性地址。
三、分页机制 |
分页单元在分段之后运行,把线性地址转换成物理地址。
页、页框、页表
- 为了效率起见,线性地址被分成以固定长度为单位的组,称为页(page)。页内部连续的线性地址被映射到连续的物理地址中。这样,内核可以指定一个页的物理地址和其存取权限,而不用指定页所包含的全部线性地址的存取权限。
- 分页单元把所有的RAM 分成固定长度的页框(page frame)。每一个页框包含一个页,也就是说一个页框的长度与一个页的长度一致。页框是主存的一部分,因此也是一个存储区域。
区分一页和一个页框是很重要的,前者只是一个数据块,可以存放在任何页框或磁盘中。 - 把线性地址映射到物理地址的数据结构称为页表(page table)。页表存放在主存中,并在启用分页单元之前必须由内核对页表进行适当的初始化。
常规分页
从80386 起,Intel 处理器的分页单元处理4KB 的页。32 位的线性地址被分成 3 个域:
- Directory(目录):最高10 位
- Table(页表):中间10 位
- Offset(偏移量):最低12 位
Directory域和Table域都是10位,它们拥有相同的结构,均包含以下的域:
- Present 标志
- Accessed 标志
- Dirty 标志
- Read/Write 标志
- User/Supervisor 标志
- PCD 和 PWT 标志
- Page Size 标志
- Global 标志
线性地址转换为物理地址
线性地址的转换分两步完成,每一步都基于一种转换表,第一种转换表称为页目录表,第二种转换表称为页表。
正在使用的页目录的物理地址存放在控制寄存器 cr3 中。线性地址内的Directory 字段决定页目录中的目录项,而目录项指向适当的页表。地址的Table 字段依次又决定页表中的表项,而表项含有页所在页框的物理地址。Offset 字段决定页框内的相对位置。
- 用最高10位作为页目录项的索引,将它乘以4,与CR3中的页目录的起始地址相加,获得相应目录项在内存的地址。
- 从这个地址开始读取32位页目录项,取出其高20位,再给低12位补0,形成页表在内存的起始地址。
- 用中间的10位作为页表中页表项的索引,将它乘以4,与页表的起始地址相加,获得相应页表项在内存的地址。
- 从这个地址开始读取32位页表项,取出其高20位,再将线性地址的第11~0位放在低12位,形成最终32位页面物理地址。