内存地址作为内存单元内容的住宿地,程序开发者常常会引用内存地址,引用内存地址是作为内存访问的一种方式。
内存地址分类
1.逻辑地址(logical address)
包含在机器语言指令中用来指定一个操作数或一条指令的地址。
每一个逻辑地址有一个段(segment)和偏移量(offset)。
段属于页内的内存单位,偏移量主要指一段固定长度内存地址分区的大小(size)。
段也分为段基地址和段内地址;寻址的方式就是段基地址加上合适的偏移量。
2.线性地址(linear address)(也称虚拟地址 virtual address)
是一个32位无符号整数,可以用来表示高达4GB的地址。
3.物理地址
用于内存芯片级内存单元寻址。由32位或36位无符号整数表示。
三者的转换关系(硬件电路转化)
逻辑地址-分段单元 →线性地址
线性地址 -分页单元 →物理地址
内存仲裁器
这一成员主要就是为了CPU访问存在。位置处在总线和每个RAM之间。
空闲RAM允许访问;忙碌RAM,延迟访问。
硬件中的分段
逻辑地址两部分构成:
段标识符和一定指定段内相对地址的偏移量。
段标识符(段选择符):16位长的字段
偏移量:32位长的字段
6个段寄存器
cs ss ds es fs gs
主要聚焦于cs ss ds
cs:代码段 指向包含程序指令的段 (我还可以指向CPU特权级 内核态和用户态)
ss:栈段 指向包含当前程序栈的段
ds:数据段 指向包含静态数据或者全局数据
段描述符
8字节长,描述段的特征,存放在全局描述符表(GDT)或局部描述符表(LDT)
gdtr控制寄存器存放GDT,ldtr控制寄存器存放LDT。
逻辑地址-分段单元 →线性地址
先检查段选择符的TI字段(选择GDT或LDT);
从段选择符的index字段计算段描述符地址,计算方式:index值乘以8
逻辑地址的偏移量加段描述符Base字段的值->线性地址
小插曲
分段可以给每一个进程分配不同的线性地址。
分页可以把同一线性地址空间映射到不同的物理空间。
逻辑地址的偏移量字段的值与相应的线性地址的值总一致。
GDT(全局描述符表)
18个段描述符和14个空的。
18个段描述符
1.用户态和内核态下的代码段和数据段(共四个)
2.任务状态段(TSS)(每个处理器1个) 线性地址空间都是内核数据段相应地址空间的一个小子集
3.一个包含缺省局部描述符表的段 所有进程共享段。
4.三个局部线程存储(TLS)段 多线程应用程序只能使用最多3个局部于线程的数据段
5.与高级电源管理(AMP)相关的3个段
6.与支持即插即用(PnP)功能的BIOS服务程序相关的5个段
7.内核用来处理"双重错误"异常的特殊TSS段(一个异常引发另一个异常)
LDT(局部描述符表)
大多数用户态不使用LDT,建立一个缺省的局部描述符表供大多数进程共享。
每个进程都可以创建自己的局部描述符表。
硬件中的分页
线性地址 -分页单元 →物理地址
线性地址被分成以固定长度为单位的组,称为页。
页内部连续的线性地址被映射到连续的物理地址。
分页单元将所有RAM分成固定长度的页框。
一个页框(物理页)包含一个页。
线性地址映射到物理地址的数据结构称为页表。
常规分页
32位线性地址分成3个域:
Directory(目录)
最高10位
Table(页表)
中间10位
Offset(偏移量)
最低12位
线性地址的转换基于页目录表(page directory)和页表(page table)。
页目录包含目录项,目录项指向适当的页表。----Directory字段
页表包含表项,表项包含所在页框的物理地址。----Table字段
页框内的相对位置。----Offset字段
页目录项和页表项的字段
1.Present标志 ----决定页或页表是否在主存中
2.Field ---- 包含页框物理地址最高20位
低12位为0;可以指页目录 也可以指页表
3.Accessed ----分页单元对相应页框进行寻址
4.Dirty ----只应用于页表项 对一个页框进行写操作
5.Read/Write ----含有页或页表的存取权限
6.User/Supervisor ---- 含有访问页或页表所需的特权级
7.PCD或PWT标志 ----控制硬件高速缓存处理页或页表的方式
8.Page Size标志 ----只应用于页目录项 页目录项指向2MB或4MB的页框
9.Global标志 ----只应用于页表项 防止常用页从TLB高速缓存中刷新出去
扩展分页
页框的大小为4MB而不是4KB。
大段连续的线性地址转换成相应的物理地址。
32位线性地址分成两个字段:
1.Directory
最高10位
2.Offset
其余22位
物理地址扩展(PAE)
32位扩大到36位(地址管脚数递增)。由4GB到64GB。
64位系统中的分页
线性地址 48位 物理地址 12位
硬件高速缓存
行:几十个连续的字节组成
以脉冲突发模式在慢速DRAM和快速的用来实现高速缓存的片上静态RAM(SRAM)之间传送。
高速缓存单元位置:在分页单元和主内存之间
硬件高速缓存内存和一个高速缓存控制器
高速缓存内存放真正的行。
高速缓存控制器存放一个表项数组,每一个表项对应高速缓存内存中的一个行。
表项有一个标签(tag)和描述高速缓存行状态的几个标志(flag)。
高位命中:访问RAM存储单元时,CPU从物理地址中提取出子集的索引号并把子集中所有行的标签与物理地址的高几位相比较。
两种基本策略(高速缓存控制器):
通写:即写RAM又写高速缓存行
回写:只写高速缓存行
高速缓存侦听:CPU修改硬件高速缓存,检查高速缓存是否包含同样的数据。
转换后援缓冲器(TLB)
TLB: Translation Lookaside Buffer
这东西就是一个缓存区域,方便下次取,前提是缓存区域之前保存了你需要的物理地址。
Linux中的分页
采用四级分页模型:
页全局目录(Page Global Directory)
页上级目录 (Page Upper Directory)
页中间目录 (Page Middle Directory)
页表 (Page Table)
物理内存布局
内核将下列页框记为保留:
在不可用的物理地址范围内的页框
含有内核代码和已初始化的数据结构的页框
保留页框中的页绝不能被动态分配或交换到磁盘上
固定映射的线性地址
基本上类似于常量的线性地址。
可以以任意方式建立。
每个固定映射的线性地址都映射一个物理内存的页框。
处理硬件高速缓存和TLB(转换后援缓冲器)
为保证命中率,内核需考虑体系架构。
1.一个数据结构中最常使用的字段放在该数据结构内的低偏移部分,使得这些最常用字段处于高速缓存同一行中。
2.当为一大组数据结构分配空间时,内核试图把它们都存放在内存中,以便所有高速缓存行按同一方式使用。
无法同步高速缓存的处理器,内核提供高速缓存刷新接口。
独立于体系结构的使TLB无效的方法扩展到了多处理器系统中。
避免TLB被刷新:
1.两个使用相同页表集的普通进程之间执行进程切换时
2.当在一个普通进程和一个内核线程间执行进程切换时。
延申出一个懒惰TLB模式的概念。
多个CPU使用相同的页表,并且必须对这些CPU上的一个TLB表项刷新,
在某些情况下,正在运行内核线程的那些CPU上的刷新可以延迟。
要注意的是每个内核线程并不拥有自己的页表集,使用一个普通进程的页表集。
内核进程设置为懒惰TLB模式,普通进程设置为非懒惰TLB模式。
懒惰TLB模式的数据结构
cpu_tlbstate变量是一个具有NR_CPUS个结构的静态数组。
这个结构含有两个字段:
1.指向当前进程内存描述符的active_mm字段
2.两个状态值的state字段:
TLBSTATE_OK和TLBSTATE_LAZY