Ytshih/hw2
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
*.o
|
*.o
|
||||||
|
*.coff
|
||||||
|
|||||||
@@ -6,8 +6,11 @@ RUN apt-get -y install build-essential ed \
|
|||||||
gcc-multilib g++-multilib lib32ncurses5-dev lib32z1 \
|
gcc-multilib g++-multilib lib32ncurses5-dev lib32z1 \
|
||||||
zlib1g:i386 libstdc++6:i386 libc6:i386 libncurses5:i386 \
|
zlib1g:i386 libstdc++6:i386 libc6:i386 libncurses5:i386 \
|
||||||
libgcc1:i386 libstdc++5:i386
|
libgcc1:i386 libstdc++5:i386
|
||||||
|
|
||||||
|
RUN apt-get -y install fish vim less gdb
|
||||||
|
|
||||||
RUN groupadd -g 60139 ytshih && useradd -g 60139 -u 60139 ytshih
|
RUN groupadd -g 60139 ytshih && useradd -g 60139 -u 60139 ytshih
|
||||||
|
|
||||||
WORKDIR /work
|
WORKDIR /work
|
||||||
ENTRYPOINT ["/usr/bin/env"]
|
ENTRYPOINT ["/usr/bin/env"]
|
||||||
CMD ["bash"]
|
CMD ["fish"]
|
||||||
|
|||||||
@@ -3,12 +3,15 @@
|
|||||||
|
|
||||||
all:
|
all:
|
||||||
make -C build.linux depend
|
make -C build.linux depend
|
||||||
make -C build.linux
|
make -C build.linux -j 16
|
||||||
make -C test
|
make -C test -j 16
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
make -C build.linux clean
|
make -C build.linux distclean
|
||||||
make -C test distclean
|
make -C test distclean
|
||||||
|
|
||||||
run:
|
run:
|
||||||
make -C test run
|
make -C test run
|
||||||
|
|
||||||
|
debug:
|
||||||
|
make -C test debug
|
||||||
|
|||||||
Binary file not shown.
@@ -200,8 +200,8 @@ DEFINES = -DFILESYS_STUB -DRDATA -DSIM_FIX
|
|||||||
# break the thread system. You might want to use -fno-inline if
|
# break the thread system. You might want to use -fno-inline if
|
||||||
# you need to call some inline functions from the debugger.
|
# you need to call some inline functions from the debugger.
|
||||||
|
|
||||||
CFLAGS = -g -Wall $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32
|
CFLAGS = -g -fsanitize=address,undefined -Wall -Wextra $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32
|
||||||
LDFLAGS = -m32
|
LDFLAGS = -fsanitize=address,undefined -m32
|
||||||
CPP_AS_FLAGS= -m32
|
CPP_AS_FLAGS= -m32
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -181,4 +181,4 @@ ConsoleOutput::PutInt(int value)
|
|||||||
WriteFile(writeFileNo, printStr, strlen(printStr)*sizeof(char));
|
WriteFile(writeFileNo, printStr, strlen(printStr)*sizeof(char));
|
||||||
putBusy = TRUE;
|
putBusy = TRUE;
|
||||||
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt);
|
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "copyright.h"
|
#include "copyright.h"
|
||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "synchconsole.h"
|
||||||
|
|
||||||
// String definitions for debugging messages
|
// String definitions for debugging messages
|
||||||
|
|
||||||
@@ -340,7 +341,7 @@ static void
|
|||||||
PrintPending (PendingInterrupt *pending)
|
PrintPending (PendingInterrupt *pending)
|
||||||
{
|
{
|
||||||
cout << "Interrupt handler "<< intTypeNames[pending->type];
|
cout << "Interrupt handler "<< intTypeNames[pending->type];
|
||||||
cout << ", scheduled at " << pending->when;
|
cout << ", scheduled at " << pending->when << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -362,5 +363,5 @@ Interrupt::DumpState()
|
|||||||
void
|
void
|
||||||
Interrupt::PrintInt(int value)
|
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
|
// Textual names of the exceptions that can be generated by user program
|
||||||
// execution, for debugging.
|
// execution, for debugging.
|
||||||
static char* exceptionNames[] = { "no exception", "syscall",
|
static char* exceptionNames[] = {
|
||||||
"page fault/no TLB entry", "page read only",
|
"no exception",
|
||||||
"bus error", "address error", "overflow",
|
"syscall",
|
||||||
"illegal instruction" };
|
"page fault/no TLB entry",
|
||||||
|
"page read only",
|
||||||
|
"bus error",
|
||||||
|
"address error",
|
||||||
|
"overflow",
|
||||||
|
"illegal instruction",
|
||||||
|
"bad memory allocation"
|
||||||
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// CheckEndian
|
// CheckEndian
|
||||||
|
|||||||
@@ -28,32 +28,34 @@
|
|||||||
// Definitions related to the size, and format of user memory
|
// Definitions related to the size, and format of user memory
|
||||||
|
|
||||||
const int PageSize = 128; // set the page size equal to
|
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.
|
// You are allowed to change this value.
|
||||||
// Doing so will change the number of pages of physical memory
|
// Doing so will change the number of pages of physical memory
|
||||||
// available on the simulated machine.
|
// available on the simulated machine.
|
||||||
//
|
//
|
||||||
const int NumPhysPages = 128;
|
const int NumPhysPages = 128;
|
||||||
|
|
||||||
const int MemorySize = (NumPhysPages * PageSize);
|
const int MemorySize = (NumPhysPages * PageSize);
|
||||||
const int TLBSize = 4; // if there is a TLB, make it small
|
const int TLBSize = 4; // if there is a TLB, make it small
|
||||||
|
|
||||||
enum ExceptionType { NoException, // Everything ok!
|
enum ExceptionType {
|
||||||
SyscallException, // A program executed a system call.
|
NoException, // Everything ok!
|
||||||
PageFaultException, // No valid translation found
|
SyscallException, // A program executed a system call.
|
||||||
ReadOnlyException, // Write attempted to page marked
|
PageFaultException, // No valid translation found
|
||||||
// "read-only"
|
ReadOnlyException, // Write attempted to page marked
|
||||||
BusErrorException, // Translation resulted in an
|
// "read-only"
|
||||||
// invalid physical address
|
BusErrorException, // Translation resulted in an
|
||||||
AddressErrorException, // Unaligned reference or one that
|
// invalid physical address
|
||||||
// was beyond the end of the
|
AddressErrorException, // Unaligned reference or one that
|
||||||
// address space
|
// was beyond the end of the
|
||||||
OverflowException, // Integer overflow in add or sub.
|
// address space
|
||||||
IllegalInstrException, // Unimplemented or reserved instr.
|
OverflowException, // Integer overflow in add or sub.
|
||||||
|
IllegalInstrException, // Unimplemented or reserved instr.
|
||||||
NumExceptionTypes
|
MemoryLimitException, // Bad allocation
|
||||||
|
|
||||||
|
NumExceptionTypes
|
||||||
};
|
};
|
||||||
|
|
||||||
// User program CPU state. The full set of MIPS registers, plus a few
|
// User program CPU state. The full set of MIPS registers, plus a few
|
||||||
@@ -94,97 +96,97 @@ class Interrupt;
|
|||||||
class Machine {
|
class Machine {
|
||||||
public:
|
public:
|
||||||
Machine(bool debug); // Initialize the simulation of the hardware
|
Machine(bool debug); // Initialize the simulation of the hardware
|
||||||
// for running user programs
|
// for running user programs
|
||||||
~Machine(); // De-allocate the data structures
|
~Machine(); // De-allocate the data structures
|
||||||
|
|
||||||
// Routines callable by the Nachos kernel
|
// Routines callable by the Nachos kernel
|
||||||
void Run(); // Run a user program
|
void Run(); // Run a user program
|
||||||
|
|
||||||
int ReadRegister(int num); // read the contents of a CPU register
|
int ReadRegister(int num); // read the contents of a CPU register
|
||||||
|
|
||||||
void WriteRegister(int num, int value);
|
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
|
// Data structures accessible to the Nachos kernel -- main memory and the
|
||||||
// page table/TLB.
|
// page table/TLB.
|
||||||
//
|
//
|
||||||
// Note that *all* communication between the user program and the kernel
|
// Note that *all* communication between the user program and the kernel
|
||||||
// are in terms of these data structures (plus the CPU registers).
|
// are in terms of these data structures (plus the CPU registers).
|
||||||
|
|
||||||
char *mainMemory; // physical memory to store user program,
|
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
|
// NOTE: the hardware translation of virtual addresses in the user program
|
||||||
// to physical addresses (relative to the beginning of "mainMemory")
|
// to physical addresses (relative to the beginning of "mainMemory")
|
||||||
// can be controlled by one of:
|
// can be controlled by one of:
|
||||||
// a traditional linear page table
|
// a traditional linear page table
|
||||||
// a software-loaded translation lookaside buffer (tlb) -- a cache of
|
// a software-loaded translation lookaside buffer (tlb) -- a cache of
|
||||||
// mappings of virtual page #'s to physical page #'s
|
// mappings of virtual page #'s to physical page #'s
|
||||||
//
|
//
|
||||||
// If "tlb" is NULL, the linear page table is used
|
// If "tlb" is NULL, the linear page table is used
|
||||||
// If "tlb" is non-NULL, the Nachos kernel is responsible for managing
|
// 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
|
// the contents of the TLB. But the kernel can use any data structure
|
||||||
// it wants (eg, segmented paging) for handling TLB cache misses.
|
// it wants (eg, segmented paging) for handling TLB cache misses.
|
||||||
//
|
//
|
||||||
// For simplicity, both the page table pointer and the TLB pointer are
|
// For simplicity, both the page table pointer and the TLB pointer are
|
||||||
// public. However, while there can be multiple page tables (one per address
|
// public. However, while there can be multiple page tables (one per address
|
||||||
// space, stored in memory), there is only one TLB (implemented in hardware).
|
// space, stored in memory), there is only one TLB (implemented in hardware).
|
||||||
// Thus the TLB pointer should be considered as *read-only*, although
|
// 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.
|
// the contents of the TLB are free to be modified by the kernel software.
|
||||||
|
|
||||||
TranslationEntry *tlb; // this pointer should be considered
|
TranslationEntry *tlb; // this pointer should be considered
|
||||||
// "read-only" to Nachos kernel code
|
// "read-only" to Nachos kernel code
|
||||||
|
|
||||||
TranslationEntry *pageTable;
|
TranslationEntry *pageTable;
|
||||||
unsigned int pageTableSize;
|
unsigned int pageTableSize;
|
||||||
|
|
||||||
bool ReadMem(int addr, int size, int* value);
|
bool ReadMem(int addr, int size, int* value);
|
||||||
bool WriteMem(int addr, int size, int value);
|
bool WriteMem(int addr, int size, int value);
|
||||||
// Read or write 1, 2, or 4 bytes of virtual
|
// Read or write 1, 2, or 4 bytes of virtual
|
||||||
// memory (at addr). Return FALSE if a
|
// memory (at addr). Return FALSE if a
|
||||||
// correct translation couldn't be found.
|
// correct translation couldn't be found.
|
||||||
private:
|
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);
|
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);
|
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);
|
ExceptionType Translate(int virtAddr, int* physAddr, int size,bool writing);
|
||||||
// Translate an address, and check for
|
// Translate an address, and check for
|
||||||
// alignment. Set the use and dirty bits in
|
// alignment. Set the use and dirty bits in
|
||||||
// the translation entry appropriately,
|
// the translation entry appropriately,
|
||||||
// and return an exception code if the
|
// and return an exception code if the
|
||||||
// translation couldn't be completed.
|
// translation couldn't be completed.
|
||||||
|
|
||||||
void RaiseException(ExceptionType which, int badVAddr);
|
void RaiseException(ExceptionType which, int badVAddr);
|
||||||
// Trap to the Nachos kernel, because of a
|
// Trap to the Nachos kernel, because of a
|
||||||
// system call or other exception.
|
// system call or other exception.
|
||||||
|
|
||||||
void Debugger(); // invoke the user program debugger
|
void Debugger(); // invoke the user program debugger
|
||||||
void DumpState(); // print the user CPU and memory state
|
void DumpState(); // print the user CPU and memory state
|
||||||
|
|
||||||
|
|
||||||
// Internal data structures
|
// Internal data structures
|
||||||
|
|
||||||
int registers[NumTotalRegs]; // CPU registers, for executing user programs
|
int registers[NumTotalRegs]; // CPU registers, for executing user programs
|
||||||
|
|
||||||
bool singleStep; // drop back into the debugger after each
|
bool singleStep; // drop back into the debugger after each
|
||||||
// simulated instruction
|
// simulated instruction
|
||||||
int runUntilTime; // drop back into the debugger when simulated
|
int runUntilTime; // drop back into the debugger when simulated
|
||||||
// time reaches this value
|
// time reaches this value
|
||||||
|
|
||||||
friend class Interrupt; // calls DelayedLoad()
|
friend class Interrupt; // calls DelayedLoad()
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void ExceptionHandler(ExceptionType which);
|
extern void ExceptionHandler(ExceptionType which);
|
||||||
// Entry point into Nachos for handling
|
// Entry point into Nachos for handling
|
||||||
// user system calls and exceptions
|
// user system calls and exceptions
|
||||||
// Defined in exception.cc
|
// Defined in exception.cc
|
||||||
|
|
||||||
|
|
||||||
// Routines for converting Words and Short Words to and from the
|
// Routines for converting Words and Short Words to and from the
|
||||||
|
|||||||
@@ -85,38 +85,38 @@ ShortToMachine(unsigned short shortword) { return ShortToHost(shortword); }
|
|||||||
bool
|
bool
|
||||||
Machine::ReadMem(int addr, int size, int *value)
|
Machine::ReadMem(int addr, int size, int *value)
|
||||||
{
|
{
|
||||||
int data;
|
int data;
|
||||||
ExceptionType exception;
|
ExceptionType exception;
|
||||||
int physicalAddress;
|
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;
|
|
||||||
|
|
||||||
default: ASSERT(FALSE);
|
DEBUG(dbgAddr, "Reading VA " << addr << ", size " << size);
|
||||||
}
|
|
||||||
|
exception = Translate(addr, &physicalAddress, size, FALSE);
|
||||||
DEBUG(dbgAddr, "\tvalue read = " << *value);
|
if (exception != NoException) {
|
||||||
return (TRUE);
|
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
|
bool
|
||||||
Machine::WriteMem(int addr, int size, int value)
|
Machine::WriteMem(int addr, int size, int value)
|
||||||
{
|
{
|
||||||
ExceptionType exception;
|
ExceptionType exception;
|
||||||
int physicalAddress;
|
int physicalAddress;
|
||||||
|
|
||||||
DEBUG(dbgAddr, "Writing VA " << addr << ", size " << size << ", value " << value);
|
|
||||||
|
|
||||||
exception = Translate(addr, &physicalAddress, size, TRUE);
|
DEBUG(dbgAddr, "Writing VA " << addr << ", size " << size << ", value " << value);
|
||||||
if (exception != NoException) {
|
|
||||||
RaiseException(exception, addr);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
switch (size) {
|
|
||||||
case 1:
|
|
||||||
mainMemory[physicalAddress] = (unsigned char) (value & 0xff);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
exception = Translate(addr, &physicalAddress, size, TRUE);
|
||||||
*(unsigned short *) &mainMemory[physicalAddress]
|
if (exception != NoException) {
|
||||||
= ShortToMachine((unsigned short) (value & 0xffff));
|
RaiseException(exception, addr);
|
||||||
break;
|
return FALSE;
|
||||||
|
}
|
||||||
case 4:
|
switch (size) {
|
||||||
*(unsigned int *) &mainMemory[physicalAddress]
|
case 1:
|
||||||
= WordToMachine((unsigned int) value);
|
mainMemory[physicalAddress] = (unsigned char) (value & 0xff);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: ASSERT(FALSE);
|
case 2:
|
||||||
}
|
*(unsigned short *) &mainMemory[physicalAddress]
|
||||||
|
= ShortToMachine((unsigned short) (value & 0xffff));
|
||||||
return TRUE;
|
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
|
ExceptionType
|
||||||
Machine::Translate(int virtAddr, int* physAddr, int size, bool writing)
|
Machine::Translate(int virtAddr, int* physAddr, int size, bool writing)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned int vpn, offset;
|
unsigned int vpn, offset;
|
||||||
TranslationEntry *entry;
|
TranslationEntry *entry;
|
||||||
unsigned int pageFrame;
|
unsigned int pageFrame;
|
||||||
|
|
||||||
DEBUG(dbgAddr, "\tTranslate " << virtAddr << (writing ? " , write" : " , read"));
|
DEBUG(dbgAddr, "\tTranslate " << virtAddr << (writing ? " , write" : " , read"));
|
||||||
|
|
||||||
// check for alignment errors
|
// check for alignment errors
|
||||||
if (((size == 4) && (virtAddr & 0x3)) || ((size == 2) && (virtAddr & 0x1))){
|
if (((size == 4) && (virtAddr & 0x3)) || ((size == 2) && (virtAddr & 0x1))){
|
||||||
DEBUG(dbgAddr, "Alignment problem at " << virtAddr << ", size " << size);
|
DEBUG(dbgAddr, "Alignment problem at " << virtAddr << ", size " << size);
|
||||||
return AddressErrorException;
|
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!
|
entry = &pageTable[vpn];
|
||||||
ASSERT(tlb == NULL || pageTable == NULL);
|
} else {
|
||||||
ASSERT(tlb != NULL || pageTable != NULL);
|
for (entry = NULL, i = 0; i < TLBSize; i++)
|
||||||
|
if (tlb[i].valid && (tlb[i].virtualPage == ((int)vpn))) {
|
||||||
// calculate the virtual page number, and offset within the page,
|
entry = &tlb[i]; // FOUND!
|
||||||
// from the virtual address
|
break;
|
||||||
vpn = (unsigned) virtAddr / PageSize;
|
}
|
||||||
offset = (unsigned) virtAddr % PageSize;
|
if (entry == NULL) { // not found
|
||||||
|
DEBUG(dbgAddr, "Invalid TLB entry for this virtual page!");
|
||||||
if (tlb == NULL) { // => page table => vpn is index into table
|
return PageFaultException; // really, this is a TLB fault,
|
||||||
if (vpn >= pageTableSize) {
|
// the page may be in memory,
|
||||||
DEBUG(dbgAddr, "Illegal virtual page # " << virtAddr);
|
// but not in the TLB
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (entry->readOnly && writing) { // trying to write to a read-only page
|
if (entry->readOnly && writing) { // trying to write to a read-only page
|
||||||
DEBUG(dbgAddr, "Write to read-only page at " << virtAddr);
|
DEBUG(dbgAddr, "Write to read-only page at " << virtAddr);
|
||||||
return ReadOnlyException;
|
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!
|
// if the pageFrame is too big, there is something really wrong!
|
||||||
// An invalid translation was loaded into the page table or TLB.
|
// An invalid translation was loaded into the page table or TLB.
|
||||||
if (pageFrame >= NumPhysPages) {
|
if (pageFrame >= NumPhysPages) {
|
||||||
DEBUG(dbgAddr, "Illegal pageframe " << pageFrame);
|
DEBUG(dbgAddr, "Illegal pageframe " << pageFrame);
|
||||||
return BusErrorException;
|
return BusErrorException;
|
||||||
}
|
}
|
||||||
entry->use = TRUE; // set the use, dirty bits
|
entry->use = TRUE; // set the use, dirty bits
|
||||||
if (writing)
|
if (writing)
|
||||||
entry->dirty = TRUE;
|
entry->dirty = TRUE;
|
||||||
*physAddr = pageFrame * PageSize + offset;
|
*physAddr = pageFrame * PageSize + offset;
|
||||||
ASSERT((*physAddr >= 0) && ((*physAddr + size) <= MemorySize));
|
ASSERT((*physAddr >= 0) && ((*physAddr + size) <= MemorySize));
|
||||||
DEBUG(dbgAddr, "phys addr = " << *physAddr);
|
DEBUG(dbgAddr, "phys addr = " << *physAddr);
|
||||||
return NoException;
|
return NoException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ ifeq ($(hosttype),unknown)
|
|||||||
PROGRAMS = unknownhost
|
PROGRAMS = unknownhost
|
||||||
else
|
else
|
||||||
# change this if you create a new test program!
|
# change this if you create a new test program!
|
||||||
PROGRAMS = add halt consoleIO_test1 consoleIO_test2 fileIO_test1 fileIO_test2
|
PROGRAMS = add halt consoleIO_test1 consoleIO_test2 fileIO_test1 fileIO_test2 test
|
||||||
# PROGRAMS = halt
|
# PROGRAMS = halt
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -189,6 +189,11 @@ fileIO_test3: fileIO_test3.o start.o
|
|||||||
$(LD) $(LDFLAGS) start.o fileIO_test3.o -o fileIO_test3.coff
|
$(LD) $(LDFLAGS) start.o fileIO_test3.o -o fileIO_test3.coff
|
||||||
$(COFF2NOFF) fileIO_test3.coff fileIO_test3
|
$(COFF2NOFF) fileIO_test3.coff fileIO_test3
|
||||||
|
|
||||||
|
test.o: test.c
|
||||||
|
$(CC) $(CFLAGS) -c test.c
|
||||||
|
test: test.o start.o
|
||||||
|
$(LD) $(LDFLAGS) start.o test.o -o test.coff
|
||||||
|
$(COFF2NOFF) test.coff test
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) -f *.o *.ii
|
$(RM) -f *.o *.ii
|
||||||
@@ -198,10 +203,11 @@ distclean: clean
|
|||||||
$(RM) -f $(PROGRAMS)
|
$(RM) -f $(PROGRAMS)
|
||||||
|
|
||||||
run: $(PROGRAMS)
|
run: $(PROGRAMS)
|
||||||
for i in $(PROGRAMS); do \
|
timeout 1 $(NACHOS) -e consoleIO_test1 -e consoleIO_test2
|
||||||
echo ===== $$i =====; \
|
echo 'done'
|
||||||
$(NACHOS) -e $$i; \
|
|
||||||
done
|
debug: $(PROGRAMS)
|
||||||
|
timeout 1 $(NACHOS) -e consoleIO_test1 -e consoleIO_test2 -d +
|
||||||
|
|
||||||
|
|
||||||
unknownhost:
|
unknownhost:
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
int n;
|
int n;
|
||||||
for (n = 9; n > 5; n--)
|
for (n = 9; n > 5; n--)
|
||||||
PrintInt(n);
|
PrintInt(n);
|
||||||
Halt();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
|
|
||||||
int
|
int main()
|
||||||
main()
|
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
for (n=15;n<=19;n++){
|
for (n=15;n<=19;n++){
|
||||||
|
|
||||||
PrintInt(n);
|
PrintInt(n);
|
||||||
}
|
}
|
||||||
Halt();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -187,12 +187,12 @@ ThreadJoin:
|
|||||||
.end ThreadJoin
|
.end ThreadJoin
|
||||||
|
|
||||||
.globl PrintInt
|
.globl PrintInt
|
||||||
.ent PrintInt
|
.ent PrintInt
|
||||||
PrintInt:
|
PrintInt:
|
||||||
addiu $2,$0,SC_PrintInt
|
addiu $2,$0,SC_PrintInt
|
||||||
syscall
|
syscall
|
||||||
j $31
|
j $31
|
||||||
.end PrintInt
|
.end PrintInt
|
||||||
|
|
||||||
|
|
||||||
/* dummy function to keep gcc happy */
|
/* dummy function to keep gcc happy */
|
||||||
|
|||||||
6
code/test/test.c
Normal file
6
code/test/test.c
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include "syscall.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
Exit(0);
|
||||||
|
}
|
||||||
@@ -26,58 +26,60 @@
|
|||||||
|
|
||||||
Kernel::Kernel(int argc, char **argv)
|
Kernel::Kernel(int argc, char **argv)
|
||||||
{
|
{
|
||||||
randomSlice = FALSE;
|
execfileNum = 0;
|
||||||
debugUserProg = FALSE;
|
threadNum = 0;
|
||||||
consoleIn = NULL; // default is stdin
|
randomSlice = FALSE;
|
||||||
consoleOut = NULL; // default is stdout
|
debugUserProg = FALSE;
|
||||||
|
consoleIn = NULL; // default is stdin
|
||||||
|
consoleOut = NULL; // default is stdout
|
||||||
#ifndef FILESYS_STUB
|
#ifndef FILESYS_STUB
|
||||||
formatFlag = FALSE;
|
formatFlag = FALSE;
|
||||||
#endif
|
#endif
|
||||||
reliability = 1; // network reliability, default is 1.0
|
reliability = 1; // network reliability, default is 1.0
|
||||||
hostName = 0; // machine id, also UNIX socket name
|
hostName = 0; // machine id, also UNIX socket name
|
||||||
// 0 is the default machine id
|
// 0 is the default machine id
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
if (strcmp(argv[i], "-rs") == 0) {
|
if (strcmp(argv[i], "-rs") == 0) {
|
||||||
ASSERT(i + 1 < argc);
|
ASSERT(i + 1 < argc);
|
||||||
RandomInit(atoi(argv[i + 1]));// initialize pseudo-random
|
RandomInit(atoi(argv[i + 1]));// initialize pseudo-random
|
||||||
// number generator
|
// number generator
|
||||||
randomSlice = TRUE;
|
randomSlice = TRUE;
|
||||||
i++;
|
i++;
|
||||||
} else if (strcmp(argv[i], "-s") == 0) {
|
} else if (strcmp(argv[i], "-s") == 0) {
|
||||||
debugUserProg = TRUE;
|
debugUserProg = TRUE;
|
||||||
} else if (strcmp(argv[i], "-e") == 0) {
|
} else if (strcmp(argv[i], "-e") == 0) {
|
||||||
execfile[++execfileNum]= argv[++i];
|
execfile[++execfileNum]= argv[++i];
|
||||||
cout << execfile[execfileNum] << "\n";
|
cout << execfile[execfileNum] << "\n";
|
||||||
} else if (strcmp(argv[i], "-ci") == 0) {
|
} else if (strcmp(argv[i], "-ci") == 0) {
|
||||||
ASSERT(i + 1 < argc);
|
ASSERT(i + 1 < argc);
|
||||||
consoleIn = argv[i + 1];
|
consoleIn = argv[i + 1];
|
||||||
i++;
|
i++;
|
||||||
} else if (strcmp(argv[i], "-co") == 0) {
|
} else if (strcmp(argv[i], "-co") == 0) {
|
||||||
ASSERT(i + 1 < argc);
|
ASSERT(i + 1 < argc);
|
||||||
consoleOut = argv[i + 1];
|
consoleOut = argv[i + 1];
|
||||||
i++;
|
i++;
|
||||||
#ifndef FILESYS_STUB
|
#ifndef FILESYS_STUB
|
||||||
} else if (strcmp(argv[i], "-f") == 0) {
|
} else if (strcmp(argv[i], "-f") == 0) {
|
||||||
formatFlag = TRUE;
|
formatFlag = TRUE;
|
||||||
#endif
|
#endif
|
||||||
} else if (strcmp(argv[i], "-n") == 0) {
|
} else if (strcmp(argv[i], "-n") == 0) {
|
||||||
ASSERT(i + 1 < argc); // next argument is float
|
ASSERT(i + 1 < argc); // next argument is float
|
||||||
reliability = atof(argv[i + 1]);
|
reliability = atof(argv[i + 1]);
|
||||||
i++;
|
i++;
|
||||||
} else if (strcmp(argv[i], "-m") == 0) {
|
} else if (strcmp(argv[i], "-m") == 0) {
|
||||||
ASSERT(i + 1 < argc); // next argument is int
|
ASSERT(i + 1 < argc); // next argument is int
|
||||||
hostName = atoi(argv[i + 1]);
|
hostName = atoi(argv[i + 1]);
|
||||||
i++;
|
i++;
|
||||||
} else if (strcmp(argv[i], "-u") == 0) {
|
} else if (strcmp(argv[i], "-u") == 0) {
|
||||||
cout << "Partial usage: nachos [-rs randomSeed]\n";
|
cout << "Partial usage: nachos [-rs randomSeed]\n";
|
||||||
cout << "Partial usage: nachos [-s]\n";
|
cout << "Partial usage: nachos [-s]\n";
|
||||||
cout << "Partial usage: nachos [-ci consoleIn] [-co consoleOut]\n";
|
cout << "Partial usage: nachos [-ci consoleIn] [-co consoleOut]\n";
|
||||||
#ifndef FILESYS_STUB
|
#ifndef FILESYS_STUB
|
||||||
cout << "Partial usage: nachos [-nf]\n";
|
cout << "Partial usage: nachos [-nf]\n";
|
||||||
#endif
|
#endif
|
||||||
cout << "Partial usage: nachos [-n #] [-m #]\n";
|
cout << "Partial usage: nachos [-n #] [-m #]\n";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -90,31 +92,32 @@ Kernel::Kernel(int argc, char **argv)
|
|||||||
void
|
void
|
||||||
Kernel::Initialize()
|
Kernel::Initialize()
|
||||||
{
|
{
|
||||||
// We didn't explicitly allocate the current thread we are running in.
|
// We didn't explicitly allocate the current thread we are running in.
|
||||||
// But if it ever tries to give up the CPU, we better have a Thread
|
// But if it ever tries to give up the CPU, we better have a Thread
|
||||||
// object to save its state.
|
// object to save its state.
|
||||||
|
|
||||||
|
|
||||||
currentThread = new Thread("main", threadNum++);
|
|
||||||
currentThread->setStatus(RUNNING);
|
|
||||||
|
|
||||||
stats = new Statistics(); // collect statistics
|
currentThread = new Thread("main", threadNum++);
|
||||||
interrupt = new Interrupt; // start up interrupt handling
|
currentThread->setStatus(RUNNING);
|
||||||
scheduler = new Scheduler(); // initialize the ready queue
|
|
||||||
alarm = new Alarm(randomSlice); // start up time slicing
|
stats = new Statistics(); // collect statistics
|
||||||
machine = new Machine(debugUserProg);
|
interrupt = new Interrupt; // start up interrupt handling
|
||||||
synchConsoleIn = new SynchConsoleInput(consoleIn); // input from stdin
|
scheduler = new Scheduler(); // initialize the ready queue
|
||||||
synchConsoleOut = new SynchConsoleOutput(consoleOut); // output to stdout
|
alarm = new Alarm(randomSlice); // start up time slicing
|
||||||
synchDisk = new SynchDisk(); //
|
machine = new Machine(debugUserProg);
|
||||||
|
synchConsoleIn = new SynchConsoleInput(consoleIn); // input from stdin
|
||||||
|
synchConsoleOut = new SynchConsoleOutput(consoleOut); // output to stdout
|
||||||
|
synchDisk = new SynchDisk(); //
|
||||||
#ifdef FILESYS_STUB
|
#ifdef FILESYS_STUB
|
||||||
fileSystem = new FileSystem();
|
fileSystem = new FileSystem();
|
||||||
#else
|
#else
|
||||||
fileSystem = new FileSystem(formatFlag);
|
fileSystem = new FileSystem(formatFlag);
|
||||||
#endif // FILESYS_STUB
|
#endif // FILESYS_STUB
|
||||||
postOfficeIn = new PostOfficeInput(10);
|
postOfficeIn = new PostOfficeInput(10);
|
||||||
postOfficeOut = new PostOfficeOutput(reliability);
|
postOfficeOut = new PostOfficeOutput(reliability);
|
||||||
|
frameTable = new FrameTable;
|
||||||
|
|
||||||
interrupt->Enable();
|
interrupt->Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -124,19 +127,20 @@ Kernel::Initialize()
|
|||||||
|
|
||||||
Kernel::~Kernel()
|
Kernel::~Kernel()
|
||||||
{
|
{
|
||||||
delete stats;
|
delete stats;
|
||||||
delete interrupt;
|
delete interrupt;
|
||||||
delete scheduler;
|
delete scheduler;
|
||||||
delete alarm;
|
delete alarm;
|
||||||
delete machine;
|
delete machine;
|
||||||
delete synchConsoleIn;
|
delete synchConsoleIn;
|
||||||
delete synchConsoleOut;
|
delete synchConsoleOut;
|
||||||
delete synchDisk;
|
delete synchDisk;
|
||||||
delete fileSystem;
|
delete fileSystem;
|
||||||
delete postOfficeIn;
|
delete postOfficeIn;
|
||||||
delete postOfficeOut;
|
delete postOfficeOut;
|
||||||
|
delete frameTable;
|
||||||
Exit(0);
|
|
||||||
|
Exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -239,7 +243,7 @@ Kernel::NetworkTest() {
|
|||||||
postOfficeOut->Send(outPktHdr, outMailHdr, ack);
|
postOfficeOut->Send(outPktHdr, outMailHdr, ack);
|
||||||
|
|
||||||
// Wait for the ack from the other machine to the first message we sent
|
// Wait for the ack from the other machine to the first message we sent
|
||||||
postOfficeIn->Receive(1, &inPktHdr, &inMailHdr, buffer);
|
postOfficeIn->Receive(1, &inPktHdr, &inMailHdr, buffer);
|
||||||
cout << "Got: " << buffer << " : from " << inPktHdr.from << ", box "
|
cout << "Got: " << buffer << " : from " << inPktHdr.from << ", box "
|
||||||
<< inMailHdr.from << "\n";
|
<< inMailHdr.from << "\n";
|
||||||
cout.flush();
|
cout.flush();
|
||||||
@@ -250,12 +254,10 @@ Kernel::NetworkTest() {
|
|||||||
|
|
||||||
void ForkExecute(Thread *t)
|
void ForkExecute(Thread *t)
|
||||||
{
|
{
|
||||||
if ( !t->space->Load(t->getName()) ) {
|
if (!t->space->Load(t->getName()))
|
||||||
return; // executable not found
|
return; // executable not found
|
||||||
}
|
|
||||||
|
|
||||||
t->space->Execute(t->getName());
|
|
||||||
|
|
||||||
|
t->space->Execute(t->getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::ExecAll()
|
void Kernel::ExecAll()
|
||||||
@@ -273,9 +275,8 @@ int Kernel::Exec(char* name)
|
|||||||
t[threadNum] = new Thread(name, threadNum);
|
t[threadNum] = new Thread(name, threadNum);
|
||||||
t[threadNum]->space = new AddrSpace();
|
t[threadNum]->space = new AddrSpace();
|
||||||
t[threadNum]->Fork((VoidFunctionPtr) &ForkExecute, (void *)t[threadNum]);
|
t[threadNum]->Fork((VoidFunctionPtr) &ForkExecute, (void *)t[threadNum]);
|
||||||
threadNum++;
|
|
||||||
|
|
||||||
return threadNum-1;
|
return threadNum++;
|
||||||
/*
|
/*
|
||||||
cout << "Total threads number is " << execfileNum << endl;
|
cout << "Total threads number is " << execfileNum << endl;
|
||||||
for (int n=1;n<=execfileNum;n++) {
|
for (int n=1;n<=execfileNum;n++) {
|
||||||
|
|||||||
@@ -60,9 +60,10 @@ class Kernel {
|
|||||||
SynchConsoleInput *synchConsoleIn;
|
SynchConsoleInput *synchConsoleIn;
|
||||||
SynchConsoleOutput *synchConsoleOut;
|
SynchConsoleOutput *synchConsoleOut;
|
||||||
SynchDisk *synchDisk;
|
SynchDisk *synchDisk;
|
||||||
FileSystem *fileSystem;
|
FileSystem *fileSystem;
|
||||||
PostOfficeInput *postOfficeIn;
|
PostOfficeInput *postOfficeIn;
|
||||||
PostOfficeOutput *postOfficeOut;
|
PostOfficeOutput *postOfficeOut;
|
||||||
|
FrameTable *frameTable;
|
||||||
|
|
||||||
int hostName; // machine identifier
|
int hostName; // machine identifier
|
||||||
|
|
||||||
|
|||||||
@@ -74,13 +74,13 @@ Scheduler::ReadyToRun (Thread *thread)
|
|||||||
Thread *
|
Thread *
|
||||||
Scheduler::FindNextToRun ()
|
Scheduler::FindNextToRun ()
|
||||||
{
|
{
|
||||||
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
||||||
|
|
||||||
if (readyList->IsEmpty()) {
|
if (readyList->IsEmpty()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
return readyList->RemoveFront();
|
return readyList->RemoveFront();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -103,50 +103,50 @@ Scheduler::FindNextToRun ()
|
|||||||
void
|
void
|
||||||
Scheduler::Run (Thread *nextThread, bool finishing)
|
Scheduler::Run (Thread *nextThread, bool finishing)
|
||||||
{
|
{
|
||||||
Thread *oldThread = kernel->currentThread;
|
Thread *oldThread = kernel->currentThread;
|
||||||
|
|
||||||
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
|
||||||
|
|
||||||
if (finishing) { // mark that we need to delete current thread
|
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
||||||
ASSERT(toBeDestroyed == NULL);
|
|
||||||
toBeDestroyed = oldThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldThread->space != NULL) { // if this thread is a user program,
|
|
||||||
oldThread->SaveUserState(); // save the user's CPU registers
|
|
||||||
oldThread->space->SaveState();
|
|
||||||
}
|
|
||||||
|
|
||||||
oldThread->CheckOverflow(); // check if the old thread
|
|
||||||
// had an undetected stack overflow
|
|
||||||
|
|
||||||
kernel->currentThread = nextThread; // switch to the next thread
|
if (finishing) { // mark that we need to delete current thread
|
||||||
nextThread->setStatus(RUNNING); // nextThread is now running
|
ASSERT(toBeDestroyed == NULL);
|
||||||
|
toBeDestroyed = oldThread;
|
||||||
DEBUG(dbgThread, "Switching from: " << oldThread->getName() << " to: " << nextThread->getName());
|
}
|
||||||
|
|
||||||
// This is a machine-dependent assembly language routine defined
|
|
||||||
// in switch.s. You may have to think
|
|
||||||
// a bit to figure out what happens after this, both from the point
|
|
||||||
// of view of the thread and from the perspective of the "outside world".
|
|
||||||
|
|
||||||
SWITCH(oldThread, nextThread);
|
if (oldThread->space != NULL) { // if this thread is a user program,
|
||||||
|
oldThread->SaveUserState(); // save the user's CPU registers
|
||||||
|
oldThread->space->SaveState();
|
||||||
|
}
|
||||||
|
|
||||||
// we're back, running oldThread
|
oldThread->CheckOverflow(); // check if the old thread
|
||||||
|
// had an undetected stack overflow
|
||||||
// interrupts are off when we return from switch!
|
|
||||||
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
|
||||||
|
|
||||||
DEBUG(dbgThread, "Now in thread: " << oldThread->getName());
|
kernel->currentThread = nextThread; // switch to the next thread
|
||||||
|
nextThread->setStatus(RUNNING); // nextThread is now running
|
||||||
|
|
||||||
CheckToBeDestroyed(); // check if thread we were running
|
DEBUG(dbgThread, "Switching from: " << oldThread->getName() << " to: " << nextThread->getName());
|
||||||
// before this one has finished
|
|
||||||
// and needs to be cleaned up
|
// This is a machine-dependent assembly language routine defined
|
||||||
|
// in switch.s. You may have to think
|
||||||
if (oldThread->space != NULL) { // if there is an address space
|
// a bit to figure out what happens after this, both from the point
|
||||||
oldThread->RestoreUserState(); // to restore, do it.
|
// of view of the thread and from the perspective of the "outside world".
|
||||||
oldThread->space->RestoreState();
|
|
||||||
}
|
SWITCH(oldThread, nextThread);
|
||||||
|
|
||||||
|
// we're back, running oldThread
|
||||||
|
|
||||||
|
// interrupts are off when we return from switch!
|
||||||
|
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
||||||
|
|
||||||
|
DEBUG(dbgThread, "Now in thread: " << oldThread->getName());
|
||||||
|
|
||||||
|
CheckToBeDestroyed(); // check if thread we were running
|
||||||
|
// before this one has finished
|
||||||
|
// and needs to be cleaned up
|
||||||
|
|
||||||
|
if (oldThread->space != NULL) { // if there is an address space
|
||||||
|
oldThread->RestoreUserState(); // to restore, do it.
|
||||||
|
oldThread->space->RestoreState();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -160,10 +160,10 @@ Scheduler::Run (Thread *nextThread, bool finishing)
|
|||||||
void
|
void
|
||||||
Scheduler::CheckToBeDestroyed()
|
Scheduler::CheckToBeDestroyed()
|
||||||
{
|
{
|
||||||
if (toBeDestroyed != NULL) {
|
if (toBeDestroyed != NULL) {
|
||||||
delete toBeDestroyed;
|
delete toBeDestroyed;
|
||||||
toBeDestroyed = NULL;
|
toBeDestroyed = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|||||||
@@ -35,17 +35,17 @@ const int STACK_FENCEPOST = 0xdedbeef;
|
|||||||
|
|
||||||
Thread::Thread(char* threadName, int threadID)
|
Thread::Thread(char* threadName, int threadID)
|
||||||
{
|
{
|
||||||
ID = threadID;
|
ID = threadID;
|
||||||
name = threadName;
|
name = threadName;
|
||||||
stackTop = NULL;
|
stackTop = NULL;
|
||||||
stack = NULL;
|
stack = NULL;
|
||||||
status = JUST_CREATED;
|
status = JUST_CREATED;
|
||||||
for (int i = 0; i < MachineStateSize; i++) {
|
for (int i = 0; i < MachineStateSize; i++) {
|
||||||
machineState[i] = NULL; // not strictly necessary, since
|
machineState[i] = NULL; // not strictly necessary, since
|
||||||
// new thread ignores contents
|
// new thread ignores contents
|
||||||
// of machine registers
|
// of machine registers
|
||||||
}
|
}
|
||||||
space = NULL;
|
space = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -62,10 +62,10 @@ Thread::Thread(char* threadName, int threadID)
|
|||||||
|
|
||||||
Thread::~Thread()
|
Thread::~Thread()
|
||||||
{
|
{
|
||||||
DEBUG(dbgThread, "Deleting thread: " << name);
|
DEBUG(dbgThread, "Deleting thread: " << name);
|
||||||
ASSERT(this != kernel->currentThread);
|
ASSERT(this != kernel->currentThread);
|
||||||
if (stack != NULL)
|
if (stack != NULL)
|
||||||
DeallocBoundedArray((char *) stack, StackSize * sizeof(int));
|
DeallocBoundedArray((char *) stack, StackSize * sizeof(int));
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -91,17 +91,17 @@ Thread::~Thread()
|
|||||||
void
|
void
|
||||||
Thread::Fork(VoidFunctionPtr func, void *arg)
|
Thread::Fork(VoidFunctionPtr func, void *arg)
|
||||||
{
|
{
|
||||||
Interrupt *interrupt = kernel->interrupt;
|
Interrupt *interrupt = kernel->interrupt;
|
||||||
Scheduler *scheduler = kernel->scheduler;
|
Scheduler *scheduler = kernel->scheduler;
|
||||||
IntStatus oldLevel;
|
IntStatus oldLevel;
|
||||||
|
|
||||||
DEBUG(dbgThread, "Forking thread: " << name << " f(a): " << (int) func << " " << arg);
|
|
||||||
StackAllocate(func, arg);
|
|
||||||
|
|
||||||
oldLevel = interrupt->SetLevel(IntOff);
|
DEBUG(dbgThread, "Forking thread: " << name << " f(a): " << (int) func << " " << arg);
|
||||||
scheduler->ReadyToRun(this); // ReadyToRun assumes that interrupts
|
StackAllocate(func, arg);
|
||||||
// are disabled!
|
|
||||||
(void) interrupt->SetLevel(oldLevel);
|
oldLevel = interrupt->SetLevel(IntOff);
|
||||||
|
scheduler->ReadyToRun(this); // ReadyToRun assumes that interrupts
|
||||||
|
// are disabled!
|
||||||
|
(void) interrupt->SetLevel(oldLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -122,13 +122,13 @@ Thread::Fork(VoidFunctionPtr func, void *arg)
|
|||||||
void
|
void
|
||||||
Thread::CheckOverflow()
|
Thread::CheckOverflow()
|
||||||
{
|
{
|
||||||
if (stack != NULL) {
|
if (stack != NULL) {
|
||||||
#ifdef HPUX // Stacks grow upward on the Snakes
|
#ifdef HPUX // Stacks grow upward on the Snakes
|
||||||
ASSERT(stack[StackSize - 1] == STACK_FENCEPOST);
|
ASSERT(stack[StackSize - 1] == STACK_FENCEPOST);
|
||||||
#else
|
#else
|
||||||
ASSERT(*stack == STACK_FENCEPOST);
|
ASSERT(*stack == STACK_FENCEPOST);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -170,12 +170,12 @@ Thread::Begin ()
|
|||||||
void
|
void
|
||||||
Thread::Finish ()
|
Thread::Finish ()
|
||||||
{
|
{
|
||||||
(void) kernel->interrupt->SetLevel(IntOff);
|
(void) kernel->interrupt->SetLevel(IntOff);
|
||||||
ASSERT(this == kernel->currentThread);
|
ASSERT(this == kernel->currentThread);
|
||||||
|
|
||||||
DEBUG(dbgThread, "Finishing thread: " << name);
|
DEBUG(dbgThread, "Finishing thread: " << name);
|
||||||
Sleep(TRUE); // invokes SWITCH
|
Sleep(TRUE); // invokes SWITCH
|
||||||
// not reached
|
// not reached
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -200,19 +200,19 @@ Thread::Finish ()
|
|||||||
void
|
void
|
||||||
Thread::Yield ()
|
Thread::Yield ()
|
||||||
{
|
{
|
||||||
Thread *nextThread;
|
Thread *nextThread;
|
||||||
IntStatus oldLevel = kernel->interrupt->SetLevel(IntOff);
|
IntStatus oldLevel = kernel->interrupt->SetLevel(IntOff);
|
||||||
|
|
||||||
ASSERT(this == kernel->currentThread);
|
ASSERT(this == kernel->currentThread);
|
||||||
|
|
||||||
DEBUG(dbgThread, "Yielding thread: " << name);
|
DEBUG(dbgThread, "Yielding thread: " << name);
|
||||||
|
|
||||||
nextThread = kernel->scheduler->FindNextToRun();
|
nextThread = kernel->scheduler->FindNextToRun();
|
||||||
if (nextThread != NULL) {
|
if (nextThread != NULL) {
|
||||||
kernel->scheduler->ReadyToRun(this);
|
kernel->scheduler->ReadyToRun(this);
|
||||||
kernel->scheduler->Run(nextThread, FALSE);
|
kernel->scheduler->Run(nextThread, FALSE);
|
||||||
}
|
}
|
||||||
(void) kernel->interrupt->SetLevel(oldLevel);
|
(void) kernel->interrupt->SetLevel(oldLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -238,20 +238,20 @@ Thread::Yield ()
|
|||||||
void
|
void
|
||||||
Thread::Sleep (bool finishing)
|
Thread::Sleep (bool finishing)
|
||||||
{
|
{
|
||||||
Thread *nextThread;
|
Thread *nextThread;
|
||||||
|
|
||||||
ASSERT(this == kernel->currentThread);
|
|
||||||
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
|
||||||
|
|
||||||
DEBUG(dbgThread, "Sleeping thread: " << name);
|
|
||||||
|
|
||||||
status = BLOCKED;
|
ASSERT(this == kernel->currentThread);
|
||||||
//cout << "debug Thread::Sleep " << name << "wait for Idle\n";
|
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
||||||
while ((nextThread = kernel->scheduler->FindNextToRun()) == NULL) {
|
|
||||||
kernel->interrupt->Idle(); // no one to run, wait for an interrupt
|
DEBUG(dbgThread, "Sleeping thread: " << name);
|
||||||
}
|
|
||||||
// returns when it's time for us to run
|
status = BLOCKED;
|
||||||
kernel->scheduler->Run(nextThread, finishing);
|
//cout << "debug Thread::Sleep " << name << "wait for Idle\n";
|
||||||
|
while ((nextThread = kernel->scheduler->FindNextToRun()) == NULL) {
|
||||||
|
kernel->interrupt->Idle(); // no one to run, wait for an interrupt
|
||||||
|
}
|
||||||
|
// returns when it's time for us to run
|
||||||
|
kernel->scheduler->Run(nextThread, finishing);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -262,7 +262,7 @@ Thread::Sleep (bool finishing)
|
|||||||
// member function.
|
// member function.
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
static void ThreadFinish() { kernel->currentThread->Finish(); }
|
static void ThreadFinish() { kernel->currentThread->Finish(); }
|
||||||
static void ThreadBegin() { kernel->currentThread->Begin(); }
|
static void ThreadBegin() { kernel->currentThread->Begin(); }
|
||||||
void ThreadPrint(Thread *t) { t->Print(); }
|
void ThreadPrint(Thread *t) { t->Print(); }
|
||||||
|
|
||||||
@@ -277,16 +277,16 @@ void ThreadPrint(Thread *t) { t->Print(); }
|
|||||||
static void *
|
static void *
|
||||||
PLabelToAddr(void *plabel)
|
PLabelToAddr(void *plabel)
|
||||||
{
|
{
|
||||||
int funcPtr = (int) plabel;
|
int funcPtr = (int) plabel;
|
||||||
|
|
||||||
if (funcPtr & 0x02) {
|
if (funcPtr & 0x02) {
|
||||||
// L-Field is set. This is a PLT pointer
|
// L-Field is set. This is a PLT pointer
|
||||||
funcPtr -= 2; // Get rid of the L bit
|
funcPtr -= 2; // Get rid of the L bit
|
||||||
return (*(void **)funcPtr);
|
return (*(void **)funcPtr);
|
||||||
} else {
|
} else {
|
||||||
// L-field not set.
|
// L-field not set.
|
||||||
return plabel;
|
return plabel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -305,59 +305,59 @@ PLabelToAddr(void *plabel)
|
|||||||
void
|
void
|
||||||
Thread::StackAllocate (VoidFunctionPtr func, void *arg)
|
Thread::StackAllocate (VoidFunctionPtr func, void *arg)
|
||||||
{
|
{
|
||||||
stack = (int *) AllocBoundedArray(StackSize * sizeof(int));
|
stack = (int *) AllocBoundedArray(StackSize * sizeof(int));
|
||||||
|
|
||||||
#ifdef PARISC
|
#ifdef PARISC
|
||||||
// HP stack works from low addresses to high addresses
|
// HP stack works from low addresses to high addresses
|
||||||
// everyone else works the other way: from high addresses to low addresses
|
// everyone else works the other way: from high addresses to low addresses
|
||||||
stackTop = stack + 16; // HP requires 64-byte frame marker
|
stackTop = stack + 16; // HP requires 64-byte frame marker
|
||||||
stack[StackSize - 1] = STACK_FENCEPOST;
|
stack[StackSize - 1] = STACK_FENCEPOST;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SPARC
|
#ifdef SPARC
|
||||||
stackTop = stack + StackSize - 96; // SPARC stack must contains at
|
stackTop = stack + StackSize - 96; // SPARC stack must contains at
|
||||||
// least 1 activation record
|
// least 1 activation record
|
||||||
// to start with.
|
// to start with.
|
||||||
*stack = STACK_FENCEPOST;
|
*stack = STACK_FENCEPOST;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PowerPC // RS6000
|
#ifdef PowerPC // RS6000
|
||||||
stackTop = stack + StackSize - 16; // RS6000 requires 64-byte frame marker
|
stackTop = stack + StackSize - 16; // RS6000 requires 64-byte frame marker
|
||||||
*stack = STACK_FENCEPOST;
|
*stack = STACK_FENCEPOST;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DECMIPS
|
#ifdef DECMIPS
|
||||||
stackTop = stack + StackSize - 4; // -4 to be on the safe side!
|
stackTop = stack + StackSize - 4; // -4 to be on the safe side!
|
||||||
*stack = STACK_FENCEPOST;
|
*stack = STACK_FENCEPOST;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ALPHA
|
#ifdef ALPHA
|
||||||
stackTop = stack + StackSize - 8; // -8 to be on the safe side!
|
stackTop = stack + StackSize - 8; // -8 to be on the safe side!
|
||||||
*stack = STACK_FENCEPOST;
|
*stack = STACK_FENCEPOST;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef x86
|
#ifdef x86
|
||||||
// the x86 passes the return address on the stack. In order for SWITCH()
|
// the x86 passes the return address on the stack. In order for SWITCH()
|
||||||
// to go to ThreadRoot when we switch to this thread, the return addres
|
// to go to ThreadRoot when we switch to this thread, the return addres
|
||||||
// used in SWITCH() must be the starting address of ThreadRoot.
|
// used in SWITCH() must be the starting address of ThreadRoot.
|
||||||
stackTop = stack + StackSize - 4; // -4 to be on the safe side!
|
stackTop = stack + StackSize - 4; // -4 to be on the safe side!
|
||||||
*(--stackTop) = (int) ThreadRoot;
|
*(--stackTop) = (int) ThreadRoot;
|
||||||
*stack = STACK_FENCEPOST;
|
*stack = STACK_FENCEPOST;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PARISC
|
#ifdef PARISC
|
||||||
machineState[PCState] = PLabelToAddr(ThreadRoot);
|
machineState[PCState] = PLabelToAddr(ThreadRoot);
|
||||||
machineState[StartupPCState] = PLabelToAddr(ThreadBegin);
|
machineState[StartupPCState] = PLabelToAddr(ThreadBegin);
|
||||||
machineState[InitialPCState] = PLabelToAddr(func);
|
machineState[InitialPCState] = PLabelToAddr(func);
|
||||||
machineState[InitialArgState] = arg;
|
machineState[InitialArgState] = arg;
|
||||||
machineState[WhenDonePCState] = PLabelToAddr(ThreadFinish);
|
machineState[WhenDonePCState] = PLabelToAddr(ThreadFinish);
|
||||||
#else
|
#else
|
||||||
machineState[PCState] = (void*)ThreadRoot;
|
machineState[PCState] = (void*)ThreadRoot;
|
||||||
machineState[StartupPCState] = (void*)ThreadBegin;
|
machineState[StartupPCState] = (void*)ThreadBegin;
|
||||||
machineState[InitialPCState] = (void*)func;
|
machineState[InitialPCState] = (void*)func;
|
||||||
machineState[InitialArgState] = (void*)arg;
|
machineState[InitialArgState] = (void*)arg;
|
||||||
machineState[WhenDonePCState] = (void*)ThreadFinish;
|
machineState[WhenDonePCState] = (void*)ThreadFinish;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,8 +391,8 @@ Thread::SaveUserState()
|
|||||||
void
|
void
|
||||||
Thread::RestoreUserState()
|
Thread::RestoreUserState()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NumTotalRegs; i++)
|
for (int i = 0; i < NumTotalRegs; i++)
|
||||||
kernel->machine->WriteRegister(i, userRegisters[i]);
|
kernel->machine->WriteRegister(i, userRegisters[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,32 +31,97 @@
|
|||||||
static void
|
static void
|
||||||
SwapHeader (NoffHeader *noffH)
|
SwapHeader (NoffHeader *noffH)
|
||||||
{
|
{
|
||||||
noffH->noffMagic = WordToHost(noffH->noffMagic);
|
noffH->noffMagic = WordToHost(noffH->noffMagic);
|
||||||
noffH->code.size = WordToHost(noffH->code.size);
|
noffH->code.size = WordToHost(noffH->code.size);
|
||||||
noffH->code.virtualAddr = WordToHost(noffH->code.virtualAddr);
|
noffH->code.virtualAddr = WordToHost(noffH->code.virtualAddr);
|
||||||
noffH->code.inFileAddr = WordToHost(noffH->code.inFileAddr);
|
noffH->code.inFileAddr = WordToHost(noffH->code.inFileAddr);
|
||||||
#ifdef RDATA
|
#ifdef RDATA
|
||||||
noffH->readonlyData.size = WordToHost(noffH->readonlyData.size);
|
noffH->readonlyData.size = WordToHost(noffH->readonlyData.size);
|
||||||
noffH->readonlyData.virtualAddr =
|
noffH->readonlyData.virtualAddr =
|
||||||
WordToHost(noffH->readonlyData.virtualAddr);
|
WordToHost(noffH->readonlyData.virtualAddr);
|
||||||
noffH->readonlyData.inFileAddr =
|
noffH->readonlyData.inFileAddr =
|
||||||
WordToHost(noffH->readonlyData.inFileAddr);
|
WordToHost(noffH->readonlyData.inFileAddr);
|
||||||
#endif
|
#endif
|
||||||
noffH->initData.size = WordToHost(noffH->initData.size);
|
noffH->initData.size = WordToHost(noffH->initData.size);
|
||||||
noffH->initData.virtualAddr = WordToHost(noffH->initData.virtualAddr);
|
noffH->initData.virtualAddr = WordToHost(noffH->initData.virtualAddr);
|
||||||
noffH->initData.inFileAddr = WordToHost(noffH->initData.inFileAddr);
|
noffH->initData.inFileAddr = WordToHost(noffH->initData.inFileAddr);
|
||||||
noffH->uninitData.size = WordToHost(noffH->uninitData.size);
|
noffH->uninitData.size = WordToHost(noffH->uninitData.size);
|
||||||
noffH->uninitData.virtualAddr = WordToHost(noffH->uninitData.virtualAddr);
|
noffH->uninitData.virtualAddr = WordToHost(noffH->uninitData.virtualAddr);
|
||||||
noffH->uninitData.inFileAddr = WordToHost(noffH->uninitData.inFileAddr);
|
noffH->uninitData.inFileAddr = WordToHost(noffH->uninitData.inFileAddr);
|
||||||
|
|
||||||
#ifdef RDATA
|
#ifdef RDATA
|
||||||
DEBUG(dbgAddr, "code = " << noffH->code.size <<
|
DEBUG(dbgAddr, "code = " << noffH->code.size <<
|
||||||
" readonly = " << noffH->readonlyData.size <<
|
" readonly = " << noffH->readonlyData.size <<
|
||||||
" init = " << noffH->initData.size <<
|
" init = " << noffH->initData.size <<
|
||||||
" uninit = " << noffH->uninitData.size << "\n");
|
" uninit = " << noffH->uninitData.size << "\n");
|
||||||
#endif
|
#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
|
// AddrSpace::AddrSpace
|
||||||
// Create an address space to run a user program.
|
// Create an address space to run a user program.
|
||||||
@@ -66,20 +131,7 @@ SwapHeader (NoffHeader *noffH)
|
|||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
AddrSpace::AddrSpace()
|
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
|
// AddrSpace::~AddrSpace
|
||||||
@@ -88,7 +140,10 @@ AddrSpace::AddrSpace()
|
|||||||
|
|
||||||
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
|
bool
|
||||||
AddrSpace::Load(char *fileName)
|
AddrSpace::Load(char *fileName)
|
||||||
{
|
{
|
||||||
OpenFile *executable = kernel->fileSystem->Open(fileName);
|
//cerr << "AddrSpace::Load" << endl;
|
||||||
NoffHeader noffH;
|
OpenFile *executable = kernel->fileSystem->Open(fileName);
|
||||||
unsigned int size;
|
NoffHeader noffH;
|
||||||
|
unsigned int size;
|
||||||
|
|
||||||
if (executable == NULL) {
|
if (executable == NULL) {
|
||||||
cerr << "Unable to open file " << fileName << "\n";
|
cerr << "Unable to open file " << fileName << "\n";
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
executable->ReadAt((char *)&noffH, sizeof(noffH), 0);
|
executable->ReadAt((char *)&noffH, sizeof(noffH), 0);
|
||||||
if ((noffH.noffMagic != NOFFMAGIC) &&
|
if ((noffH.noffMagic != NOFFMAGIC) &&
|
||||||
(WordToHost(noffH.noffMagic) == NOFFMAGIC))
|
(WordToHost(noffH.noffMagic) == NOFFMAGIC))
|
||||||
SwapHeader(&noffH);
|
SwapHeader(&noffH);
|
||||||
ASSERT(noffH.noffMagic == NOFFMAGIC);
|
ASSERT(noffH.noffMagic == NOFFMAGIC);
|
||||||
|
|
||||||
#ifdef RDATA
|
#ifdef RDATA
|
||||||
// how big is address space?
|
// how big is address space?
|
||||||
size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size +
|
size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size +
|
||||||
noffH.uninitData.size + UserStackSize;
|
noffH.uninitData.size + UserStackSize;
|
||||||
// we need to increase the size
|
//cerr << noffH.code.size << ' '
|
||||||
// to leave room for the stack
|
// << noffH.readonlyData.size << ' '
|
||||||
|
// << noffH.initData.size << ' '
|
||||||
|
// << noffH.uninitData.size << ' '
|
||||||
|
// << UserStackSize << endl;
|
||||||
|
// we need to increase the size
|
||||||
|
// to leave room for the stack
|
||||||
#else
|
#else
|
||||||
// how big is address space?
|
// how big is address space?
|
||||||
size = noffH.code.size + noffH.initData.size + noffH.uninitData.size
|
size = noffH.code.size + noffH.initData.size + noffH.uninitData.size
|
||||||
+ UserStackSize; // we need to increase the size
|
+ UserStackSize; // we need to increase the size
|
||||||
// to leave room for the stack
|
// to leave room for the stack
|
||||||
|
//cerr << noffH.code.size << ' '
|
||||||
|
// << noffH.initData.size << ' '
|
||||||
|
// << noffH.uninitData.size << ' '
|
||||||
|
// << UserStackSize << endl;
|
||||||
#endif
|
#endif
|
||||||
numPages = divRoundUp(size, PageSize);
|
numPages = divRoundUp(size, PageSize);
|
||||||
size = numPages * PageSize;
|
size = numPages * PageSize;
|
||||||
|
|
||||||
ASSERT(numPages <= NumPhysPages); // check we're not trying
|
ASSERT(numPages <= NumPhysPages); // check we're not trying
|
||||||
// to run anything too big --
|
// to run anything too big --
|
||||||
// at least until we have
|
// at least until we have
|
||||||
// virtual memory
|
// 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
|
// then, copy in the code and data segments into memory
|
||||||
// Note: this code assumes that virtual address = physical address
|
if (noffH.code.size > 0) {
|
||||||
if (noffH.code.size > 0) {
|
DEBUG(dbgAddr, "Initializing code segment.");
|
||||||
DEBUG(dbgAddr, "Initializing code segment.");
|
DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size);
|
||||||
DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size);
|
|
||||||
executable->ReadAt(
|
for (size_t cur = 0; cur < (size_t)noffH.code.size; cur += PageSize) {
|
||||||
&(kernel->machine->mainMemory[noffH.code.virtualAddr]),
|
size_t physAddr, size = min((size_t)PageSize, noffH.code.size - cur);
|
||||||
noffH.code.size, noffH.code.inFileAddr);
|
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.");
|
if (noffH.initData.size > 0) {
|
||||||
DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size);
|
DEBUG(dbgAddr, "Initializing data segment.");
|
||||||
executable->ReadAt(
|
DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size);
|
||||||
&(kernel->machine->mainMemory[noffH.initData.virtualAddr]),
|
|
||||||
noffH.initData.size, noffH.initData.inFileAddr);
|
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
|
#ifdef RDATA
|
||||||
if (noffH.readonlyData.size > 0) {
|
if (noffH.readonlyData.size > 0) {
|
||||||
DEBUG(dbgAddr, "Initializing read only data segment.");
|
DEBUG(dbgAddr, "Initializing read only data segment.");
|
||||||
DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size);
|
DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size);
|
||||||
executable->ReadAt(
|
|
||||||
&(kernel->machine->mainMemory[noffH.readonlyData.virtualAddr]),
|
for (size_t cur = 0; cur < (size_t)noffH.readonlyData.size; cur += PageSize) {
|
||||||
noffH.readonlyData.size, noffH.readonlyData.inFileAddr);
|
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
|
#endif
|
||||||
|
|
||||||
delete executable; // close file
|
delete executable; // close file
|
||||||
return TRUE; // success
|
return TRUE; // success
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -185,17 +278,17 @@ AddrSpace::Load(char *fileName)
|
|||||||
void
|
void
|
||||||
AddrSpace::Execute(char* fileName)
|
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
|
kernel->machine->Run(); // jump to the user progam
|
||||||
this->RestoreState(); // load page table register
|
|
||||||
|
|
||||||
kernel->machine->Run(); // jump to the user progam
|
ASSERTNOTREACHED(); // machine->Run never returns;
|
||||||
|
// the address space exits
|
||||||
ASSERTNOTREACHED(); // machine->Run never returns;
|
// by doing the syscall "exit"
|
||||||
// the address space exits
|
|
||||||
// by doing the syscall "exit"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -212,27 +305,27 @@ AddrSpace::Execute(char* fileName)
|
|||||||
void
|
void
|
||||||
AddrSpace::InitRegisters()
|
AddrSpace::InitRegisters()
|
||||||
{
|
{
|
||||||
Machine *machine = kernel->machine;
|
Machine *machine = kernel->machine;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < NumTotalRegs; i++)
|
for (i = 0; i < NumTotalRegs; i++)
|
||||||
machine->WriteRegister(i, 0);
|
machine->WriteRegister(i, 0);
|
||||||
|
|
||||||
// Initial program counter -- must be location of "Start", which
|
// Initial program counter -- must be location of "Start", which
|
||||||
// is assumed to be virtual address zero
|
// is assumed to be virtual address zero
|
||||||
machine->WriteRegister(PCReg, 0);
|
machine->WriteRegister(PCReg, 0);
|
||||||
|
|
||||||
// Need to also tell MIPS where next instruction is, because
|
// Need to also tell MIPS where next instruction is, because
|
||||||
// of branch delay possibility
|
// of branch delay possibility
|
||||||
// Since instructions occupy four bytes each, the next instruction
|
// Since instructions occupy four bytes each, the next instruction
|
||||||
// after start will be at virtual address four.
|
// after start will be at virtual address four.
|
||||||
machine->WriteRegister(NextPCReg, 4);
|
machine->WriteRegister(NextPCReg, 4);
|
||||||
|
|
||||||
// Set the stack register to the end of the address space, where we
|
// 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
|
// allocated the stack; but subtract off a bit, to make sure we don't
|
||||||
// accidentally reference off the end!
|
// accidentally reference off the end!
|
||||||
machine->WriteRegister(StackReg, numPages * PageSize - 16);
|
machine->WriteRegister(StackReg, numPages * PageSize - 16);
|
||||||
DEBUG(dbgAddr, "Initializing stack pointer: " << numPages * PageSize - 16);
|
DEBUG(dbgAddr, "Initializing stack pointer: " << numPages * PageSize - 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -256,8 +349,8 @@ void AddrSpace::SaveState()
|
|||||||
|
|
||||||
void AddrSpace::RestoreState()
|
void AddrSpace::RestoreState()
|
||||||
{
|
{
|
||||||
kernel->machine->pageTable = pageTable;
|
kernel->machine->pageTable = pageTable;
|
||||||
kernel->machine->pageTableSize = numPages;
|
kernel->machine->pageTableSize = numPages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -272,45 +365,48 @@ void AddrSpace::RestoreState()
|
|||||||
ExceptionType
|
ExceptionType
|
||||||
AddrSpace::Translate(unsigned int vaddr, unsigned int *paddr, int isReadWrite)
|
AddrSpace::Translate(unsigned int vaddr, unsigned int *paddr, int isReadWrite)
|
||||||
{
|
{
|
||||||
TranslationEntry *pte;
|
TranslationEntry *pte;
|
||||||
int pfn;
|
int pfn;
|
||||||
unsigned int vpn = vaddr / PageSize;
|
unsigned int vpn = vaddr / PageSize;
|
||||||
unsigned int offset = vaddr % PageSize;
|
unsigned int offset = vaddr % PageSize;
|
||||||
|
|
||||||
if(vpn >= numPages) {
|
if(vpn >= numPages) {
|
||||||
return AddressErrorException;
|
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) {
|
pte->use = TRUE; // set the use, dirty bits
|
||||||
return ReadOnlyException;
|
|
||||||
}
|
|
||||||
|
|
||||||
pfn = pte->physicalPage;
|
if(isReadWrite)
|
||||||
|
pte->dirty = TRUE;
|
||||||
|
|
||||||
// if the pageFrame is too big, there is something really wrong!
|
*paddr = pfn * PageSize + offset;
|
||||||
// An invalid translation was loaded into the page table or TLB.
|
|
||||||
if (pfn >= NumPhysPages) {
|
|
||||||
DEBUG(dbgAddr, "Illegal physical page " << pfn);
|
|
||||||
return BusErrorException;
|
|
||||||
}
|
|
||||||
|
|
||||||
pte->use = TRUE; // set the use, dirty bits
|
ASSERT((*paddr < MemorySize));
|
||||||
|
|
||||||
if(isReadWrite)
|
//cerr << " -- AddrSpace::Translate(): vaddr: " << vaddr <<
|
||||||
pte->dirty = TRUE;
|
// ", paddr: " << *paddr << "\n";
|
||||||
|
|
||||||
*paddr = pfn*PageSize + offset;
|
return NoException;
|
||||||
|
|
||||||
ASSERT((*paddr < MemorySize));
|
|
||||||
|
|
||||||
//cerr << " -- AddrSpace::Translate(): vaddr: " << vaddr <<
|
|
||||||
// ", paddr: " << *paddr << "\n";
|
|
||||||
|
|
||||||
return NoException;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,28 @@
|
|||||||
|
|
||||||
#define UserStackSize 1024 // increase this as necessary!
|
#define UserStackSize 1024 // increase this as necessary!
|
||||||
|
|
||||||
|
class FrameTable {
|
||||||
|
public:
|
||||||
|
FrameTable();
|
||||||
|
~FrameTable();
|
||||||
|
|
||||||
|
int Allocate();
|
||||||
|
void Release(int phyPageNum);
|
||||||
|
size_t RemainSize();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Node {
|
||||||
|
Node *next;
|
||||||
|
int idx;
|
||||||
|
Node(int idx = -1);
|
||||||
|
};
|
||||||
|
|
||||||
|
Node *begin, *end;
|
||||||
|
|
||||||
|
size_t available;
|
||||||
|
int *useCount;
|
||||||
|
};
|
||||||
|
|
||||||
class AddrSpace {
|
class AddrSpace {
|
||||||
public:
|
public:
|
||||||
AddrSpace(); // Create an address space.
|
AddrSpace(); // Create an address space.
|
||||||
@@ -40,8 +62,7 @@ class AddrSpace {
|
|||||||
ExceptionType Translate(unsigned int vaddr, unsigned int *paddr, int mode);
|
ExceptionType Translate(unsigned int vaddr, unsigned int *paddr, int mode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TranslationEntry *pageTable; // Assume linear page table translation
|
TranslationEntry *pageTable;
|
||||||
// for now!
|
|
||||||
unsigned int numPages; // Number of pages in the virtual
|
unsigned int numPages; // Number of pages in the virtual
|
||||||
// address space
|
// address space
|
||||||
|
|
||||||
|
|||||||
@@ -109,10 +109,10 @@ SynchConsoleOutput::PutChar(char ch)
|
|||||||
void
|
void
|
||||||
SynchConsoleOutput::PutInt(int value)
|
SynchConsoleOutput::PutInt(int value)
|
||||||
{
|
{
|
||||||
lock->Acquire();
|
lock->Acquire();
|
||||||
consoleOutput->PutInt(value);
|
consoleOutput->PutInt(value);
|
||||||
waitFor->P();
|
waitFor->P();
|
||||||
lock->Release();
|
lock->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user