Lec 05 内存地址翻译

Lec 05 内存地址翻译

(参考来源:上海交通大学并行与分布式系统研究所+操作系统课程ppt)
Creative Commons Attribution 4.0 License

Contents

1. 内存管理

a

1.1 物理内存

  • 常说的“内存条”就是指物理内存
  • 数据从磁盘中加载到物理内存后,才能被CPU访问
    -- 操作系统的代码和数据
    -- 应用程序的代码和数据

1.2 早期系统

  • 硬件
    -- 物理内存容量小
  • 软件
    -- 单个应用程序 + (简单)操作系统
    -- 直接面对物理内存编程
    -- 各自使用物理内存的一部分

a

1.3 多重编程时代

  • 多用户多程序
    -- “发生在共享单车前的共享计算机”

  • 分时复用CPU资源
    -- 保存恢复寄存器速度很快

  • 如何共享物理内存资源?

1.分时复用物理内存资源

-- 将全部内存写入磁盘开销太高

2.同时使用、各占一部分物理内存
-- 缺乏安全性/隔离性
-- 如何不被物理内存容量限制?

a

在编译语言中,编译器会对每一行指令,生成一个地址编码

a

1.4 虚拟地址空间易于程序开发

  • 编译器面临的问题
    -- 如果某个地址的物理内存被别人占用了怎么办?
    • 例如:0x400000
      -- 如果物理内存大小不够怎么办?
  • 解决:编译器假设应用运行时,会独占所有内存,且内存足够大
    -- 内存大小:\(2^{32}\) Byte,或\(2^{64}\) Byte,称为“虚拟内存空间”
    -- 编译器基于该假设进行内存布局,并生成指令
  • 谁来实现这个假设?CPU+操作系统
    -- 思路:地址映射(虚拟地址翻译到物理地址)
    -- 由CPU将虚拟地址翻译到物理地址,由操作系统来配置如何翻译

1.5 物理地址(physical address, pa)

  • 物理内存可以看成由连续字节组成的数组
    -- 每个字节都有唯一的物理地址

a

1.6 虚拟地址(virtual address, va)

  • Memory Management Unit (MMU)
    -- 按照规则将虚拟地址翻译成物理地址

a

1.7 主流翻译规则:分页机制

  • 分页机制
    -- 虚拟地址空间划分成连续的、等长的虚拟页
    -- 物理内存也被划分成连续的、等长的物理页
    -- 虚拟页和物理页的页长相等
    -- 虚拟地址分为:虚拟页号 + 页内偏移
  • 使用页表记录虚拟页号到物理页号的映射
    -- 页表:Page Table

1.8 页表:分页机制的核心数据结构

a

1.9 分页机制的特点

  • 物理内存离散分配
    -- 任意虚拟页可以映射到任意物理页
    -- 大大降低对物理内存连续性的要求

  • 主存资源易于管理,利用率更高
    -- 按照固定页大小分配物理内存
    -- 能大大降低外部碎片和内部碎片

  • 被现代处理器和操作系统广泛采用

1.10 基于分页的地址翻译

a

页内偏移不会因为翻译而改变,只会由页面大小决定。

a

1.11 通过页表进行地址翻译

a

页表:

  • 存储在屋里内存中。由OS进行维护。
  • 起始地址存放在页表基地址寄存器中。

1.12 内存地址翻译示例

  • 假定一种地址格式
    -- 14 位虚拟地址
    -- 12 位物理地址
    -- 页大小 = 64 字节 (6位)
  1. 确定我们的虚拟地址(虚拟页号+虚拟页内偏移)以及物理地址(物理页号+物理页内偏移)

a

a

a

我们有虚拟地址0x03D4.
虚拟地址
00 0011 1101 0100
页大小64字节,6位,因此虚拟页号为0000 1111
查看我们的页表,有物理页号是0D.
因此我们的物理地址为
0011 0101 0100
也就是0x354

2. 多级页表

2.1 单级页表存在的问题

对于有14位的虚拟地址,12位的物理地址,页表本身将会有:

  1. 假设32位的地址空间,页大小为4K,页表项则为4字节。
  2. 假设64位的地址空间,页大小为4K,页表项则为8字节。
  • 对于32位的地址空间
    -- \(2^{32}/4K * 4=4MB\)
    -- \(2^{64}/4K * 8=33,554,432GB\) !

