操作系统课设实验七---Nachos内存地址扩展

这次我们实验要求是一直做到实验七为止,但是比较难受的就是按照实验七的要求内存地址空间扩展部分即使做完了也没法验证,因为如果想验证就需要等到实验八做完才能验证,这里为了通过增加部分代码的方式来对实验七进行了验证,很多实现也参考了写完实验八的那位学长的博客。
山东大学操作系统课设实验nachos系统(6)系统调用Exec()和Exit()

一、实验要求重述

扩展地址空间,使其能够运行多个用户程序。

通过查看实验指导书中的Things to Do,可以知道在本次试验中,我们需要扩展地址空间使其能够运行多个用户程序,此外就是通过对Exec函数的处理,使得我们能够观察到扩展地址空间之后的结果。

二、地址空间扩展部分

首先我们来处理地址空间的扩展,通过对相关代码的分析,我们知道与空间分配有关的代码均在AddrSpace这个类中,在修改之前虚拟地址页到物理地址帧之间的映射是一对一的,这样也无法运行多个用户进程,所以我们需要对其进行修改,根据提示,我们知道这里在分配物理地址单位的时候可以用到bitmap这个数据结构,而这个数据结构可能在整个系统运行过程中都需要,因此我们可以把它设置为一个静态变量,这里我写到了addrspace.h中,如图:
bitmap的添加
我们曾经在文件系统的扩展中用过这个数据结构,那时将其写到磁盘上的时候只占了一个扇区,通过计算可以知道其最多存储128个项目,这里我们沿袭传统,也设为128,如果需要的话也可以设置的更大。
有了分配使用的数据结构,我们可以来实际的进行物理内存的分配,这里可以看到AddrSpace的构造函数中之前的设定是物理内存与虚拟内存一一对应,为了让一个虚拟内存号对应多个物理内存号,我们在这里使用BitMap来为其分配一个空闲的物理帧。
find
之后我们看到构造函数中调用了一个bzero函数,这个函数会将主存清空,即置为0,这里我们并不需要它去清空主存,所以把这句话注释掉。按照注释说明是应该注释掉这句话的,不过有同学说没有注释似乎也能执行。。
bzero
最后在构造函数中的代码段和初始化数据的读取用到的是之前的虚拟内存页号,因为之前虚拟内存等同于物理内存,既然我们这里修改了原来一一映射的关系,这里我们也要进行处理,处理方法就是通过虚拟内存计算出实际内存来,具体算法就是首先通过虚拟内存和页大小计算出所在页,然后得出所在页对应的物理帧,最后加上页内偏移量即可。这里首先计算代码段的物理地址:
物理地址

这里通过代码上下文的阅读我们知道程序的代码段是写在物理帧的起始位置,所以不需要加偏移量也可以找到具体内容,所以这里省去了偏移量的计算。接下来还有初始数据的读取:
初始数据
这里的初始化数据段未必写在页的起始位置,因此我们需要计算出偏移量并在最后计算物理地址时加上偏移量。
到这里我们分配物理内存的部分就算完成了,但是如果不对分配的内存进行释放,最后也会导致系统出错,所以我们需要在析构函数中释放掉BitMap中分配的物理内存,代码如下:
free

至此,扩展内存的部分就全部完成了。

三、扩展结果检验部分

首先我们知道Exec函数属于一个系统调用,因此会在exception.cc文件中的ExceptionHandler函数中进行处理,因此我们需要增加一个else if语句来对其进行处理,否则会直接调到else语句中,无法实现功能。

在这个else if语句中,我们需要做到3件事,拿到Exec函数的参数、开启一个新的线程去运行新的程序文件、将寄存器的值增加防止其卡死在这里。

首先来说拿参数的部分,通过对注释的阅读,我们知道第一个参数存储在4号寄存器中,所以我们可以从4号寄存器中读取出所需的字符串参数,而这里我们取出的是一个虚拟内存,因此我们可以使用Machine::ReadMem函数来读取出与其对应的物理内存中存储的内容,这里由于是一个长度未知的字符串,因此在读取时需要逐字符处理,一直读,直到读到’\0’为止,并将读到的字符拼接成字符串。代码如下:
读参数

接下来则是新建线程,这里我们可以参考实验一的进程切换与progtest.cc中的StartProcess方法来实现线程的新建。

这里首先说一下StartProcess方法,他的作用就是传进去一个文件名字符串,然后它根据这个文件名打开并执行对应的进程,然而我们将要使用的Thread的Fork方法却支持的是int类型参数,所以我们需要将StartProcess的参数改为int类型,并在内部将其转换为char *类型,再去执行原来的逻辑,代码如下:
startProcess
最后则是fork一个线程去执行StartProcess方法,这里仿照实验一中的内容来实现:
fork

这里传入时取到filename字符串的起始地址,转换成int类型再传入。
最后则是寄存器的推移,这里可以参照mipssim.cc中相关代码来实现:
寄存器推移
至此,测试的代码也修改完了,最后则是完成并编译测试代码。

四、编写测试代码并运行

在test目录下新建bar.c和exec.c,并写入实验指导书给出的测试代码:
测试文件
为了编译这两个新文件,我们需要修改test目录下的Makefile文件,在target那一行后面添加上bar和exec:
makefile

然后首先在test下面执行make命令来编译这两个新文件,再去userprog下执行修改完并编译过的nachos,并加上运行参数来运行bar.noff程序,得到如图的效果:
result
即扩展空间成功,并且exec命令得到执行。

猜你喜欢

转载自blog.csdn.net/zekdot/article/details/84308449