x86虚拟地址映射

分析x86体系下虚拟地址映射前,我们先提出一个问题,打印一个局部变量的地址,这个地址是什么地址??
逻辑地址?线性地址?物理地址?

我们弄清上面的概念先看一下inter x86的发展历史
x86虚拟地址映射
CPU的位数
cpu的位数并不是代表着地址总线条数,而是代表着计算的能力,在ALU算术逻辑单元中,一次性计算最长整数的字节数,
也是代表着ALU的宽度。

1974年
实模式

先看8080  8085这两个处理器都是8位的这两个操作的是多少个地址总线呢?是8条吗?
如果是8条,那么这个cpu最多寻址2^8 = 256个地址,这样大的cpu 什么也干不了,所以 地址总线  != CPU的位数
8080  8085他们的地址总线是16根  2^16 = 64K,地址总线和CPU位数不对等,怎么解决呢?利用16位的汇编器。

1983年

8086处理器是正式进入我们的x86体系里的第一个处理器,这是的处理器位数变成16位,但是地址总线又变成了20根,
因为要创建一个新的体制,所以不在引用之前复杂的方法,改成20位汇编器。而是用新的方法,在CPU里添加了4个
寄存器,分别为CS(代码段寄存器)DS(数据段寄存器) SS(堆栈段寄存器)ES(扩展段寄存器)。ip寄存器(保存段偏移
量)由于处理器位数是16位,所以这里的四个寄存器都是16位(2个字节)。那么它是怎么(利用16位处理器和四个寄存器)
处理20根地址总线的呢?

这里抽象出一个例子: 
假设我们有一个100页的笔记本,需要记录语文,数学,英语三门学科的课堂笔记。我们很显然的就想到,把本子分成三份,
记录每份的起始页。我的每个科目做个目录,记录一下偏移量。由于某种原因起始页都只能记录一位数,那
么怎么处理呢?这里是不是可以这么处理呢。

那么我们规定在分成三份时候,我们要以最小的10的整数倍来分,相当于这个位数记录着十位,个位为0。起始页只能是10
的倍数。我们要找自己的页数时候,就是我们要找的页数 =  起始页+偏移页数。

这个例子只是为了让我们理解接下来8086处理器是怎么来操作。它是在真实的物理内存上,划分了很多段,每个起始地址是
16的倍数,2进制来说低四位一直是0,这么说来,只要记录高16位地址,后面四位就不用记录了。不同起始段分别用四个寄存器来保存,要访问的地址 = (寄存器 << 4) + (ip寄存器(偏移量))
x86虚拟地址映射

这个就是解决CPU位数和地址总线不同的问题。


所有的操作都是在真实的物理内存上,当时没有操作系统这么一说,就没有所谓的权限控制,只要你调用驱动接口,就可以随意改内存上的数据。这样就是所谓的实模式。安全性很差,使用起来很复杂,因为需要用户自己去管理物理内存。只能使用2^20 =1M的内存,太小了。


保护模式分段
到了我们处理器80386时候,这时候cpu是32位,地址总线变成了32根。但是它的寄存器大小为了兼容之前体系下的版本,寄存器依旧是16位,这么说寻址能力又不能满足了。这个时候增加了两个寄存器,GDTR(全局的段的描述附表),LDTR(局部的描述附表),新增的寄存器可以不和上个版本兼容不是16位,是32位。

x86虚拟地址映射

新增的寄存器GDTR保存GDT附表的地址,原来CS DS SS ES寄存器保存的是GDT数组下标了,这样就可以满足32位地址总线的
寻址了。 我们看一下段寄存器的定义

x86虚拟地址映射

这就是代表着四个寄存器每个位的含义,12个表项被系统预留了。用户只能用8080个表项。

分析完寄存器,我们在分析一下每个表项,每个表项是8个字节64位
x86虚拟地址映射

看完这个相信大家应该明白了点把,这是一个段描述符,它64位分别存储了什么东西,上面那张图都画出来了,段限长是20位也好理解,因为4KB*1M = 4G,刚好一个物理内存大小。然后基地址长度位数是32位和地址总线长度刚好吻合。

保护模式下的分段的映射
GDT [DS>>3].BaseAddr   +  IP(逻辑地址)   =    线性地址
GDT[DS >>3]这个是数组的下标高13位保存着所以向左移动3个位

x86虚拟地址映射
分页

CRO寄存器  PG位内存是否开启分页
CR2寄存器   保存发生缺页异常时的虚拟地址
CR3寄存器   保存当前进程的页目录的起始地址
CR4寄存器   PRE  是否开启物理地址扩展

我们现在要分析一下线性地址分页后怎么转化成物理地址
x86虚拟地址映射
我们知道线性地址是32位的,这里就解析了开启分页之后每个位代表什么意思,高十位代表着页目录下标,理解为一个保存1024个页表地址的数组,然后前十位表示出下标,寻找到所在页表,那么页表也是个一个保存1024个物理页面地址的数组,那么次高十位就能找得到我们需要的物理页面,最后12位代表偏移量。这样就能访问到我们所需要的真正的物理地址。

参考《LINUX内核完全剖析》--  第4章
这里我就是说明一下X86的虚拟地址映射的问题,有时间我继续写一篇内存管理的博客。