单级页表会导致占有的空间过大!

2.2 多级页表

  • 多级页表能够有效压缩页表的大小。
  • 原因:允许页表出现空洞
    -- 若某个页表页中的某个页表项为空,那么其对应的下一级页表页就无需存在。
    -- 应用程序的虚拟地址空间大部分都未分配

2.3 AArch64 体系结构下4级页表

a

a

a

页表占用16K,虚拟地址范围?

  • 我们有:
  • 一个页表项8Byte,64位
  • 一张页表页有\(2^9\)个页表项,\(2^{12}Byte=4KB\)
  • 根据四级页表结构,我们就有:一张0级页表(一个页表项),一张一级页表(一个页表项),一张二级页表(一个页表项),一张三级页表(可以全满),也就是\(2^{9}个\)页表项。
  • 那么,每个三级页表项可以寻找到\(2^{12}\)个地址。因为是按字节寻址,因此一个地址为1个Byte,也就是\(2^{12}Byte\).
  • 那么这样,我们总共有寻址空间:\(2^9\cdot 2^{12}=2^{21}Byte=2MB\).
    因此虚拟地址范围为2MB。

2.4 多级页表节省内存

假设进程只用到0,1,\(2^{36}-1\)三个虚拟页

  • 单级页表,需要\(2^{36}\)个页表项,占用\(2^{39}Byte\).
  • 四级页表,需要一个0级页表(2个页表项),两个一级页表(每个一个页表项),两个二级页表(每个一个页表项),两个三级页表(三个页表项2+1)。因此总共为2+2+2+1=7,也就是28KB。

