Ytshih/hw2
This commit is contained in:
@@ -31,32 +31,97 @@
|
||||
static void
|
||||
SwapHeader (NoffHeader *noffH)
|
||||
{
|
||||
noffH->noffMagic = WordToHost(noffH->noffMagic);
|
||||
noffH->code.size = WordToHost(noffH->code.size);
|
||||
noffH->code.virtualAddr = WordToHost(noffH->code.virtualAddr);
|
||||
noffH->code.inFileAddr = WordToHost(noffH->code.inFileAddr);
|
||||
noffH->noffMagic = WordToHost(noffH->noffMagic);
|
||||
noffH->code.size = WordToHost(noffH->code.size);
|
||||
noffH->code.virtualAddr = WordToHost(noffH->code.virtualAddr);
|
||||
noffH->code.inFileAddr = WordToHost(noffH->code.inFileAddr);
|
||||
#ifdef RDATA
|
||||
noffH->readonlyData.size = WordToHost(noffH->readonlyData.size);
|
||||
noffH->readonlyData.virtualAddr =
|
||||
WordToHost(noffH->readonlyData.virtualAddr);
|
||||
noffH->readonlyData.inFileAddr =
|
||||
WordToHost(noffH->readonlyData.inFileAddr);
|
||||
noffH->readonlyData.size = WordToHost(noffH->readonlyData.size);
|
||||
noffH->readonlyData.virtualAddr =
|
||||
WordToHost(noffH->readonlyData.virtualAddr);
|
||||
noffH->readonlyData.inFileAddr =
|
||||
WordToHost(noffH->readonlyData.inFileAddr);
|
||||
#endif
|
||||
noffH->initData.size = WordToHost(noffH->initData.size);
|
||||
noffH->initData.virtualAddr = WordToHost(noffH->initData.virtualAddr);
|
||||
noffH->initData.inFileAddr = WordToHost(noffH->initData.inFileAddr);
|
||||
noffH->uninitData.size = WordToHost(noffH->uninitData.size);
|
||||
noffH->uninitData.virtualAddr = WordToHost(noffH->uninitData.virtualAddr);
|
||||
noffH->uninitData.inFileAddr = WordToHost(noffH->uninitData.inFileAddr);
|
||||
noffH->initData.size = WordToHost(noffH->initData.size);
|
||||
noffH->initData.virtualAddr = WordToHost(noffH->initData.virtualAddr);
|
||||
noffH->initData.inFileAddr = WordToHost(noffH->initData.inFileAddr);
|
||||
noffH->uninitData.size = WordToHost(noffH->uninitData.size);
|
||||
noffH->uninitData.virtualAddr = WordToHost(noffH->uninitData.virtualAddr);
|
||||
noffH->uninitData.inFileAddr = WordToHost(noffH->uninitData.inFileAddr);
|
||||
|
||||
#ifdef RDATA
|
||||
DEBUG(dbgAddr, "code = " << noffH->code.size <<
|
||||
" readonly = " << noffH->readonlyData.size <<
|
||||
" init = " << noffH->initData.size <<
|
||||
" uninit = " << noffH->uninitData.size << "\n");
|
||||
DEBUG(dbgAddr, "code = " << noffH->code.size <<
|
||||
" readonly = " << noffH->readonlyData.size <<
|
||||
" init = " << noffH->initData.size <<
|
||||
" uninit = " << noffH->uninitData.size << "\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
FrameTable::Node::Node(int idx):
|
||||
next(nullptr), idx(idx) {}
|
||||
|
||||
FrameTable::FrameTable()
|
||||
{
|
||||
available = NumPhysPages;
|
||||
useCount = new int[NumPhysPages];
|
||||
begin = end = new FrameTable::Node;
|
||||
for (int i = 0; i < NumPhysPages; i++) {
|
||||
useCount[i] = 0;
|
||||
end->idx = i;
|
||||
end->next = new FrameTable::Node;
|
||||
end = end->next;
|
||||
}
|
||||
}
|
||||
|
||||
FrameTable::~FrameTable()
|
||||
{
|
||||
delete[] useCount;
|
||||
while (begin != end) {
|
||||
FrameTable::Node *tmpNode = begin;
|
||||
begin = begin->next;
|
||||
delete tmpNode;
|
||||
}
|
||||
delete begin;
|
||||
}
|
||||
|
||||
int FrameTable::Allocate()
|
||||
{
|
||||
if (available == 0)
|
||||
return -1;
|
||||
|
||||
int ret = begin->idx;
|
||||
Node *tmp = begin;
|
||||
begin = begin->next;
|
||||
delete tmp;
|
||||
|
||||
--available;
|
||||
useCount[ret]++;
|
||||
|
||||
bzero(kernel->machine->mainMemory + ret * PageSize, PageSize);
|
||||
|
||||
//cerr << "Allocated at page: " << ret << endl;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void FrameTable::Release(int phyPageNum)
|
||||
{
|
||||
useCount[phyPageNum]--;
|
||||
|
||||
if (useCount[phyPageNum] > 0)
|
||||
return;
|
||||
|
||||
++available;
|
||||
|
||||
//cerr << "Release page: " << end->idx << endl;
|
||||
end->idx = phyPageNum;
|
||||
end->next = new FrameTable::Node;
|
||||
}
|
||||
|
||||
size_t FrameTable::RemainSize()
|
||||
{
|
||||
return available;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// AddrSpace::AddrSpace
|
||||
// Create an address space to run a user program.
|
||||
@@ -66,20 +131,7 @@ SwapHeader (NoffHeader *noffH)
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
AddrSpace::AddrSpace()
|
||||
{
|
||||
pageTable = new TranslationEntry[NumPhysPages];
|
||||
for (int i = 0; i < NumPhysPages; i++) {
|
||||
pageTable[i].virtualPage = i; // for now, virt page # = phys page #
|
||||
pageTable[i].physicalPage = i;
|
||||
pageTable[i].valid = TRUE;
|
||||
pageTable[i].use = FALSE;
|
||||
pageTable[i].dirty = FALSE;
|
||||
pageTable[i].readOnly = FALSE;
|
||||
}
|
||||
|
||||
// zero out the entire address space
|
||||
bzero(kernel->machine->mainMemory, MemorySize);
|
||||
}
|
||||
{}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// AddrSpace::~AddrSpace
|
||||
@@ -88,7 +140,10 @@ AddrSpace::AddrSpace()
|
||||
|
||||
AddrSpace::~AddrSpace()
|
||||
{
|
||||
delete pageTable;
|
||||
for (int i = 0; i < NumPhysPages; i++)
|
||||
if (pageTable[i].use == TRUE)
|
||||
kernel->frameTable->Release(pageTable[i].physicalPage);
|
||||
delete[] pageTable;
|
||||
}
|
||||
|
||||
|
||||
@@ -105,72 +160,110 @@ AddrSpace::~AddrSpace()
|
||||
bool
|
||||
AddrSpace::Load(char *fileName)
|
||||
{
|
||||
OpenFile *executable = kernel->fileSystem->Open(fileName);
|
||||
NoffHeader noffH;
|
||||
unsigned int size;
|
||||
//cerr << "AddrSpace::Load" << endl;
|
||||
OpenFile *executable = kernel->fileSystem->Open(fileName);
|
||||
NoffHeader noffH;
|
||||
unsigned int size;
|
||||
|
||||
if (executable == NULL) {
|
||||
cerr << "Unable to open file " << fileName << "\n";
|
||||
return FALSE;
|
||||
}
|
||||
if (executable == NULL) {
|
||||
cerr << "Unable to open file " << fileName << "\n";
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
executable->ReadAt((char *)&noffH, sizeof(noffH), 0);
|
||||
if ((noffH.noffMagic != NOFFMAGIC) &&
|
||||
(WordToHost(noffH.noffMagic) == NOFFMAGIC))
|
||||
SwapHeader(&noffH);
|
||||
ASSERT(noffH.noffMagic == NOFFMAGIC);
|
||||
executable->ReadAt((char *)&noffH, sizeof(noffH), 0);
|
||||
if ((noffH.noffMagic != NOFFMAGIC) &&
|
||||
(WordToHost(noffH.noffMagic) == NOFFMAGIC))
|
||||
SwapHeader(&noffH);
|
||||
ASSERT(noffH.noffMagic == NOFFMAGIC);
|
||||
|
||||
#ifdef RDATA
|
||||
// how big is address space?
|
||||
size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size +
|
||||
noffH.uninitData.size + UserStackSize;
|
||||
// we need to increase the size
|
||||
// to leave room for the stack
|
||||
size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size +
|
||||
noffH.uninitData.size + UserStackSize;
|
||||
//cerr << noffH.code.size << ' '
|
||||
// << noffH.readonlyData.size << ' '
|
||||
// << noffH.initData.size << ' '
|
||||
// << noffH.uninitData.size << ' '
|
||||
// << UserStackSize << endl;
|
||||
// we need to increase the size
|
||||
// to leave room for the stack
|
||||
#else
|
||||
// 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
|
||||
size = noffH.code.size + noffH.initData.size + noffH.uninitData.size
|
||||
+ UserStackSize; // we need to increase the size
|
||||
// to leave room for the stack
|
||||
//cerr << noffH.code.size << ' '
|
||||
// << noffH.initData.size << ' '
|
||||
// << noffH.uninitData.size << ' '
|
||||
// << UserStackSize << endl;
|
||||
#endif
|
||||
numPages = divRoundUp(size, PageSize);
|
||||
size = numPages * PageSize;
|
||||
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
|
||||
ASSERT(numPages <= NumPhysPages); // check we're not trying
|
||||
// to run anything too big --
|
||||
// at least until we have
|
||||
// virtual memory
|
||||
|
||||
pageTable = new TranslationEntry[numPages];
|
||||
for (int i = 0; i < numPages; i++) {
|
||||
pageTable[i].virtualPage = i;
|
||||
pageTable[i].physicalPage = -1;
|
||||
pageTable[i].valid = TRUE;
|
||||
pageTable[i].use = FALSE;
|
||||
pageTable[i].dirty = FALSE;
|
||||
pageTable[i].readOnly = FALSE;
|
||||
}
|
||||
|
||||
DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size);
|
||||
DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size);
|
||||
|
||||
// then, copy in the code and data segments into memory
|
||||
// Note: this code assumes that virtual address = physical address
|
||||
if (noffH.code.size > 0) {
|
||||
DEBUG(dbgAddr, "Initializing code segment.");
|
||||
DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size);
|
||||
executable->ReadAt(
|
||||
&(kernel->machine->mainMemory[noffH.code.virtualAddr]),
|
||||
noffH.code.size, noffH.code.inFileAddr);
|
||||
if (noffH.code.size > 0) {
|
||||
DEBUG(dbgAddr, "Initializing code segment.");
|
||||
DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size);
|
||||
|
||||
for (size_t cur = 0; cur < (size_t)noffH.code.size; cur += PageSize) {
|
||||
size_t physAddr, size = min((size_t)PageSize, noffH.code.size - cur);
|
||||
Translate(noffH.code.virtualAddr + cur, &physAddr, 1);
|
||||
//cerr << "physAddr, size: " << physAddr << ' ' << size << endl;
|
||||
|
||||
executable->ReadAt(
|
||||
&(kernel->machine->mainMemory[physAddr]), size,
|
||||
noffH.code.inFileAddr + cur);
|
||||
}
|
||||
if (noffH.initData.size > 0) {
|
||||
DEBUG(dbgAddr, "Initializing data segment.");
|
||||
DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size);
|
||||
executable->ReadAt(
|
||||
&(kernel->machine->mainMemory[noffH.initData.virtualAddr]),
|
||||
noffH.initData.size, noffH.initData.inFileAddr);
|
||||
}
|
||||
if (noffH.initData.size > 0) {
|
||||
DEBUG(dbgAddr, "Initializing data segment.");
|
||||
DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size);
|
||||
|
||||
for (size_t cur = 0; cur < (size_t)noffH.initData.size; cur += PageSize) {
|
||||
size_t physAddr, size = min((size_t)PageSize, noffH.initData.size - cur);
|
||||
Translate(noffH.initData.virtualAddr + cur, &physAddr, 1);
|
||||
|
||||
executable->ReadAt(
|
||||
&(kernel->machine->mainMemory[physAddr]), size,
|
||||
noffH.initData.inFileAddr + cur);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RDATA
|
||||
if (noffH.readonlyData.size > 0) {
|
||||
DEBUG(dbgAddr, "Initializing read only data segment.");
|
||||
DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size);
|
||||
executable->ReadAt(
|
||||
&(kernel->machine->mainMemory[noffH.readonlyData.virtualAddr]),
|
||||
noffH.readonlyData.size, noffH.readonlyData.inFileAddr);
|
||||
if (noffH.readonlyData.size > 0) {
|
||||
DEBUG(dbgAddr, "Initializing read only data segment.");
|
||||
DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size);
|
||||
|
||||
for (size_t cur = 0; cur < (size_t)noffH.readonlyData.size; cur += PageSize) {
|
||||
size_t physAddr, size = min((size_t)PageSize, noffH.readonlyData.size - cur);
|
||||
Translate(noffH.readonlyData.virtualAddr + cur, &physAddr, 1);
|
||||
|
||||
executable->ReadAt(
|
||||
&(kernel->machine->mainMemory[physAddr]),
|
||||
size, noffH.readonlyData.inFileAddr + cur);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
delete executable; // close file
|
||||
return TRUE; // success
|
||||
delete executable; // close file
|
||||
return TRUE; // success
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -185,17 +278,17 @@ AddrSpace::Load(char *fileName)
|
||||
void
|
||||
AddrSpace::Execute(char* fileName)
|
||||
{
|
||||
//cerr << "AddrSpace::Execute" << endl;
|
||||
kernel->currentThread->space = this;
|
||||
|
||||
kernel->currentThread->space = this;
|
||||
this->InitRegisters(); // set the initial register values
|
||||
this->RestoreState(); // load page table register
|
||||
|
||||
this->InitRegisters(); // set the initial register values
|
||||
this->RestoreState(); // load page table register
|
||||
kernel->machine->Run(); // jump to the user progam
|
||||
|
||||
kernel->machine->Run(); // jump to the user progam
|
||||
|
||||
ASSERTNOTREACHED(); // machine->Run never returns;
|
||||
// the address space exits
|
||||
// by doing the syscall "exit"
|
||||
ASSERTNOTREACHED(); // machine->Run never returns;
|
||||
// the address space exits
|
||||
// by doing the syscall "exit"
|
||||
}
|
||||
|
||||
|
||||
@@ -212,27 +305,27 @@ AddrSpace::Execute(char* fileName)
|
||||
void
|
||||
AddrSpace::InitRegisters()
|
||||
{
|
||||
Machine *machine = kernel->machine;
|
||||
int i;
|
||||
Machine *machine = kernel->machine;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NumTotalRegs; i++)
|
||||
machine->WriteRegister(i, 0);
|
||||
for (i = 0; i < NumTotalRegs; i++)
|
||||
machine->WriteRegister(i, 0);
|
||||
|
||||
// Initial program counter -- must be location of "Start", which
|
||||
// is assumed to be virtual address zero
|
||||
machine->WriteRegister(PCReg, 0);
|
||||
// Initial program counter -- must be location of "Start", which
|
||||
// is assumed to be virtual address zero
|
||||
machine->WriteRegister(PCReg, 0);
|
||||
|
||||
// Need to also tell MIPS where next instruction is, because
|
||||
// of branch delay possibility
|
||||
// Since instructions occupy four bytes each, the next instruction
|
||||
// after start will be at virtual address four.
|
||||
machine->WriteRegister(NextPCReg, 4);
|
||||
// Need to also tell MIPS where next instruction is, because
|
||||
// of branch delay possibility
|
||||
// Since instructions occupy four bytes each, the next instruction
|
||||
// after start will be at virtual address four.
|
||||
machine->WriteRegister(NextPCReg, 4);
|
||||
|
||||
// Set the stack register to the end of the address space, where we
|
||||
// allocated the stack; but subtract off a bit, to make sure we don't
|
||||
// accidentally reference off the end!
|
||||
machine->WriteRegister(StackReg, numPages * PageSize - 16);
|
||||
DEBUG(dbgAddr, "Initializing stack pointer: " << numPages * PageSize - 16);
|
||||
// Set the stack register to the end of the address space, where we
|
||||
// allocated the stack; but subtract off a bit, to make sure we don't
|
||||
// accidentally reference off the end!
|
||||
machine->WriteRegister(StackReg, numPages * PageSize - 16);
|
||||
DEBUG(dbgAddr, "Initializing stack pointer: " << numPages * PageSize - 16);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -256,8 +349,8 @@ void AddrSpace::SaveState()
|
||||
|
||||
void AddrSpace::RestoreState()
|
||||
{
|
||||
kernel->machine->pageTable = pageTable;
|
||||
kernel->machine->pageTableSize = numPages;
|
||||
kernel->machine->pageTable = pageTable;
|
||||
kernel->machine->pageTableSize = numPages;
|
||||
}
|
||||
|
||||
|
||||
@@ -272,45 +365,48 @@ void AddrSpace::RestoreState()
|
||||
ExceptionType
|
||||
AddrSpace::Translate(unsigned int vaddr, unsigned int *paddr, int isReadWrite)
|
||||
{
|
||||
TranslationEntry *pte;
|
||||
int pfn;
|
||||
unsigned int vpn = vaddr / PageSize;
|
||||
unsigned int offset = vaddr % PageSize;
|
||||
TranslationEntry *pte;
|
||||
int pfn;
|
||||
unsigned int vpn = vaddr / PageSize;
|
||||
unsigned int offset = vaddr % PageSize;
|
||||
|
||||
if(vpn >= numPages) {
|
||||
return AddressErrorException;
|
||||
if(vpn >= numPages) {
|
||||
return AddressErrorException;
|
||||
}
|
||||
|
||||
pte = &pageTable[vpn];
|
||||
|
||||
if(isReadWrite && pte->readOnly) {
|
||||
return ReadOnlyException;
|
||||
}
|
||||
|
||||
pfn = pte->physicalPage;
|
||||
if (pfn == -1) {
|
||||
pfn = pte->physicalPage = kernel->frameTable->Allocate();
|
||||
if (pfn == -1) {
|
||||
DEBUG(dbgAddr, "Memory Limit exceeded");
|
||||
return MemoryLimitException;
|
||||
}
|
||||
}
|
||||
|
||||
pte = &pageTable[vpn];
|
||||
// if the pageFrame is too big, there is something really wrong!
|
||||
// An invalid translation was loaded into the page table or TLB.
|
||||
if (pfn >= NumPhysPages) {
|
||||
DEBUG(dbgAddr, "Illegal physical page " << pfn);
|
||||
return BusErrorException;
|
||||
}
|
||||
|
||||
if(isReadWrite && pte->readOnly) {
|
||||
return ReadOnlyException;
|
||||
}
|
||||
pte->use = TRUE; // set the use, dirty bits
|
||||
|
||||
pfn = pte->physicalPage;
|
||||
if(isReadWrite)
|
||||
pte->dirty = TRUE;
|
||||
|
||||
// if the pageFrame is too big, there is something really wrong!
|
||||
// An invalid translation was loaded into the page table or TLB.
|
||||
if (pfn >= NumPhysPages) {
|
||||
DEBUG(dbgAddr, "Illegal physical page " << pfn);
|
||||
return BusErrorException;
|
||||
}
|
||||
*paddr = pfn * PageSize + offset;
|
||||
|
||||
pte->use = TRUE; // set the use, dirty bits
|
||||
ASSERT((*paddr < MemorySize));
|
||||
|
||||
if(isReadWrite)
|
||||
pte->dirty = TRUE;
|
||||
//cerr << " -- AddrSpace::Translate(): vaddr: " << vaddr <<
|
||||
// ", paddr: " << *paddr << "\n";
|
||||
|
||||
*paddr = pfn*PageSize + offset;
|
||||
|
||||
ASSERT((*paddr < MemorySize));
|
||||
|
||||
//cerr << " -- AddrSpace::Translate(): vaddr: " << vaddr <<
|
||||
// ", paddr: " << *paddr << "\n";
|
||||
|
||||
return NoException;
|
||||
return NoException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user