Merge branch 'ytshih/hw2' into 'main'

Ytshih/hw2

See merge request cs_os_group_20/cs_os_project_20_hw!2
This commit is contained in:
Yi-Ting Shih
2024-11-02 07:58:12 +08:00
24 changed files with 752 additions and 4283 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
*.o *.o
*.coff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

@@ -0,0 +1,6 @@
#include "syscall.h"
int main()
{
Exit(0);
}

View File

@@ -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++) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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