1.多级页表一定比单级页表占用的少?
不一定。如果应用占用了大量的虚拟空间(例如占用了\(0~2^9-1\)的所有空间,此时单级页表将要比多级页表少占用空间。多级页表的优势在于当应用程序占用跨度大但是不多的虚拟空间时,可以节省存储空间。

2.虚拟地址0xFFF8080604FFF对应的各级页表的索引?
分为虚拟页号+页内偏移。
我们有
1111_111111111_000000010_000000011_000000100_111111111111
因此0级页表索引第511项,1级页表索引第2项,2级页表索引第3项,3级页表得到真实物理页号为4,页内偏移为511.
3. 若在页表中填写\(0\thicksim16M\)的映射,页表需要占用?

  • 我们有:\(16MB=2^{4}\cdot 2^{20}B\)个映射。
  • 这样我们有:\(24=12+9+3\)这样我们需要8张三级页表(满表),1张二级页表(8项),1张一级页表(1项),1张0级页表(1项)
  • 这样空间占用则为: 44KB。

2.5 页表基地址寄存器

  • AARCH64
    -- 两个页表基地址寄存器:TTBR0_EL1 & TTBR1_EL1
    • MMU根据虚拟地址第63位选择使用哪一个
      -- 以Linux为例
    • 应用程序(地址首位为0):使用TTBR0_EL1
    • 操作系统(地址首位为1):使用TTBR1_EL1
  • X86_64
    -- 一个寄存器:CR3(Control Register 3)

2.6 页表使能

  • 机器上电会先进入物理寻址模式
    -- 系统软件配置控制寄存器使能页表进入虚拟寻址模式
  • aarch64
    -- SCTLR_EL1,System Control Register, EL1.
    -- 第0位(M位)置1,即在EL0和EL1权限级使能页表
  • X86_64
    -- CR4,第31位(PG位)置1,即使能页表!
    操作系统运行过程中使用虚拟地址。实际执行时通过页表等翻译成物理地址。

a

3 页表项

  • 每级页表有若干离散的页表页
    -- 每个页表页占用一个物理页
  • 第 0 级(顶层)页表有且仅有一个页表页
    -- 页表基地址寄存器存储的就是该页的物理地址
  • 每个页表页中有 512 个页表项
    -- 每项为 8 个字节(64位),用于存储物理地址和权限

a

  • V(Valid):当访问时V=0,则触发缺页异常
  • UXN(Unprivileged eXecute Never):用户态不可执行(例如栈)
  • PXN(Privileged eXecute Never):内核态不可执行(防止内核执行用户代码)
  • AF(Access Flag):当访问时,MMU标记该位
  • AP(Access Permissions)
  • DBM (Dirty Bit): 51位,ARMv8.1-TTHM特性支持

a

a

a

  • 有效的0-2级页表项
  • 第1位为0表示PFN指向大页
  • 第1位为1表示PFN指向下一级页表

4 TLB:加速地址翻译,缓存页表项

  • Tradeoff是计算机中经典而永恒的话题
  • 多级页表的设计是典型的用时间换空间的设计
    -- 优点:压缩页表大小
    -- 缺点:增加了访存次数(逐级查询)
    • 1次内存访问,变成了5次内存访问

如何降低地址翻译的开销?

a

  • TLB 位于CPU内部,是页表的缓存
    -- Translation Lookaside Buffer
    -- 缓存了虚拟页号到物理页号的映射关系
    -- 有限数目的TLB缓存项
  • 在地址翻译过程中,MMU首先查询TLB
    -- TLB命中,则不再查询页表 (fast path)
    -- TLB未命中,再查询页表

a

a

4.1 地址翻译

  • 虚拟地址(VA)构成
    -- VPO(Virtual page offset),虚拟页偏移
    -- VPN(Virtual page number),虚拟页号
    • TLBI(TLB index)
    • TLBT(TLB tag)
  • 物理地址(PA)构成
    -- PPO(Physical page offset),物理页偏移
    -- PPN(Physical page number),物理页号

a

a

4.2 TLB刷新

  • TLB 使用虚拟地址索引
    -- 当OS切换进程页表时需要全部刷新

  • AARCH64上内核和应用程序使用不同的页表
    -- 分别存在TTBR0_EL1和TTBR1_EL1
    -- 使用的虚拟地址范围不同
    -- 系统调用过程不用切换

  • 刷新TLB的相关指令
    -- 清空全部 TLBI VMALLEL1IS
    -- 清空指定ASID相关 TLBI ASIDE1IS
    -- 清空指定虚拟地址 TLBI VAE1IS

4.3 TLB刷新导致的开销降低

  • 硬件特性ASID(AARCH64): Address Space ID
    -- OS为不同进程分配8位或16位 ASID
    • ASID的位数由TCR_EL1的第36位(AS位)决定
    • OS负责将ASID填写在TTBR0_EL1的高8位或高16位
      -- TLB的每一项也会缓存ASID
    • 地址翻译时,硬件会将TLB项的ASID与TTBR0_EL1的ASID对比
    • 若不匹配,则TLB miss
  • 使用了ASID之后
    -- 切换页表(即切换进程)后,不再需要刷新TLB,提高性能
    -- 修改页表映射后,仍需刷新TLB(为什么?)
    需要对地址映射进行更新否则会导致页表错误

4.4 页表和多核

  • OS修改页表后,需要刷新其它核的TLB吗?
    -- 需要,因为一个进程可能在多个核上运行
  • OS如何知道需要刷新哪些核的TLB?
    -- 操作系统知道进程调度信息
  • OS如何刷新其他核的TLB?
    -- x86_64: 发送IPI中断某个核,通知它主动刷新
    -- AARCH64: 可在local CPU上刷新其它核TLB
    调用的ARM指令:TLBI ASIDE1IS

4.5 多级页表的优势

  • 高效使用物理内存
    -- 使用 DRAM 作为虚拟地址空间的缓存

  • 简化内存管理
    -- 每个进程看到的是统一的线性地址空间

  • 更强的隔离与更细的权限控制
    -- 一个进程不能访问属于其他进程的内存
    -- 用户程序不能够访问特权更高的内核信息
    -- 不同内存页的读、写、执行权限可以不同

每个进程拥有其独立的内存空间
  • 不同进程互不干扰
    -- 仿佛独占所有内存
  • 绝大部分地址段均可用
    -- 除了顶部的内核地址区域

a

灵活的虚拟内存-物理内存映射
  • 每个虚拟页都可以被映射到任意物理页
  • 一个虚拟页可以在不同的时刻存储在不同的物理页中

alt

alt

可在不同进程之间共享内存
  • 不同虚拟地址空间的虚拟内存页可映射到相同的物理页

alt

基于虚拟内存实现内存保护
  • 不同的进程对相同的物理页拥有不同的权限
    -- 通过页表项中的权限位来控制

总结

alt

posted @ 2024-11-12 13:48  木木ちゃん  阅读(161)  评论(0)    收藏  举报