OS 简单教程六OS 简单教程六
🔬

OS 简单教程六

地址空间

虚拟化完 CPU 后,我们虚拟化内存。为什么虚拟化内存呢?
  • 之前应用使用物理内存,需要指定具体的地址,如 0x80400000 ,如果应用一个个执行还好,下一章会看到为了最大化 CPU 的利用率,应用往往是并行运行的,这就需要应用间线下协商。
  • 如果每个应用都能通过地址访问物理内存,应用就可以为所欲为,为了安全也需要虚拟化。
虚拟化内存的本质是虚拟地址到物理地址的映射,每个应用的虚拟地址总和构成地址空间。
  • 每个应用认为自己独占地址空间那么大的内存
  • 应用的地址空间从 0 开始,应用可以随便自己布局内存分布,不会影响别人
  • 切换应用也要切换地址空间,包括应用和内核,所以 trap 的时候也要切换
我们来看地址空间的数据结构
pub struct MemorySet {    page_table: PageTable,    areas: Vec<MapArea>, }
  • 每个地址空间都有一个页表和若干逻辑段,页表是存储地址映射的数据结构,下节讲,单个页不好统一管理,逻辑段是一组功能相同的页的组合,用来统一管理页。
我们来看逻辑段的数据结构
pub struct MapArea {    vpn_range: VPNRange,    data_frames: BTreeMap<VirtPageNum, FrameTracker>,    map_type: MapType,    map_perm: MapPermission, }
  • VPNRange 是一个虚拟页号的迭代器,保存了这个逻辑段下所有虚拟页号,从后面可以看到,等于所有的虚拟地址
  • data_frames 保存所有的物理帧,内核和应用不同,应用才给这个字段加物理帧,因为
    • 内核的内存一般不需要释放,常驻内存
    • 内核采用恒等分配(后面会解释)
  • map_type 指定该逻辑段的内存映射方式,到底是恒等还是映射
  • map_perm 权限,脱胎于页表项的 PTEFlags ,一般一个逻辑段的虚拟地址权限相同,所以该逻辑段的所有页表项的 PTEFlags 相同
一个应用对应一个地址空间,一个地址空间所有的映射关系都在一个页表中,页表有很多页表项,每一个都是一个映射,指定了应用一个页的映射关系。
地址空间分为内核和应用,二者内存布局如下
内核高 256G
notion imagenotion image
内核低 256G
notion imagenotion image
应用
notion imagenotion image
可以看到
  1. 内核把各个应用的内核栈放在内核地址空间,而 trap context 却放在应用地址空间,后面具体讲 trap 的时候会解释
  1. 跳板是什么?后面具体讲 trap 的时候也会解释
  1. 分别把代码、数据等都放在各自地址空间
  1. 保护页没有映射关系,主要为了应对递归层数太多

附录:虚拟地址相关的数据结构(请一定要记住,很重要~)

  • 页:每 4K 一个页
  • 虚拟地址:应用访问的地址
  • 物理地址:虚拟地址通过页表映射过的
  • 虚拟页号:每 4K 一个页号
  • 物理页号:每 4K 一个页号
  • 物理帧:实际分配的物理内存
具体代码请参考 https://github.com/buhe/bugu/tree/6

图片来自 https://rcore-os.github.io/rCore-Tutorial-Book-v3/