接下来我们看一下lab2的
这个实验指导书
来对lab2要完成的工作
做一个初步的了解
那lab2主要是完成物理内存管理
当然是建立在lab1基础之上的
意味着如果你lab1没有完成
那你没法开展lab2的工作
这是它们是一个就是有相互依赖关系的
之后的实验也都具有同样的特点
那这个实验的目的是什么呢
这个实验目的是结合我们原理课的讲解
更深入的理解段页式内存的
地址的转换方式
以及如何建立页表
建立页表之前其实还有一个
连续地址空间的这个物理内存管理
这一块呢
也是需要在lab2中有更深入体会
大家可以看一下就是在lab2中
如何通过我们一系列的
操作来完成这些工作的
其实大家很关注就是要完成几个练习
lab2提供三个基本练习和两个扩展练习
我们一个一个来逐一给大家做个讲解
首先这个练习0呢实际上
就是重复lab1的工作
把lab1做的那些你修改的
那些代码填到lab2中来
你可以通过一些工具
比如说diff和patch来自动的merge
如果merge合并的时候呢 出了点问题的话
就可能要手动来做更新
也可以用图形化的工具来手动合并
比如说我们这里面提供的meld等等
这是第一步
因为你要把lab1的工作
能够让它正常工作了
才能进一步完成lab2的后续的一些工作
这个实际上是一个基本的
第二步就是说怎么去来完成
对这个物理内存空间的
分配的一个算法实现
那在原理课中我们讲了好几种不同的
连续物理内存空间的分配算法
包括first-fit best-fit worst-fit等
这里面我们考虑
在操作系统里面怎么来实现
那看起来在原理课里面讲的
first-fit是相当简单的
那如果要具体实现在我们的
ucore操作系统里面
我们设计实现一个新的一种框架
在基于物理内存管理框架之下呢
我们可以实现不同的这个内存分配算法
那么first-fit是我们要求大家去完成的
首先你们就要去了解
我们说的物理内存pmm manager
这么一个程序里面
它到底是怎么来组织的
这也是需要根据源码来看一下
那在这个lab2源代码里面
我们可以看到两个文件
default_ pmm.h和default_ pmm.c
那这里面很重要的pmm_ manager
在这个框架里面
我们设定好了一个
连续物理内存分配算法的
一个最主要的一些函数的实现
这里面列出来了
我们重点实现的是分配 释放
当然你要能够完成正确的分配 释放
你还需要有一定初始化的工作
为什么初始化
首先要把我们说在ucore启动之后
要把我们计算机物理内存有效感知
然后知道哪些是空闲的
哪些可以去为后续做malloc free
动态内存分配
这个需要在前面init_ memmap
这一块来完成
最后这个是完成一个检查
这个检查是说
我们知道想判断一下你的实现是否对
我们会有check 这么一个函数
这个是得到当前
剩余多少页的这么一个函数
就是返回当前的free pages
这个形成了我们pmm_ manager
看起来比较简单
这是基于函数指针的方式来实现的
那我们需要把我们的first-fit
这个代码填到这里面
这里面有详细的信息
这里面到底要怎么做
你的代码应该怎么去完成相应的工作
它的步骤是什么 这里面都列出来了
我建议大家在实现之前呢
把这一块代码仔细阅读一下
仔细阅读一下
来理解你应该怎么来填写
那到底你填在什么地方
这个也是需要注意的
在我们这个源代码里面呢
我们可以通过
如下这个命令来查找
你需要填写的地方
我们已经标注出来
大写的LAB2这个位置呢
实际上就是你要填写的地方
我们每个练习里面都包含这个信息
就是可以看到在练习一里面呢
它在这个地方需要你去填写
如果是在后续的练习 练习二和练习三
那么在这个地方要填写
这里面也知道
比如你要完成first-fit这个算法呢
这需要对default_ pmm.c
这个文件呢做相应的填充
来实现你的那些
刚才说那些函数指针里面对应的函数
从而可以完成正确的
分配内存和释放内存
以及初始化内存的工作
那这里面可以看到
其实这些函数 列出来了一些
但这些并不是一个正确的first-fit实现
它也许可以工作
但其实它没有达到
first-fit它所要求的功能
所以说我们需要去对此进行修改
来完成这个对这个以页为单位的
内存的动态分配
这个内存是连续物理内存
这是第一部分的内容
那我们还希望你通过
完成这个实验之后
能够在你的实验报告中说明
你设计过程中
到底有没有进一步改进空间
其实first-fit这个实现呢
有多种实验方式
你可以有一些技巧
来使得它更加高效
甚至说你还可以去跟worst-fit
或者是best-fit进行比较
当然前提是你需要去实现
看看在你的操作系统里面
这些算法到底哪个好
哪个差一些 这是练习一的工作
练习二的工作主要是完成页表的
一个更深入的理解
通过设置页表和对应的列表项来建立
对于某一个虚拟地址和物理地址
一个对应关系
所以说练习二呢 它需要去修改
修改跟页表相关的一些位置信息
那我们前面已经看到你修改练习二
主要集中在pmm.c 350行这个地方
我们查一下pmm.c
大约的位置在这儿
这里面是要完成一个获取页表项(page table entry)
这么一个函数的实现
这里面讲到两点
或者这个页表项已经建立好了
那么你只需查找对应的这个逻辑地址
我们称之为虚拟地址和逻辑地址
它所对应页表项是哪一项
把它取回来就OK了
如果说这里面没有这一项
对应的逻辑地址或者是线性地址
它没有页表项对应
那你就需要创建一个页表项
你怎么去实现对页表项的创建
这需要去修改相关的一些函数
来完成对应的功能
那我们这里其实也列的比较详细
你到底要完成哪些步骤
这个是肯定是错的
但是它的注释也一样
你需要仔细的阅读这一块的注释
以及这里面一些要求
这实际上给很多帮助
你要为了完成这个功能
你可以用我们这里面
ucore里面已有一些函数
到底用哪些函数
哪些宏 可以帮助你来完成这些功能
这是练习二要求的
我们还可以通过understand来
其实还可以更深入看一看
整体的架构它怎么实现的
这一点需要大家掌握
就是这个get_ pte这个函数
到底是怎么调这个函数来的
怎么一步步过来的
那从最开始的kern_init一直到pmm_init
再最后获得PTE
那我们其实在understand里面
也很好可以看到这个过程
在kern_init其实是
整个内核初始化的总控函数
我们前面还没有涉及到
物理内存这些管理之后
其实比如说之前中断控制器的初始化
中断向量表初始化等等
都在这儿来完成了
这次呢新增加了pmm初始化
那我们可以看看这个函数在这儿
它的一个函数量关系比较复杂
那可以看出来这是kern_init比较小
调到了pmm_init
然后呢最后它还会去一层一层的去
我们看看在哪
比如说在这儿
check_ pgdir这么一个函数
这个函数会进一步
调get_ page获取某一个页
这里面呢会调get_ pte
这里面就可以看出来
它有不同的调用关系
get_ pte有好几个函数对它进行有调用
我们双击一下这个呢
可以在这儿重新看一下以get_ pte为准
来看一下它被谁调用了
那可以看出来 这里列出来了
被这些函数所调用
通过理解这些函数的实现能够知道
这些函数在什么情况下
为什么调用get_ pte
从而可以更好地有助于完成get_ pte
这个函数里面的需要完成的功能
另一方面我们还希望大家在实验报告中
能够说明如下一些问题
比如说如果你访问一个虚拟地址
或者一个线性地址
然后呢按道理来说应该有一个对应的
物理地址和它对应
如果说这个物理地址没有对应
也意味着你的页表项或者没有
或者是建错了 会出现页访问异常
这时候出现什么情况 OK
第二个呢
如果说出现了页访问异常那么
我们ucore呢它应该有一个
对应的缺页的服务例程
中断服务例程来完成对这个
页访问异常的进一步处理
但是如果说这个缺页服务例程
缺页中断服务例程
进一步又出现了页访问异常
那会出现什么现象 请大家思考一下
这是练习二这一块的工作
那练习三呢 其实是练习二的一个
反操作或者逆操作 前面是建立
建立对应的页表项
从而把这个映射关系建立好
这里面是说如果要释放一个映射关系
把这个页给释放掉
那么就意味着不存在了
我们应该让它这个页表
这个映射关系也取消 怎么做
这里面你如果说
对这个get_ pte有一定了解之后
相信你来完成所谓page_ remove_ pte
也一样可以比较好的完成相应的工作
同样 用同样的方法
可以用前面说到的415行是练习三
在这里面完成这个page_ remove_ pte的
一个大致实现
这里面讲函数到底要干什么
然后还讲到它大致一个实现步骤
这里是重点需要你去填写的
当然提醒一下你实现完之后
把这个注释给去掉
否则这个代码是无法
被编译到执行码里面去的
好 那我们完成了这个函数实现之后呢
我们希望你能够在实验报告中
回答如下一些问题
第一个是关于数据结构
page的全局变量它是什么
它其实是一个数组
这个数组每一项与页表中的
页目录项或者是
页表项有没有对应关系
如果有这个关系那关系是啥 这是一个
第二我们前面已经讲到在lab2中
我们完成的虚拟地址到物理地址映射
是有一个偏移
就是虚地址是0xC0000000
会映射到物理地址0
这是一个非对等映射
如果我们要完成对等映射也意味着
虚拟地址的0也就是物理地址0
如果要完成这件事情怎么做
我们希望大家能够去尝试一下
也同时能够在实验报告中做一个说明
当然你如果不完成这个编程
也是没有问题的
我们完成的要求的编程是
练习一二三里面明确指出的
要修改或者扩展的几个函数
好 接下来我们再看一下扩展练习两个
第一个是buddy system
第二个是slub分配算法
那这两个分配算法呢
在我们今年呢
通用操作系统里面是存在的
这两个都在Linux里面有对应的实现
那我们可以考虑能不能在我们ucore中
实现buddy system和slub分配算法
一个可以给大家提示一点是说
其实在我们早期的这个同学实验中呢
已经完成了对这个
buddy system和slub分配算法的一个实现
所以说希望大家
在有兴趣有时间的情况下
可以尝试一下这挑战中的一个或两个
好 那我就把练习
给大家做一个简单介绍
那为了能够更好的完成
更好的完成这个练习呢
我希望大家能够把后续这个
lab2实验执行流程能够去读一下
从而可以在整体上知道
lab2是怎么完成的
读完这个文档之后
就是lab2的实验指导书之后呢
还需要大家能够
去结合代码去静态的分析
或者说是动态的调试来看我们这个
lab2大致的一个执行过程
和对文档描述是否一致
从而可以对如何感知物理内存
这个在原理课中是没有涉及到的
如何以页为单位来管理内存
实现段页式机制
那么这部分在原理课中
也很少涉及到这么详细的细节
这是需要大家通过理解原理
分析代码 调试代码
完成我们的练习
从而可以有一个更好的一个
更深入的一个理解
那这是最后的实验报告
要求指出了我们要
把我们代码提交到git server上去
然后我们这个实验报告呢
是markdown格式
也需要大家提交到我们
对应的git server的帐号
所对应的git repo里面去
注意有lab2的注释你去写的时候
还要将your code
替换为你的学号
这一点希望大家能够稍微
在提交代码之前注意一下
这里面附录A B C D
是有一些相关的一些讲解
A B C是和物理内存相关
以及虚拟地址 物理地址的
一个对应关系做了一个介绍
自映射呢是一个更高级的机制
它描述了如何通过
虚拟地址的一个访问
快速把这个页表给打印出来
它还有其它一些功能
在这里面如果有感兴趣的同学
可以深入去分析一下
这个附录D所描述的内容
好 我们其实可以看看
如果说lab2你如果完成了
正确完成了相应的工作
我们可以执行一下
可以看到在这里面呢
lab2已经正确完成了这个内存的分配
建立好了相应的页表
然后在enable了
这个段机制和页机制之后
所有的系统还依然能够
正确完成相应的工作
包括lab1里面的中断实现
你看还在正确地一步步地
产生相应的执行
希望大家能够
更好地更顺利地完成这个实验
在这里面你也许
会碰到一些意想不到一些困难
希望大家能够及时到我们说的
piazza那个问答平台去提问
我们的助教随时解答
大家碰到的一些问题
好 谢谢大家