Bug description:
When nachos is executing two different executable files, the result will be weird.
The following is picture is how the bug looks like.
Finding the Bug:
Now I know what the bug looks like, It's time to find out what cause the bug.
Since our TA have told us that the bug may be in the ./userprog/addrspace.h and ./userprog/addrspace.cc, my team mate and I start to understand what this two files are doing.
1. AddrSpace::Load(), which will load the image into the physical addrspace.
2. AddrSpace::AddrSpace, which is the constructor of this class, and will create the page table of this process.
In the source code of AddrSpace::Load()
these code is to load the .text and .data into the physical memory
if (noffH.code.size > 0) {
executable->ReadAt(&(kernel->machine->mainMemory[noffH.code.virtualAddr]),noffH.code.size, noffH.code.inFileAddr);
}
if (noffH.initData.size > 0) {
executable->ReadAt(&(kernel->machine->mainMemory[noffH.initData.virtualAddr]),noffH.initData.size, noffH.initData.inFileAddr);
}
The allocating process will allocate the virtual address space into the physical address space.
However as the red highlight suggest, the physical address of the process is exactly the same as the virtual address of the process.
If the second process is allocate into the memory, it will overwrite the previous process. Hence, when the previous process restore the state, it will execute the code of another process, not the one belongs to it.
Here, we may find our problem.
But not so fast, before we modified the code and fixed the bug, there is one thing that we need to be aware.Nachos is using paging to map the virtual address to physical address. Therefore, when we modified the allocating part, we also need to modified the paging (page tables).The mapping of the page table is in the constructor. As the code suggest, the page table is one to one linear mapping. Therefore, if another process is load into the memory, and the process 1 restore the state. The page table of process 1 will tell that the physical address space of process1 in in the old place where it has already been overwritten by process 2.
Fixed the bug:
Now we have the information we need. It's time to modified the code and fix the bug.
The method of our team is to add a static unsigned int variable which will record how many physical frame is being used, and when process 2 is load into the memory, it will not overwritten the address space of process 1.
1. first add a static unsigned int variable in the addrspace.h
addrspace.h
class AddrSpace {
public:
.....
private:
TranslationEntry *pageTable;
unsigned int numPages;
static unsigned int usedPhys;
bool Load(char *fileName);
void InitRegisters();
};
2. initialize the static variable in the addrspace.cc
#include "addrspace.h"
unsigned int AddrSpace::usedPhys=0;
3. modified the AddrSpace::Load()
executable->ReadAt(
&(kernel->machine->mainMemory[noffH.code.virtualAddr+128*usedPhys]),noffH.code.size, noffH.code.inFileAddr);
P.S
why usedPhys multiply 128 before adding to the virtualAddr?
The reason is simple, cuz the usedPhys is the page frame which is being used, not the physical memory.
Therefore, when we are adding the usedPhys we also need to multiply the page size of the page frame, which is 128 byte per page.
4.remapping the page table
for (unsigned int i = 0; i < numPages; i++) {
pageTable[i].virtualPage = i;
pageTable[i].physicalPage = i+usedPhys;
}
P.S
the numPages is the number of the page frame the current process is using.
there is no need to map the whole page again, just those the process is using.
5. record the usedPhys
usedPhys += numPages;
P.S
after those steps, adding the numPages to the usedPhys. Therefore, when the process 2 is loading it will not overwritten the address space of process 1.
6. the last steps is to compile the source code again and test the result.
Result:
No comments:
Post a Comment