Operating system course design of Software School of Shandong University Nachos Experiment 7 virtual memory

Posted by abhi201090 on Fri, 21 Jan 2022 20:08:58 +0100

Note: the experiments written in the blog are not comprehensive, and they are not the final version of the submitted experimental report (they are the notes simply recorded with typera during the experiment). The complete content (including code + experimental report) can be passed( Operating system course design of Software College of Shandong University Download, or WeChat official account for "free blog" free access.


1, Virtual memory

1. Problem analysis

Combined with the experimental instructions, the process of realizing nachos virtual memory can be divided into three parts: dealing with page missing exceptions, page replacement and frame allocation.

1.1 request paging technology

Virtual memory technology can be realized by using request paging storage management technology in the system with paging memory management. The key technology is that when the requested page is not in the physical memory, the page missing exception or self trap is used to enter the kernel. The kernel page missing exception handler loads the page into a free memory frame from external memory. If there is no free frame, it will select a page already in the physical memory to replace it. After this exception is handled, the same instruction that issued the memory access will be executed again.

Nachos provides basic mechanisms for implementing virtual memory technology, which can be used to realize virtual memory in nachos. The page missing exception is generated by the MIPS machine simulation function translate.

From this part of the source code, we can see that the parameter addr is the logical address to be found when an instruction is issued. This address is converted to a physical address by calling the function translate. If a page missing exception occurs, it will be dispatched to the corresponding exception handling function by calling the function RaiseException.

Finally, RaiseException calls ExceptionHandler for processing. As in Experiment 6, the first thing we need to do is add a branch to handle missing page exceptions in ExceptionHandler.

1.2 page replacement

Page replacement is to solve the problem of how to select obsolete pages when the physical memory is full and a new page needs to be loaded.

Nachos's support for hardware emulation of page replacement is reflected in machine / translate In the page table structure TranslationEntry defined in the H file:

The variables valid and readonly correspond to the valid and read only bits of MMU hardware and are used for memory management and protection. The variables use and dirty correspond to the hardware use and dirty bits, which are used for virtual memory page replacement.

Significant bit: valid indicates that the relevant page is in the logical address space of the process and in memory and can be accessed. Otherwise, it cannot be accessed (illegal or on disk).

1.3. Frame allocation

The physical memory in Nachos's MIPS simulator is simulated by a byte array. In the file Machine / Machine The constructor of the Machine class defined in CC initializes this basic memory, which is Memeorysize bytes or NumphysPages frames.

In the file machine You can see that the currently defined size of NumPhysPages is 32

2. Implement virtual memory

1. Implement missing page exception handling

Firstly, we implement the missing page exception handling function. In Experiment 6, we have been familiar with the relevant mechanism of nachos exception handling, so the implementation method here is similar to that in Experiment 6.

First, in exception Add else if branch in CC to handle page missing exception by calling PageFault() of interrupt

Then implement PageFault(). First, in interrupt Class methods defined in H

Then in interrupt Implementation function in CC

//lab-7 add by lhw************************************
void
Interrupt::PageFault()
{
	//Read the page you want to swap in from the register
	int badVAddr= machine->ReadRegister(BadVAddrReg);
	AddrSpace *space=currentThread->space;
	//Call FIFO function to realize page replacement
	space->FIFO(badVAddr);
}
//lab-7 add by lhw************************************

2. Implement page replacement

Next, implement the FIFO function

Add a member function in the AddrSpace class and add a member function in the file addspace Defined in H

void FIFO(int badVAdrr);

Then in addrspace Implement functions in CC

//lab-7 add by lhw**************************
void 
AddrSpace::FIFO(int badVAddr)
{
	int newPage=badVAddr/PageSize;
	printf("Need to change in newPage: %d\n",newPage);
	int oldPage = virtualMem[p_vm];
	printf("use FIFO OK to swap out the page oldPage: %d\n",oldPage);
	
	virtualMem[p_vm] = newPage;
	p_vm = (p_vm+1)%MaxNumPhysPages;
	
	printf("conduct FIFO Page replacement:%d Page out,%d Page in\n",oldPage,newPage);
	//Write back
	writeBack(oldPage);
	pageTable[oldPage].valid = false;
	pageTable[newPage].physicalPage = pageTable[oldPage].physicalPage;
	pageTable[oldPage].physicalPage = -1;
	pageTable[newPage].valid = true;
	pageTable[newPage].dirty = false;
	pageTable[newPage].readOnly = false;

	OpenFile *executable = fileSystem->Open(filename);

	if (executable == NULL) {
	printf("Unable to open file %s\n", filename);
		return;
	}
	executable->ReadAt(&(machine->mainMemory[pageTable[newPage].physicalPage]),PageSize, newPage*PageSize);
	delete executable;
	
	Print();
}

The replacePage function calls the writeBack function to write back the replaced page.

Implement the writeback function, also addrspace H definition

void writeBack(int oldPage);

addrspace.cc implementation

//First, judge whether it has been changed through dirty. If true, write back to the disk
void 
AddrSpace::writeBack(int oldPage)
{
	if(pageTable[oldPage].dirty){
		OpenFile *executable = fileSystem->Open(filename);
		if (executable == NULL) {
			printf("Unable to open file %s\n", filename);
				return;
		}
		executable->WriteAt(&(machine->mainMemory[pageTable[oldPage].physicalPage]),PageSize,oldPage*PageSize);
		delete executable;
	}
}

Then add several necessary member variables to the AddrSpace class

//lab-7 add by lhw************************
	unsigned int StackPages;
	char *filename;		
	//for FIFO
	int virtualMem[MaxNumPhysPages]; //FIFO page sequential storage
	int p_vm; //FIFO swap out page pointer
//lab-7 add by lhw************************

Modify the constructor of AddrSpace

//lab-7 modify by lhw*****************************
AddrSpace::AddrSpace(char *filename)
{
//lab-6 add by lhw***************************
//During initialization, traverse to find the unallocated spaceID, and then allocate the spaceID
    bool flag = false;
    for(int i = 0; i < 128; i++)
    {
        if(!ThreadMap[i]){
            ThreadMap[i] = 1;
            flag = true;
            spaceID=i;
            break;
        }
    }
    ASSERT(flag);
//lab-6 add by lhw*************************

//lab-7 add by lhw*************************
    OpenFile *executable = fileSystem->Open(filename);

    if (executable == NULL) {
		printf("Unable to open file %s\n", filename);
		return;
    }
    this->filename=filename;
//lab-7 add by lhw**************************

    NoffHeader noffH;
    unsigned int i, size;

    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?
//lab-7 add by lhw***************************
	StackPages = divRoundUp(UserStackSize,PageSize);
	numPages = divRoundUp(noffH.code.size,PageSize) + divRoundUp
			(noffH.initData.size,PageSize) + divRoundUp(noffH.uninitData.size,PageSize)+ StackPages;
	size = (MaxNumPhysPages+StackPages)*PageSize;
	printf( "numPages = %d \n" ,numPages );
//lab-7 add by lhw***************************

//lab-6 add by lhw***************************
	//Check the required space size
    ASSERT(numPages <= NumPhysPages && numPages <= bitmap->NumClear());	
//lab-6 add by lhw***************************

    DEBUG('a', "Initializing address space, num pages %d, size %d\n", 
					numPages, size);
// first, set up the translation 
//lab-7 add by lhw*************************
	initPageTable();
//lab-7 add by lhw*************************
	
// zero out the entire address space, to zero the unitialized data segment 
// and the stack segment
//lab-6 add by lhw*************************
    //bzero(machine->mainMemory, size);
//lab-6 add by lhw*************************

// then, copy in the code and data segments into memory
    if (noffH.code.size > 0) {
        DEBUG('a', "Initializing code segment, at 0x%x, size %d\n", 
            noffH.code.virtualAddr, noffH.code.size);
			
    int code_page = noffH.code.virtualAddr/PageSize;
    int code_phy_addr = pageTable[code_page].physicalPage *PageSize;
        executable->ReadAt(&(machine->mainMemory[code_phy_addr]),
            noffH.code.size, noffH.code.inFileAddr);
    }
	
    if (noffH.initData.size > 0) {
        DEBUG('a', "Initializing data segment, at 0x%x, size %d\n", 
            noffH.initData.virtualAddr, noffH.initData.size);		
    int data_page = noffH.initData.virtualAddr/PageSize;
    int data_offset = noffH.initData.virtualAddr%PageSize;
    int data_phy_addr = pageTable[data_page].physicalPage *PageSize + data_offset;
        executable->ReadAt(&(machine->mainMemory[data_phy_addr]),
            noffH.initData.size, noffH.initData.inFileAddr);
    }
//lab-7 add by lhw**********************
    delete executable;
//lab-7 add by lhw**********************
    Print();
}

The AddrSpace::AddrSpace() constructor parameter is changed from executable to char* filename, so the StartProgress and Exec system calls should be changed accordingly

progtest.cc:

interrupt.cc:

Then, in AddrSpace::AddrSpace(), the initPageTable() function is called to initialize the page table, followed by addrspace.. H definition

void initPageTable(); //Page table initialization

In addrspace Implementation in CC

void
AddrSpace::initPageTable(){
	int i=0;
	int numFrames =MaxNumPhysPages;
	p_vm = 0;
	
    pageTable = new TranslationEntry[numPages];

	for (i=0;i<numFrames;i++){
			pageTable[i].virtualPage = i;
			pageTable[i].physicalPage = bitmap->Find();
			pageTable[i].valid = true;
			pageTable[i].use = false;
			pageTable[i].dirty = false;
			pageTable[i].readOnly = false; 
			virtualMem[p_vm] = pageTable[i].virtualPage;
			p_vm = (p_vm+1)%MaxNumPhysPages; //Move forward one bit
		
	}
	
	for(i;i<numPages;i++){
		    pageTable[i].virtualPage = i;
			pageTable[i].physicalPage = -1;
			pageTable[i].valid = false;
	}
}

Then modify the destructor of AddrSpace to increase the judgment of significant bits

Finally, modify the Print function to facilitate testing. The output of valid, dirty and use is added.

//lab-7 modify by lhw********************
void
AddrSpace::Print() 
{ 
	printf("spaceID: %d\n",spaceID);
	printf("page table dump: %d pages in total\n", numPages); 
	printf("============================================\n"); 
	printf(" VirtPage, PhysPage, valid, dirty, use \n"); 
	for (int i=0; i < numPages; i++) { 
	printf("\t%d,\t%d,\t%d,\t%d,\t%d\n", pageTable[i].virtualPage,pageTable[i].physicalPage,pageTable[i].valid,pageTable[i].dirty,pageTable[i].use); 
	} 
	printf("============================================\n\n"); 
}
//lab-7 modify by lhw**********************

3. Testing

You can use code / test / sort, which consumes a lot of user memory C as a user test program of virtual memory. But we need to change two places. First, the value 1024 originally defined by ARRAYSIZE is too large, so that the program changes pages frequently, resulting in too strong output screen brushing, so it needs to be reduced here. Second, the last Exit system call has not been implemented, so it can be simply changed to Halt system call temporarily.

After compiling make in the test and lab7 directories respectively, execute sort in the lab7 directory Noff, observe the screen output

Output results:

Topics: Operating System