Lab2 是关于操作系统存储管理的细节。主要是建立内存模型,页表,物理地址映射等。
在Lab2之前,请复习好前序知识:
Lab2内存管理准备知识
MIT6.828——Lab1 PartA
MIT6.828——Lab1 PartB
在开始做题之前,需要了解一下一些常用的函数,宏以及内存布局,建议复习一下LAB1中的简单内存模型,LAB2预备知识中的相关。这里有几个很有用的地址变换工具,具体实现可以查看<code>mmu.h</code>和<code>pmap.h</code>,提前掌握这些小工具对于理解地址变换和后续的程序编写有很大帮助。
名称
参数
作用
PADDR
内核虚拟地址kva
将内核虚拟地址kva转成对应的物理地址
KADDR
物理地址pa
将物理地址pa转化为内核虚拟地址
page2pa
页信息结构struct PageInfo
通过空闲页结构得到这一页起始位置的物理地址
pa2page
通过物理地址pa获取这一页对应的页结构体struct PageInfo
page2kva
通过空闲页结构得到这一页起始位置的虚拟地址
PDX
线性地址la
获得该线性地址la对应的页目录项索引
PTX
获得该线性地址la在二级页表中对应的页表项索引
PTE_ADDR(pte)
页表项或页目录项的值
获得对应的页表基址或者物理地址基址(低12位为0)

首先关于第一个函数<code>boot_alloc()</code>这是在内存管理机制还没建立起来时,系统内存的分配函数。在page等建立以后当使用<code>page_alloc()</code>而不该再使用该函数。根据函数的注释,先记录当前的free指针,然后将free指针偏移n单元即可,注意内存对齐(使用ROUNDUP函数)。
第二个函数是初始化内存管理了,只需要做到check_page_free_list(1)之前即可。
首先使用<code>i386_detect_memory</code>获取物理内存大小;之后创建内核的页目录,使用的是<code>boot_alloc()</code>,大小是1页(4KB);然后将内核页目录安装到一个页目录项中;之后创建空闲物理页数组pages。
第三个函数,建立page相关的数据结构。首先哪些物理内存是free的?根据注释,首先物理内存的第0页需要被标记为已使用;IO-hole需要被标记为已使用,不能被分配出去;扩展地址包含内核地方不能被分配出去,剩下的空间就可标记为free并后续可以分配出去。
第四个函数,是后续应该使用的内存分配函数<code>page_alloc</code>,根据前面我们知道,<code>page_free_list</code>指着第一个空闲页,因此只需要从这个链表上摘取一个下来即可。这里通过前面的几个函数或者宏,可以将<code>struct PageInfo</code>轻松地对应到物理地址或者虚拟地址。
第五个函数,作用是释放一个页。也就是将一个<code>struct PageInfo</code>结构,重新挂回<code>page_free_list</code>。注意不能释放一个引用值不为0的页,或者链接值不为空的页。
这一部分的前序知识,可以看上一篇文章Lab2内存管理准备知识。于是开始建立页表管理。
第一个函数,用于给定一个页目录和虚拟地址,返回对于的页表项指针。就是一个访问二级页表找值的过程,上一篇文章中详细地写到了。
第二个函数,建立起一段虚拟地址空间和物理地址空间的映射关系,也就是填充页表的值。
第三个函数,查找一个虚拟地址对应的页。
第四个函数,取消一个映射关系
第五个函数
继续完善```mem_init()``
现在可以来一段总结了
这便是JOS目前建立起来的内存映射了,左侧是物理地址空间,右边是虚拟地址空间。比如说UVPT,在代码中有这样一段
而<code>PDX(UVPT)=1110 1111 01</code>因此地址区间<code>0xef400000~0xef7fffff</code>共计4MB被映射到<code>PADDR(kern_pgdir)</code>处。而正如JOS一开始所说,只会使用256MB的内存,映射关系也满足。
内存映射这块,需要好好地阅读代码,文章中没有详细地列出JOS内存布局,虚拟内存的布局在<code>memlayout.h</code>中
为了更好地理解这部分,需要熟悉保护模式分页模式下地寻址Lab2内存管理准备知识
要区分好物理地址和虚拟地址,页表,页目录这些里面装地内容是什么
要有一个内存模型总体上的概念