Ytshih/hw2
This commit is contained in:
@@ -181,4 +181,4 @@ ConsoleOutput::PutInt(int value)
|
||||
WriteFile(writeFileNo, printStr, strlen(printStr)*sizeof(char));
|
||||
putBusy = TRUE;
|
||||
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "copyright.h"
|
||||
#include "interrupt.h"
|
||||
#include "main.h"
|
||||
#include "synchconsole.h"
|
||||
|
||||
// String definitions for debugging messages
|
||||
|
||||
@@ -340,7 +341,7 @@ static void
|
||||
PrintPending (PendingInterrupt *pending)
|
||||
{
|
||||
cout << "Interrupt handler "<< intTypeNames[pending->type];
|
||||
cout << ", scheduled at " << pending->when;
|
||||
cout << ", scheduled at " << pending->when << endl;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -362,5 +363,5 @@ Interrupt::DumpState()
|
||||
void
|
||||
Interrupt::PrintInt(int value)
|
||||
{
|
||||
return kernel->PrintInt(value);
|
||||
}
|
||||
kernel->synchConsoleOut->PutInt(value);
|
||||
}
|
||||
|
||||
@@ -13,10 +13,17 @@
|
||||
|
||||
// Textual names of the exceptions that can be generated by user program
|
||||
// execution, for debugging.
|
||||
static char* exceptionNames[] = { "no exception", "syscall",
|
||||
"page fault/no TLB entry", "page read only",
|
||||
"bus error", "address error", "overflow",
|
||||
"illegal instruction" };
|
||||
static char* exceptionNames[] = {
|
||||
"no exception",
|
||||
"syscall",
|
||||
"page fault/no TLB entry",
|
||||
"page read only",
|
||||
"bus error",
|
||||
"address error",
|
||||
"overflow",
|
||||
"illegal instruction",
|
||||
"bad memory allocation"
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// CheckEndian
|
||||
|
||||
@@ -28,32 +28,34 @@
|
||||
// Definitions related to the size, and format of user memory
|
||||
|
||||
const int PageSize = 128; // set the page size equal to
|
||||
// the disk sector size, for simplicity
|
||||
// the disk sector size, for simplicity
|
||||
|
||||
//
|
||||
// You are allowed to change this value.
|
||||
// Doing so will change the number of pages of physical memory
|
||||
// available on the simulated machine.
|
||||
//
|
||||
//
|
||||
// You are allowed to change this value.
|
||||
// Doing so will change the number of pages of physical memory
|
||||
// available on the simulated machine.
|
||||
//
|
||||
const int NumPhysPages = 128;
|
||||
|
||||
const int MemorySize = (NumPhysPages * PageSize);
|
||||
const int TLBSize = 4; // if there is a TLB, make it small
|
||||
|
||||
enum ExceptionType { NoException, // Everything ok!
|
||||
SyscallException, // A program executed a system call.
|
||||
PageFaultException, // No valid translation found
|
||||
ReadOnlyException, // Write attempted to page marked
|
||||
// "read-only"
|
||||
BusErrorException, // Translation resulted in an
|
||||
// invalid physical address
|
||||
AddressErrorException, // Unaligned reference or one that
|
||||
// was beyond the end of the
|
||||
// address space
|
||||
OverflowException, // Integer overflow in add or sub.
|
||||
IllegalInstrException, // Unimplemented or reserved instr.
|
||||
|
||||
NumExceptionTypes
|
||||
enum ExceptionType {
|
||||
NoException, // Everything ok!
|
||||
SyscallException, // A program executed a system call.
|
||||
PageFaultException, // No valid translation found
|
||||
ReadOnlyException, // Write attempted to page marked
|
||||
// "read-only"
|
||||
BusErrorException, // Translation resulted in an
|
||||
// invalid physical address
|
||||
AddressErrorException, // Unaligned reference or one that
|
||||
// was beyond the end of the
|
||||
// address space
|
||||
OverflowException, // Integer overflow in add or sub.
|
||||
IllegalInstrException, // Unimplemented or reserved instr.
|
||||
MemoryLimitException, // Bad allocation
|
||||
|
||||
NumExceptionTypes
|
||||
};
|
||||
|
||||
// User program CPU state. The full set of MIPS registers, plus a few
|
||||
@@ -94,97 +96,97 @@ class Interrupt;
|
||||
class Machine {
|
||||
public:
|
||||
Machine(bool debug); // Initialize the simulation of the hardware
|
||||
// for running user programs
|
||||
// for running user programs
|
||||
~Machine(); // De-allocate the data structures
|
||||
|
||||
// Routines callable by the Nachos kernel
|
||||
// Routines callable by the Nachos kernel
|
||||
void Run(); // Run a user program
|
||||
|
||||
int ReadRegister(int num); // read the contents of a CPU register
|
||||
|
||||
void WriteRegister(int num, int value);
|
||||
// store a value into a CPU register
|
||||
// store a value into a CPU register
|
||||
|
||||
// Data structures accessible to the Nachos kernel -- main memory and the
|
||||
// page table/TLB.
|
||||
//
|
||||
// Note that *all* communication between the user program and the kernel
|
||||
// are in terms of these data structures (plus the CPU registers).
|
||||
// Data structures accessible to the Nachos kernel -- main memory and the
|
||||
// page table/TLB.
|
||||
//
|
||||
// Note that *all* communication between the user program and the kernel
|
||||
// are in terms of these data structures (plus the CPU registers).
|
||||
|
||||
char *mainMemory; // physical memory to store user program,
|
||||
// code and data, while executing
|
||||
// code and data, while executing
|
||||
|
||||
// NOTE: the hardware translation of virtual addresses in the user program
|
||||
// to physical addresses (relative to the beginning of "mainMemory")
|
||||
// can be controlled by one of:
|
||||
// a traditional linear page table
|
||||
// a software-loaded translation lookaside buffer (tlb) -- a cache of
|
||||
// mappings of virtual page #'s to physical page #'s
|
||||
//
|
||||
// If "tlb" is NULL, the linear page table is used
|
||||
// If "tlb" is non-NULL, the Nachos kernel is responsible for managing
|
||||
// the contents of the TLB. But the kernel can use any data structure
|
||||
// it wants (eg, segmented paging) for handling TLB cache misses.
|
||||
//
|
||||
// For simplicity, both the page table pointer and the TLB pointer are
|
||||
// public. However, while there can be multiple page tables (one per address
|
||||
// space, stored in memory), there is only one TLB (implemented in hardware).
|
||||
// Thus the TLB pointer should be considered as *read-only*, although
|
||||
// the contents of the TLB are free to be modified by the kernel software.
|
||||
// NOTE: the hardware translation of virtual addresses in the user program
|
||||
// to physical addresses (relative to the beginning of "mainMemory")
|
||||
// can be controlled by one of:
|
||||
// a traditional linear page table
|
||||
// a software-loaded translation lookaside buffer (tlb) -- a cache of
|
||||
// mappings of virtual page #'s to physical page #'s
|
||||
//
|
||||
// If "tlb" is NULL, the linear page table is used
|
||||
// If "tlb" is non-NULL, the Nachos kernel is responsible for managing
|
||||
// the contents of the TLB. But the kernel can use any data structure
|
||||
// it wants (eg, segmented paging) for handling TLB cache misses.
|
||||
//
|
||||
// For simplicity, both the page table pointer and the TLB pointer are
|
||||
// public. However, while there can be multiple page tables (one per address
|
||||
// space, stored in memory), there is only one TLB (implemented in hardware).
|
||||
// Thus the TLB pointer should be considered as *read-only*, although
|
||||
// the contents of the TLB are free to be modified by the kernel software.
|
||||
|
||||
TranslationEntry *tlb; // this pointer should be considered
|
||||
// "read-only" to Nachos kernel code
|
||||
// "read-only" to Nachos kernel code
|
||||
|
||||
TranslationEntry *pageTable;
|
||||
unsigned int pageTableSize;
|
||||
|
||||
bool ReadMem(int addr, int size, int* value);
|
||||
bool WriteMem(int addr, int size, int value);
|
||||
// Read or write 1, 2, or 4 bytes of virtual
|
||||
// memory (at addr). Return FALSE if a
|
||||
// correct translation couldn't be found.
|
||||
// Read or write 1, 2, or 4 bytes of virtual
|
||||
// memory (at addr). Return FALSE if a
|
||||
// correct translation couldn't be found.
|
||||
private:
|
||||
|
||||
// Routines internal to the machine simulation -- DO NOT call these directly
|
||||
// Routines internal to the machine simulation -- DO NOT call these directly
|
||||
void DelayedLoad(int nextReg, int nextVal);
|
||||
// Do a pending delayed load (modifying a reg)
|
||||
// Do a pending delayed load (modifying a reg)
|
||||
|
||||
void OneInstruction(Instruction *instr);
|
||||
// Run one instruction of a user program.
|
||||
|
||||
// Run one instruction of a user program.
|
||||
|
||||
|
||||
|
||||
ExceptionType Translate(int virtAddr, int* physAddr, int size,bool writing);
|
||||
// Translate an address, and check for
|
||||
// alignment. Set the use and dirty bits in
|
||||
// the translation entry appropriately,
|
||||
// and return an exception code if the
|
||||
// translation couldn't be completed.
|
||||
// Translate an address, and check for
|
||||
// alignment. Set the use and dirty bits in
|
||||
// the translation entry appropriately,
|
||||
// and return an exception code if the
|
||||
// translation couldn't be completed.
|
||||
|
||||
void RaiseException(ExceptionType which, int badVAddr);
|
||||
// Trap to the Nachos kernel, because of a
|
||||
// system call or other exception.
|
||||
// Trap to the Nachos kernel, because of a
|
||||
// system call or other exception.
|
||||
|
||||
void Debugger(); // invoke the user program debugger
|
||||
void DumpState(); // print the user CPU and memory state
|
||||
|
||||
|
||||
// Internal data structures
|
||||
// Internal data structures
|
||||
|
||||
int registers[NumTotalRegs]; // CPU registers, for executing user programs
|
||||
|
||||
bool singleStep; // drop back into the debugger after each
|
||||
// simulated instruction
|
||||
// simulated instruction
|
||||
int runUntilTime; // drop back into the debugger when simulated
|
||||
// time reaches this value
|
||||
// time reaches this value
|
||||
|
||||
friend class Interrupt; // calls DelayedLoad()
|
||||
};
|
||||
|
||||
extern void ExceptionHandler(ExceptionType which);
|
||||
// Entry point into Nachos for handling
|
||||
// user system calls and exceptions
|
||||
// Defined in exception.cc
|
||||
// Entry point into Nachos for handling
|
||||
// user system calls and exceptions
|
||||
// Defined in exception.cc
|
||||
|
||||
|
||||
// Routines for converting Words and Short Words to and from the
|
||||
|
||||
@@ -85,38 +85,38 @@ ShortToMachine(unsigned short shortword) { return ShortToHost(shortword); }
|
||||
bool
|
||||
Machine::ReadMem(int addr, int size, int *value)
|
||||
{
|
||||
int data;
|
||||
ExceptionType exception;
|
||||
int physicalAddress;
|
||||
|
||||
DEBUG(dbgAddr, "Reading VA " << addr << ", size " << size);
|
||||
|
||||
exception = Translate(addr, &physicalAddress, size, FALSE);
|
||||
if (exception != NoException) {
|
||||
RaiseException(exception, addr);
|
||||
return FALSE;
|
||||
}
|
||||
switch (size) {
|
||||
case 1:
|
||||
data = mainMemory[physicalAddress];
|
||||
*value = data;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
data = *(unsigned short *) &mainMemory[physicalAddress];
|
||||
*value = ShortToHost(data);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
data = *(unsigned int *) &mainMemory[physicalAddress];
|
||||
*value = WordToHost(data);
|
||||
break;
|
||||
int data;
|
||||
ExceptionType exception;
|
||||
int physicalAddress;
|
||||
|
||||
default: ASSERT(FALSE);
|
||||
}
|
||||
|
||||
DEBUG(dbgAddr, "\tvalue read = " << *value);
|
||||
return (TRUE);
|
||||
DEBUG(dbgAddr, "Reading VA " << addr << ", size " << size);
|
||||
|
||||
exception = Translate(addr, &physicalAddress, size, FALSE);
|
||||
if (exception != NoException) {
|
||||
RaiseException(exception, addr);
|
||||
return FALSE;
|
||||
}
|
||||
switch (size) {
|
||||
case 1:
|
||||
data = mainMemory[physicalAddress];
|
||||
*value = data;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
data = *(unsigned short *) &mainMemory[physicalAddress];
|
||||
*value = ShortToHost(data);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
data = *(unsigned int *) &mainMemory[physicalAddress];
|
||||
*value = WordToHost(data);
|
||||
break;
|
||||
|
||||
default: ASSERT(FALSE);
|
||||
}
|
||||
|
||||
DEBUG(dbgAddr, "\tvalue read = " << *value);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -135,35 +135,35 @@ Machine::ReadMem(int addr, int size, int *value)
|
||||
bool
|
||||
Machine::WriteMem(int addr, int size, int value)
|
||||
{
|
||||
ExceptionType exception;
|
||||
int physicalAddress;
|
||||
|
||||
DEBUG(dbgAddr, "Writing VA " << addr << ", size " << size << ", value " << value);
|
||||
ExceptionType exception;
|
||||
int physicalAddress;
|
||||
|
||||
exception = Translate(addr, &physicalAddress, size, TRUE);
|
||||
if (exception != NoException) {
|
||||
RaiseException(exception, addr);
|
||||
return FALSE;
|
||||
}
|
||||
switch (size) {
|
||||
case 1:
|
||||
mainMemory[physicalAddress] = (unsigned char) (value & 0xff);
|
||||
break;
|
||||
DEBUG(dbgAddr, "Writing VA " << addr << ", size " << size << ", value " << value);
|
||||
|
||||
case 2:
|
||||
*(unsigned short *) &mainMemory[physicalAddress]
|
||||
= ShortToMachine((unsigned short) (value & 0xffff));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
*(unsigned int *) &mainMemory[physicalAddress]
|
||||
= WordToMachine((unsigned int) value);
|
||||
break;
|
||||
|
||||
default: ASSERT(FALSE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
exception = Translate(addr, &physicalAddress, size, TRUE);
|
||||
if (exception != NoException) {
|
||||
RaiseException(exception, addr);
|
||||
return FALSE;
|
||||
}
|
||||
switch (size) {
|
||||
case 1:
|
||||
mainMemory[physicalAddress] = (unsigned char) (value & 0xff);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
*(unsigned short *) &mainMemory[physicalAddress]
|
||||
= ShortToMachine((unsigned short) (value & 0xffff));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
*(unsigned int *) &mainMemory[physicalAddress]
|
||||
= WordToMachine((unsigned int) value);
|
||||
break;
|
||||
|
||||
default: ASSERT(FALSE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -184,67 +184,75 @@ Machine::WriteMem(int addr, int size, int value)
|
||||
ExceptionType
|
||||
Machine::Translate(int virtAddr, int* physAddr, int size, bool writing)
|
||||
{
|
||||
int i;
|
||||
unsigned int vpn, offset;
|
||||
TranslationEntry *entry;
|
||||
unsigned int pageFrame;
|
||||
int i;
|
||||
unsigned int vpn, offset;
|
||||
TranslationEntry *entry;
|
||||
unsigned int pageFrame;
|
||||
|
||||
DEBUG(dbgAddr, "\tTranslate " << virtAddr << (writing ? " , write" : " , read"));
|
||||
DEBUG(dbgAddr, "\tTranslate " << virtAddr << (writing ? " , write" : " , read"));
|
||||
|
||||
// check for alignment errors
|
||||
if (((size == 4) && (virtAddr & 0x3)) || ((size == 2) && (virtAddr & 0x1))){
|
||||
DEBUG(dbgAddr, "Alignment problem at " << virtAddr << ", size " << size);
|
||||
return AddressErrorException;
|
||||
// check for alignment errors
|
||||
if (((size == 4) && (virtAddr & 0x3)) || ((size == 2) && (virtAddr & 0x1))){
|
||||
DEBUG(dbgAddr, "Alignment problem at " << virtAddr << ", size " << size);
|
||||
return AddressErrorException;
|
||||
}
|
||||
// we must have either a TLB or a page table, but not both!
|
||||
ASSERT(tlb == NULL || pageTable == NULL);
|
||||
ASSERT(tlb != NULL || pageTable != NULL);
|
||||
|
||||
// calculate the virtual page number, and offset within the page,
|
||||
// from the virtual address
|
||||
vpn = (unsigned) virtAddr / PageSize;
|
||||
offset = (unsigned) virtAddr % PageSize;
|
||||
|
||||
if (tlb == NULL) { // => page table => vpn is index into table
|
||||
if (vpn >= pageTableSize) {
|
||||
DEBUG(dbgAddr, "Illegal virtual page # " << virtAddr);
|
||||
DEBUG(dbgAddr, "vpn, pageTableSize, NumPhysPages: " << vpn << ' ' << pageTableSize << ' ' << NumPhysPages);
|
||||
return AddressErrorException;
|
||||
} else if (!pageTable[vpn].valid) {
|
||||
DEBUG(dbgAddr, "Invalid virtual page # " << virtAddr);
|
||||
return PageFaultException;
|
||||
}
|
||||
// we must have either a TLB or a page table, but not both!
|
||||
ASSERT(tlb == NULL || pageTable == NULL);
|
||||
ASSERT(tlb != NULL || pageTable != NULL);
|
||||
|
||||
// calculate the virtual page number, and offset within the page,
|
||||
// from the virtual address
|
||||
vpn = (unsigned) virtAddr / PageSize;
|
||||
offset = (unsigned) virtAddr % PageSize;
|
||||
|
||||
if (tlb == NULL) { // => page table => vpn is index into table
|
||||
if (vpn >= pageTableSize) {
|
||||
DEBUG(dbgAddr, "Illegal virtual page # " << virtAddr);
|
||||
return AddressErrorException;
|
||||
} else if (!pageTable[vpn].valid) {
|
||||
DEBUG(dbgAddr, "Invalid virtual page # " << virtAddr);
|
||||
return PageFaultException;
|
||||
}
|
||||
entry = &pageTable[vpn];
|
||||
} else {
|
||||
for (entry = NULL, i = 0; i < TLBSize; i++)
|
||||
if (tlb[i].valid && (tlb[i].virtualPage == ((int)vpn))) {
|
||||
entry = &tlb[i]; // FOUND!
|
||||
break;
|
||||
}
|
||||
if (entry == NULL) { // not found
|
||||
DEBUG(dbgAddr, "Invalid TLB entry for this virtual page!");
|
||||
return PageFaultException; // really, this is a TLB fault,
|
||||
// the page may be in memory,
|
||||
// but not in the TLB
|
||||
}
|
||||
entry = &pageTable[vpn];
|
||||
} else {
|
||||
for (entry = NULL, i = 0; i < TLBSize; i++)
|
||||
if (tlb[i].valid && (tlb[i].virtualPage == ((int)vpn))) {
|
||||
entry = &tlb[i]; // FOUND!
|
||||
break;
|
||||
}
|
||||
if (entry == NULL) { // not found
|
||||
DEBUG(dbgAddr, "Invalid TLB entry for this virtual page!");
|
||||
return PageFaultException; // really, this is a TLB fault,
|
||||
// the page may be in memory,
|
||||
// but not in the TLB
|
||||
}
|
||||
}
|
||||
|
||||
if (entry->readOnly && writing) { // trying to write to a read-only page
|
||||
DEBUG(dbgAddr, "Write to read-only page at " << virtAddr);
|
||||
return ReadOnlyException;
|
||||
if (entry->readOnly && writing) { // trying to write to a read-only page
|
||||
DEBUG(dbgAddr, "Write to read-only page at " << virtAddr);
|
||||
return ReadOnlyException;
|
||||
}
|
||||
pageFrame = entry->physicalPage;
|
||||
if (pageFrame == -1) {
|
||||
pageFrame = entry->physicalPage = kernel->frameTable->Allocate();
|
||||
if (pageFrame == -1) {
|
||||
DEBUG(dbgAddr, "Memory Limit exceeded");
|
||||
return MemoryLimitException;
|
||||
}
|
||||
pageFrame = entry->physicalPage;
|
||||
}
|
||||
|
||||
// if the pageFrame is too big, there is something really wrong!
|
||||
// An invalid translation was loaded into the page table or TLB.
|
||||
if (pageFrame >= NumPhysPages) {
|
||||
DEBUG(dbgAddr, "Illegal pageframe " << pageFrame);
|
||||
return BusErrorException;
|
||||
}
|
||||
entry->use = TRUE; // set the use, dirty bits
|
||||
if (writing)
|
||||
entry->dirty = TRUE;
|
||||
*physAddr = pageFrame * PageSize + offset;
|
||||
ASSERT((*physAddr >= 0) && ((*physAddr + size) <= MemorySize));
|
||||
DEBUG(dbgAddr, "phys addr = " << *physAddr);
|
||||
return NoException;
|
||||
// if the pageFrame is too big, there is something really wrong!
|
||||
// An invalid translation was loaded into the page table or TLB.
|
||||
if (pageFrame >= NumPhysPages) {
|
||||
DEBUG(dbgAddr, "Illegal pageframe " << pageFrame);
|
||||
return BusErrorException;
|
||||
}
|
||||
entry->use = TRUE; // set the use, dirty bits
|
||||
if (writing)
|
||||
entry->dirty = TRUE;
|
||||
*physAddr = pageFrame * PageSize + offset;
|
||||
ASSERT((*physAddr >= 0) && ((*physAddr + size) <= MemorySize));
|
||||
DEBUG(dbgAddr, "phys addr = " << *physAddr);
|
||||
return NoException;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user