1.实现nachos中用户程序的装入和内存页式转换机制,
2.实现带有TLB机制的内存管理机制
3.实现几种基本的系统调用功能
4.实现虚拟内存管理机制
5.通过多用户程序并发执行验证以上你的设计是否成功的实现了。
6.扩展现有的class AddrSpace的实现,使得Nachos可以实现多用户程序,完成系统调Exec
使Nachos按页分配内存空间
二、实验环境:
硬件环境(虚拟机下):1G内存 60G硬盘空间 CPU主频:2.1GHz
软件环境:linux操作系统(gdb和g++ gcc,mips交叉编译器配置)
三、实验内容:
1. 首先编写实验6的Print函数,为了可以显示内存空间的分配。以下为Print函数的实现:
addrSpace.cc:
void AddrSpace::Print()
{
printf("page table dump: %d pages in total\n", numPages);
printf("============================================\n");
printf("\tVirtPage, \tPhysPage\n");
for(int i=0; i < numPages; i++) {
printf("\t%d, \t\t%d\n", pageTable[i].virtualPage, pageTable[i].physicalPage);
}
printf("============================================\n\n");
}
#include "syscall.h"
int
main()
{
int i,j,k;
k=3;
i=2;
j=i-1;
k=i-j+k;
Halt();
/* not reached */
}
#include "syscall.h"
static int a[40];
int
main()
{
int i,j,k;
k=3;
i=2;
j=i-1;
k=i-j+k;
Halt();
/* not reached */
}
2. 编写一个exec.c的源码,然后编译生成一个可执行文件,exec.noff
#include "syscall.h"
int main()
{
SpaceId pid;
pid=Exec("../test/halt.noff");
Halt();
}
3. Nachos原来实现AddressSpace分配的时候没有使用bitmap来寻找空闲页,而是直接的从0号内存空间开始分配,因而需要修改成使用bitmap的find函数分配内存空间
pageTable = new TranslationEntry[numPages];
for (i = 0; i < numPages; i++) {
pageTable[i].virtualPage = i; // for now, virtual page # = phys page #
//=======================================================
pageTable[i].physicalPage = freePageMap->Find();
//=======================================================
pageTable[i].valid = TRUE;
pageTable[i].use = FALSE;
pageTable[i].dirty = FALSE;
pageTable[i].readOnly = FALSE;
}
其中,要声明一个位试图的是对象,在AddrSpace中
//================================
static BitMap *freePageMap = NULL;
//================================
AddrSpace::AddrSpace(OpenFile *executable)
{
NoffHeader noffH;
unsigned int i, size;
//================================================
if(freePageMap == NULL) {
freePageMap = new BitMap(NumPhysPages);
}
//================================================
executable->ReadAt((char *)&noffH, sizeof(noffH), 0);
if ((noffH.noffMagic != NOFFMAGIC) &&
(WordToHost(noffH.noffMagic) == NOFFMAGIC))
SwapHeader(&noffH);
ASSERT(noffH.noffMagic == NOFFMAGIC);
// how big is address space?
size = noffH.code.size + noffH.initData.size + noffH.uninitData.size
+ UserStackSize; // we need to increase the size
// to leave room for the stack
numPages = divRoundUp(size, PageSize);
size = numPages * PageSize;
ASSERT(numPages <= NumPhysPages); // check we're not trying
// to run anything too big --
// at least until we have
// virtual memory
DEBUG('a', "Initializing address space, num pages %d, size %d\n",
numPages, size);
4. 计算加载一个程序需要的页表的数目
numPages = divRoundUp(size, PageSize);
size = numPages * PageSize;
5. 实现Nachos的系统调用,采用的是触发异常中断的,在userprog/exception.cc,添加SC_Exec异常,存放要执行的文件的路径的字符串的首地址存放在4号寄存器中,因此可以通过这个方式找到文件的路径,从而使用文件系统提供的方法打开这个文件:
void
ExceptionHandler(ExceptionType which)
{
int type = machine->ReadRegister(2);
//printf("exception handler\n");
if ((which == SyscallException) && (type == SC_Halt)) {
DEBUG('a', "Shutdown, initiated by user program.\n");
printf("HALT!!\n");
//printf("AddrSpace addr is %d\n", (int)currentThread->space);
interrupt->Halt();
} else if((which == SyscallException) && (type == SC_Exec)) {
printf("exception exec\n");
int fileAddr = (machine->ReadRegister(4));
char* filename = readFileName(fileAddr);
//printf("filename is :%s\n", filename);
OpenFile *executable = fileSystem->Open(filename);
//printf("file opened!\n");
if(executable == NULL) {
printf("Unable to open file \n", filename);
return;
}
//printf("Old AddrSpace addr is %d\n", (int)currentThread->space);
AddrSpace *space = new AddrSpace(executable);
delete executable;
delete filename;
//machine->Debugger();
space->InitRegisters();
space->RestoreState();
delete currentThread->space;
currentThread->space = space;
machine->WriteRegister(2, (int)space);
//printf("register 2 written back. The value is :%d\n", (int)space);
//pcInc();
return;
} else if((which == SyscallException) && (type == SC_Exit)) {
//printf("EXIT!!\n");
int status = machine->ReadRegister(4);
printf("STATUS IS %d\n", status);
//printf("AddrSpace addr is %d\n", (int)currentThread->space);
if(status == 0) {
//currentThread->Finish();
machine->WriteRegister(2, 0);
}
pcInc();
return;
} else {
printf("Unexpected user mode exception %d %d\n", which, type);
ASSERT(FALSE);
}
}
6. 结果分析:编译成功之后,输入命令 ./nachos –x ../test/Exec.noff
运行结果:
四 实验体会及总结
结论分析与体会:
Nachos之前没有实现按页分配地址空间,物理页和逻辑页地址一致,而且数据段代码段连续分配,每当一个新的用户程序建立的时候,虚拟地址和物理地址都是从0开始分配,这样新的用户程序将会冲掉原来在物理0开始的程序。
因而使用位示图分配物理地址。使用bitmap的find函数分配虚存对应的物理地址,在为数据段和代码段写入数据的时候是以扇区为单位的,而不是原有的连续一个文件的读入连续的内存。Nachos操作系统通过中断的方式实现系统调用。需要增加userprog/exception.cc中的内容,即必须在此类中添加处理Exec的方法