Ytshih/hw2

This commit is contained in:
Yi-Ting Shih
2024-11-02 07:58:12 +08:00
parent 549bc9bcdc
commit 4912fe4736
24 changed files with 752 additions and 4283 deletions

View File

@@ -181,4 +181,4 @@ ConsoleOutput::PutInt(int value)
WriteFile(writeFileNo, printStr, strlen(printStr)*sizeof(char));
putBusy = TRUE;
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt);
}
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}