XV6的内存管理

简介

用自己的语言描述XV6的内存管理系统。

引子

当xv6在启动的过程中,主控函数main调用了三个函数来完成内存管理系统的初始化。

  • kinit把空闲的物理内存以页为单位放到一个单向链表kmem.freelist里,这样就可以通过操作这个链表来管理物理页了。
  • kvminit是给物理页和虚拟页之间建立映射关系,这样就为开启分页做好了准备。
  • kvminithart用于开启分页。

与内存管理相关的文件有kernel目录下kalloc.cvm.cmemlayout.h

  • kalloc.c的作用是进行物理内存管理,它的核心数据结构是kmem.freelist,它的核心函数是kfreekalloc
  • vm.c的作用是进行虚拟内存的管理,它的核心变量是kernel_pagetable,它的函数用于管理虚拟内存,即包括在管理员模式下,也包括在用户模式下。
  • memlayout.h的作用是描述物理内存的布局。其内容是一些重要的物理地址的宏定义。

虚拟内存到物理内存的映射

RISC-V有三种映射方式,Sv32、Sv39、Sv48。它们区别仅在于映射的层级不一样,进而物理地址和虚拟地址的可表示范围不一样。其中Sv32是二级映射,Sv39是三级映射,Sv48是四级映射。

虚拟地址和物理地址的页内偏移是相等的,所以,它们的大小的设计仅需考虑PTE。

对于Sv32,每个PTE占用4个字节,所以页表对应了(4K/4B)=1024个PTE,所以每一级VPN需要占用10位,所以它的虚拟地址是10*2+12=32位。由于高22位是PPN,所以物理地址是22+12=34位。

对于Sv39和Sv48,每个PTE占用8个字节,所以页表对应了(4K/8B)=512个PTE,所以每一级VPN需要占用9位。类似于Sv32的计算方式,可得它们的有效虚拟地址,Sv39是9*3+12=39位,Sv48是9*4+12=48位。它们的PPN都是44位,所以物理地址是44+12=56位。

内核空间的映射

对于机器virtio来说,物理内存是从0x80000000开始计数的,物理内存前面的部分是MMIO。

0~0x7FFFFFFF是MMIO,映射在虚拟内存相同的位置。

0x80000000~0x80000000+128M,映射在虚拟内存相同的位置。

trampoline页,用于内核空间和用户空间的切换,被映射在虚拟内存的顶部。

内核栈,被映射在虚拟内存里trampoline页的下面。

参考文档