(持续更新)
相关概念
查看的书籍为 深入linux内核
内存地址
当使用80x86(32位)微处理器时,一般分为三种不同的地址:
逻辑地址
包含在机器语言指令中用来指定一个操作数或一条指令的地址。每一个逻辑地址都由一个段(segment)和偏移量(offset或displacement)组成,偏移量指明了从段开始的地方到实际地址之间的距离。
所有段都从0x00000000开始,只需关注段内偏移即可。而段内偏移的值恰好等于线性地址的值。
线性地址(也称虚拟地址)
线性地址通常用十六进制数字表示,值的范围从0x00000000到0xffffffff。
物理地址
用于内存芯片级内存单元寻址。他们与从微处理器的地址引脚发送到内存总线上的电信号相对应。
物理地址
用于内存芯片级内存单元寻址。他们与从微处理器的地址引脚发送到内存总线上的电信号相对应。
页(page)
线性地址被分成以固定长度为单位的组,称为页。页内部连续的线性地址被映射到l连续的物理地址中。内核可以指定一个页的物理地址和其存储权限。
页框(page frame)
分页单元把所有的RAM分成固定长度的页框(有时叫做物理页)。
每一个页框包含一个页,也就是说一个页框的长度与一个页的长度一致(目前操作系统应该不是)。
页表 (page table)
把线性地址映射到物理地址的数据结构称为页表。
页表内存储页表项,页表项含有页所在页框的物理地址。
在启用分页单元之前必须由内核对页表进行适当的初始化。
地址转换
内存控制单元(MMU)通过一种称为分段单元的硬件电路把一个逻辑地址准换成线性地址;接着,第二个称为分页单元的硬件电路把线性地址转换成一个物理地址。
这个地方有疑问! 逻辑地址一般等于线性地址,那不同的进程中相同的地址获取到的逻辑地址是一样?还要继续看。
段选择符
机器语言指令中出现的内存地址,都是逻辑地址。
一个逻辑地址由两部分组成: 段选择符以及偏移量。
段选择符字段
index :指定了放在GDT或LDT中的相对应段描述符的入口。
TI:TI (Table Indicator)标志 :指明段描述符实在GDT(TI=0)中或在LDT中 (TI=1)
RPL:请求者特权级。
段描述符
每个段由一个8字节的段描述符表示,它描述了段的特征。段描述符放在全局描述符表(Global Descriptor Table,GDT)或局部描述符表(Local Descriptor Table, LDT中)。
Linux GDT(全局描述符表)
在单处理器系统中只有一个GDT,而在多处理器系统中每个CPU对应一个GDT。
通常只定义一个GDT,每个进程除了存放在GDT中的段之外如果还需创建附加的段,就有自己的LDT。GDT在主存中的地址和大小存放在gdtr控制寄存器中,当前正被使用的LDT地址和大小放在ldtr控制寄存器中。
段描述符类型
代码段描述符
数据段描述符
任务状态段描述符(TSSD)
局部描述符表描述符(LDTD)
段描述符字段
Base: 包含段的首字节的线性地址
.............
.............
分段单元
逻辑地址转换为线性地址,分段单元执行以下操作
1.通过逻辑地址(由段选择符及偏移量组成)得到段选择符;
2.先检查段选择符的TI字段,判断段选择符保存在哪一个描述符表中。TI字段指明描述符是在GDT中(在这种情况下,分段单元从gdtr寄存器中得到GDT的线性基地址)还是在LDT中(在这种情况下,分段单元从ldtr寄存器中得到LDT的线性基地址);
3.从段选择符的index 字段计算段描述符的地址,index字段的值乘以8(一个段描述符的大小),这个结果与gdtr或ldtr寄存器中的内容相加;
4.把逻辑地址的偏移量与段描述符Base字段的值相加就得到了线性地址。
简单说就是,通过逻辑地址找到段选择符,再找到对应的段描述符,最后得到最后的线性地址。
段描述符中有包含段的首地址的线性地址(base)。
常规分页
线性地址结构
32位的线性地址被分成3个域页表 (我的理解:这里怎么分具体要看有几级页表以及页的大小)
Diretory(目录)
最高10位
Table(页表)
中间10位
Offset(偏移量)
最低12位
这里分为两级页表,线性地址的转换就分两步完成,每一步都基于一种转换表,第一个种叫页目录表 ,第二种叫页表。
个人理解:
如果进程使用全部4G线性地址空间,每个页框(物理页)代表4096个字节(2的12次方);一个页表最多存储1024个页表项(2的10次方),1个页表项含有页所在页框的物理地址,即1个页表项对应4k地址空间,一个页表能找到4M地址空间;1个页目录最多存储1024个页目录项(2的10次方),而一个页目录项指向适当的页表,那么一个页目录项就能找到一个4M地址空间,一个页目录就能找到4G地址空间。
由上图可知,一个页大小为2的10次方,那么内存就以2的十次方分页,知道页表项大小为2字节,
1.一个页表中的页表项数量为 1024(2的10次方) / 2 = 512(2的9次方)个,页号由9位表示,
2.一个页表能表示的空间大小为 512(2的9次方) * 1024(2的10次方) = 512K (2的19次方),
3.一个页目录包含表项的个数 为 总空间大小除以一个页表能表示的空间大小,即
(2的16次方) * (2的10次方) / 512K (2的19次方) = 128 (2的7次方)。
书看到这里有了疑惑点:
书上说,使用这种二级模式的目的是在于减少每个进程页表所需RAM的数量,二级模式通过只为进程实际使用的那些虚拟内存区请求页表来减少容量。
那么问题来了,我只用一级页表为什么不能对实际使用的那些虚拟内存区请求页表?