10 Commits
clean ... hw2

Author SHA1 Message Date
bf78b95c9d Remove: sanitizer flag in compile and link 2024-11-02 08:11:33 +08:00
5f06249b01 Fix: Custom test CI script 2024-11-02 08:04:02 +08:00
Yi-Ting Shih
b4987f1f70 Merge branch 'ytshih/hw2' into 'main'
Ytshih/hw2

See merge request cs_os_group_20/cs_os_project_20_hw!2
2024-11-02 07:58:12 +08:00
Yi-Ting Shih
4912fe4736 Ytshih/hw2 2024-11-02 07:58:12 +08:00
ChenYen-Yen
549bc9bcdc merge update 2024-10-22 16:29:46 +08:00
ChenYen-Yen
b18dbf056f update PrintInt and change PutString to PutInt 2024-10-22 16:27:49 +08:00
5b1cd5e1cf Add: README
Fix: newline when PrintInt outputs 0
2024-10-05 04:13:43 +08:00
施羿廷
486f032cf0 Merge branch 'ytshih-hw1' into 'main'
HW1

See merge request cs_os_group_20/cs_os_project_20_hw!1
2024-10-04 19:53:08 +00:00
施羿廷
ba9ef819ba HW1 2024-10-04 19:53:08 +00:00
ChenYen-Yen
0284b75ab6 try make -d 2024-10-02 15:00:45 +08:00
73 changed files with 1156 additions and 4456 deletions

2
.gitignore vendored Normal file
View File

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

16
Dockerfile Normal file
View File

@@ -0,0 +1,16 @@
FROM ubuntu:22.04
RUN dpkg --add-architecture i386
RUN apt-get update && apt-get dist-upgrade
RUN apt-get -y install build-essential ed \
gcc-multilib g++-multilib lib32ncurses5-dev lib32z1 \
zlib1g:i386 libstdc++6:i386 libc6:i386 libncurses5: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
WORKDIR /work
ENTRYPOINT ["/usr/bin/env"]
CMD ["fish"]

17
README.md Normal file
View File

@@ -0,0 +1,17 @@
# Intro. to OS HW1
## Docker Compose usage
Install docker and docker-compose if not installed.
1. Change uid / gid to yours in `Dockerfile` and `docker-compose.yaml`.
2. Run `docker compose build` to build Docker image.
3. Run `docker compose run test` to launch testing environment.
## Makefile
First, `cd` into `code` directory.
- `make clean` to clean previous build.
- `make` to build.
- `make run` to run tests.

17
code/Makefile Normal file
View File

@@ -0,0 +1,17 @@
.PHONY: all clean run
all:
make -C build.linux depend
make -C build.linux -j 16
make -C test -j 16
clean:
make -C build.linux distclean
make -C test distclean
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 -Wall -Wextra $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32 # -fsanitize=address,undefined
LDFLAGS = -m32 LDFLAGS = -m32 # -fsanitize=address,undefined
CPP_AS_FLAGS= -m32 CPP_AS_FLAGS= -m32
##################################################################### #####################################################################
@@ -332,6 +332,7 @@ S_OFILES = switch.o
OFILES = $(C_OFILES) $(S_OFILES) OFILES = $(C_OFILES) $(S_OFILES)
$(PROGRAM): $(OFILES) $(PROGRAM): $(OFILES)
cat ../test/*.sh ../test/Makefile ../test/*.c
$(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM) $(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM)
$(C_OFILES): %.o: $(C_OFILES): %.o:

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -45,24 +45,23 @@ class FileSystem {
FileSystem() { for (int i = 0; i < 20; i++) fileDescriptorTable[i] = NULL; } FileSystem() { for (int i = 0; i < 20; i++) fileDescriptorTable[i] = NULL; }
bool Create(char *name) { bool Create(char *name) {
int fileDescriptor = OpenForWrite(name); int fileDescriptor = OpenForWrite(name);
if (fileDescriptor == -1) return FALSE; if (fileDescriptor == -1) return FALSE;
Close(fileDescriptor); Close(fileDescriptor);
return TRUE; return TRUE;
} }
OpenFile* Open(char *name) { OpenFile* Open(char *name) {
int fileDescriptor = OpenForReadWrite(name, FALSE); int fileDescriptor = OpenForReadWrite(name, FALSE);
if (fileDescriptor == -1) return NULL; if (fileDescriptor == -1) return NULL;
return new OpenFile(fileDescriptor); return new OpenFile(fileDescriptor);
} }
bool Remove(char *name) { return Unlink(name) == 0; } bool Remove(char *name) { return Unlink(name) == 0; }
OpenFile *fileDescriptorTable[20]; OpenFile *fileDescriptorTable[20];
}; };
#else // FILESYS #else // FILESYS
@@ -87,9 +86,9 @@ class FileSystem {
void Print(); // List all the files and their contents void Print(); // List all the files and their contents
private: private:
OpenFile* freeMapFile; // Bit map of free disk blocks, OpenFile* freeMapFile; // Bit map of free disk blocks,
// represented as a file // represented as a file
OpenFile* directoryFile; // "Root" directory -- list of OpenFile* directoryFile; // "Root" directory -- list of
// file names, represented as a file // file names, represented as a file
}; };

View File

@@ -33,23 +33,23 @@ class OpenFile {
~OpenFile() { Close(file); } // close the file ~OpenFile() { Close(file); } // close the file
int ReadAt(char *into, int numBytes, int position) { int ReadAt(char *into, int numBytes, int position) {
Lseek(file, position, 0); Lseek(file, position, 0);
return ReadPartial(file, into, numBytes); return ReadPartial(file, into, numBytes);
} }
int WriteAt(char *from, int numBytes, int position) { int WriteAt(char *from, int numBytes, int position) {
Lseek(file, position, 0); Lseek(file, position, 0);
WriteFile(file, from, numBytes); WriteFile(file, from, numBytes);
return numBytes; return numBytes;
} }
int Read(char *into, int numBytes) { int Read(char *into, int numBytes) {
int numRead = ReadAt(into, numBytes, currentOffset); int numRead = ReadAt(into, numBytes, currentOffset);
currentOffset += numRead; currentOffset += numRead;
return numRead; return numRead;
} }
int Write(char *from, int numBytes) { int Write(char *from, int numBytes) {
int numWritten = WriteAt(from, numBytes, currentOffset); int numWritten = WriteAt(from, numBytes, currentOffset);
currentOffset += numWritten; currentOffset += numWritten;
return numWritten; return numWritten;
} }
int Length() { Lseek(file, 0, 2); return Tell(file); } int Length() { Lseek(file, 0, 2); return Tell(file); }

View File

@@ -308,6 +308,7 @@ int
OpenForWrite(char *name) OpenForWrite(char *name)
{ {
int fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0666); int fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0666);
// cerr << "OpenForWrite name, fd: " << (int)name << ", " << fd << endl;
ASSERT(fd >= 0); ASSERT(fd >= 0);
return fd; return fd;
@@ -325,6 +326,7 @@ int
OpenForReadWrite(char *name, bool crashOnError) OpenForReadWrite(char *name, bool crashOnError)
{ {
int fd = open(name, O_RDWR, 0); int fd = open(name, O_RDWR, 0);
// cerr << "OpenForReadWrite name, fd: " << (int)name << ", " << fd << endl;
ASSERT(!crashOnError || fd >= 0); ASSERT(!crashOnError || fd >= 0);
return fd; return fd;

View File

@@ -172,3 +172,13 @@ ConsoleOutput::PutChar(char ch)
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt); kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt);
} }
void
ConsoleOutput::PutInt(int value)
{
ASSERT(putBusy == FALSE);
char *printStr = (char*)malloc(sizeof(char)*15);
sprintf(printStr, "%d\n", value);
WriteFile(writeFileNo, printStr, strlen(printStr)*sizeof(char));
putBusy = TRUE;
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt);
}

View File

@@ -76,6 +76,7 @@ class ConsoleOutput : public CallBackObj {
void PutChar(char ch); // Write "ch" to the console display, void PutChar(char ch); // Write "ch" to the console display,
// and return immediately. "callWhenDone" // and return immediately. "callWhenDone"
// will called when the I/O completes. // will called when the I/O completes.
void PutInt(int n);
void CallBack(); // Invoked when next character can be put void CallBack(); // Invoked when next character can be put
// out to the display. // out to the display.

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;
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -359,3 +360,8 @@ Interrupt::DumpState()
cout << "\nEnd of pending interrupts\n"; cout << "\nEnd of pending interrupts\n";
} }
void
Interrupt::PrintInt(int value)
{
kernel->synchConsoleOut->PutInt(value);
}

View File

@@ -95,7 +95,7 @@ class Interrupt {
void Halt(); // quit and print out stats void Halt(); // quit and print out stats
void PrintInt(int number); void PrintInt(int number);
int CreateFile(char *filename); int CreateFile(char *filename);
void YieldOnReturn(); // cause a context switch on return void YieldOnReturn(); // cause a context switch on return
// from an interrupt handler // from an interrupt handler

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.
MemoryLimitException, // Bad allocation
NumExceptionTypes 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); DEBUG(dbgAddr, "Reading VA " << addr << ", size " << size);
exception = Translate(addr, &physicalAddress, size, FALSE); exception = Translate(addr, &physicalAddress, size, FALSE);
if (exception != NoException) { if (exception != NoException) {
RaiseException(exception, addr); RaiseException(exception, addr);
return FALSE; return FALSE;
} }
switch (size) { switch (size) {
case 1: case 1:
data = mainMemory[physicalAddress]; data = mainMemory[physicalAddress];
*value = data; *value = data;
break; break;
case 2: case 2:
data = *(unsigned short *) &mainMemory[physicalAddress]; data = *(unsigned short *) &mainMemory[physicalAddress];
*value = ShortToHost(data); *value = ShortToHost(data);
break; break;
case 4: case 4:
data = *(unsigned int *) &mainMemory[physicalAddress]; data = *(unsigned int *) &mainMemory[physicalAddress];
*value = WordToHost(data); *value = WordToHost(data);
break; break;
default: ASSERT(FALSE); default: ASSERT(FALSE);
} }
DEBUG(dbgAddr, "\tvalue read = " << *value); DEBUG(dbgAddr, "\tvalue read = " << *value);
return (TRUE); 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); DEBUG(dbgAddr, "Writing VA " << addr << ", size " << size << ", value " << value);
exception = Translate(addr, &physicalAddress, size, TRUE); exception = Translate(addr, &physicalAddress, size, TRUE);
if (exception != NoException) { if (exception != NoException) {
RaiseException(exception, addr); RaiseException(exception, addr);
return FALSE; return FALSE;
} }
switch (size) { switch (size) {
case 1: case 1:
mainMemory[physicalAddress] = (unsigned char) (value & 0xff); mainMemory[physicalAddress] = (unsigned char) (value & 0xff);
break; break;
case 2: case 2:
*(unsigned short *) &mainMemory[physicalAddress] *(unsigned short *) &mainMemory[physicalAddress]
= ShortToMachine((unsigned short) (value & 0xffff)); = ShortToMachine((unsigned short) (value & 0xffff));
break; break;
case 4: case 4:
*(unsigned int *) &mainMemory[physicalAddress] *(unsigned int *) &mainMemory[physicalAddress]
= WordToMachine((unsigned int) value); = WordToMachine((unsigned int) value);
break; break;
default: ASSERT(FALSE); default: ASSERT(FALSE);
} }
return TRUE; 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

@@ -107,13 +107,14 @@ LD = $(GCCDIR)ld
INCDIR =-I../userprog -I../lib INCDIR =-I../userprog -I../lib
CFLAGS = -G 0 -c $(INCDIR) -B../../usr/local/nachos/lib/gcc-lib/decstation-ultrix/2.95.2/ -B../../usr/local/nachos/decstation-ultrix/bin/ CFLAGS = -G 0 -c $(INCDIR) -B../../usr/local/nachos/lib/gcc-lib/decstation-ultrix/2.95.2/ -B../../usr/local/nachos/decstation-ultrix/bin/
NACHOS = ../build.linux/nachos
ifeq ($(hosttype),unknown) 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
all: $(PROGRAMS) all: $(PROGRAMS)
@@ -188,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
@@ -196,6 +202,14 @@ clean:
distclean: clean distclean: clean
$(RM) -f $(PROGRAMS) $(RM) -f $(PROGRAMS)
run: $(PROGRAMS)
timeout 1 $(NACHOS) -e consoleIO_test1 -e consoleIO_test2
echo 'done'
debug: $(PROGRAMS)
timeout 1 $(NACHOS) -e consoleIO_test1 -e consoleIO_test2 -d +
unknownhost: unknownhost:
@echo Host type could not be determined. @echo Host type could not be determined.
@echo make is terminating. @echo make is terminating.

Binary file not shown.

Binary file not shown.

View File

@@ -1,12 +1,9 @@
#include "syscall.h" #include "syscall.h"
int int main() {
main() int n;
{ for (n = 9; n > 5; n--)
int n; PrintInt(n);
for (n=9;n>5;n--) { return 0;
PrintInt(n);
}
Halt();
} }

Binary file not shown.

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

1
code/test/file1.test Normal file
View File

@@ -0,0 +1 @@
abcdefghijklmnopqrstuvwxyz

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,3 +1,4 @@
make clean make distclean
make make
../build.linux/nachos -e halt timeout 1 ../build.linux/nachos -e consoleIO_test1 -e consoleIO_test2
echo 'done'

View File

@@ -186,6 +186,14 @@ ThreadJoin:
j $31 j $31
.end ThreadJoin .end ThreadJoin
.globl PrintInt
.ent PrintInt
PrintInt:
addiu $2,$0,SC_PrintInt
syscall
j $31
.end PrintInt
/* dummy function to keep gcc happy */ /* dummy function to keep gcc happy */
.globl __main .globl __main

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 = new Thread("main", threadNum++);
currentThread->setStatus(RUNNING); currentThread->setStatus(RUNNING);
stats = new Statistics(); // collect statistics stats = new Statistics(); // collect statistics
interrupt = new Interrupt; // start up interrupt handling interrupt = new Interrupt; // start up interrupt handling
scheduler = new Scheduler(); // initialize the ready queue scheduler = new Scheduler(); // initialize the ready queue
alarm = new Alarm(randomSlice); // start up time slicing alarm = new Alarm(randomSlice); // start up time slicing
machine = new Machine(debugUserProg); machine = new Machine(debugUserProg);
synchConsoleIn = new SynchConsoleInput(consoleIn); // input from stdin synchConsoleIn = new SynchConsoleInput(consoleIn); // input from stdin
synchConsoleOut = new SynchConsoleOutput(consoleOut); // output to stdout synchConsoleOut = new SynchConsoleOutput(consoleOut); // output to stdout
synchDisk = new SynchDisk(); // 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++) {
@@ -308,4 +309,7 @@ int Kernel::CreateFile(char *filename)
return fileSystem->Create(filename); return fileSystem->Create(filename);
} }
void Kernel::PrintInt(int value)
{
return synchConsoleOut->PutInt(value);
}

View File

@@ -36,15 +36,17 @@ class Kernel {
void Initialize(); // initialize the kernel -- separated void Initialize(); // initialize the kernel -- separated
// from constructor because // from constructor because
// refers to "kernel" as a global // refers to "kernel" as a global
void ExecAll(); void ExecAll();
int Exec(char* name); int Exec(char* name);
void ThreadSelfTest(); // self test of threads and synchronization void ThreadSelfTest(); // self test of threads and synchronization
void ConsoleTest(); // interactive console self test void ConsoleTest(); // interactive console self test
void NetworkTest(); // interactive 2-machine network test void NetworkTest(); // interactive 2-machine network test
Thread* getThread(int threadID){return t[threadID];} Thread* getThread(int threadID){return t[threadID];}
int CreateFile(char* filename); // fileSystem call void PrintInt(int n);
int CreateFile(char* filename); // fileSystem call
// These are public for notational convenience; really, // These are public for notational convenience; really,
// they're global variables used everywhere. // they're global variables used everywhere.
@@ -61,15 +63,16 @@ class Kernel {
FileSystem *fileSystem; FileSystem *fileSystem;
PostOfficeInput *postOfficeIn; PostOfficeInput *postOfficeIn;
PostOfficeOutput *postOfficeOut; PostOfficeOutput *postOfficeOut;
FrameTable *frameTable;
int hostName; // machine identifier int hostName; // machine identifier
private: private:
Thread* t[10]; Thread* t[10];
char* execfile[10]; char* execfile[10];
int execfileNum; int execfileNum;
int threadNum; int threadNum;
bool randomSlice; // enable pseudo-random time slicing bool randomSlice; // enable pseudo-random time slicing
bool debugUserProg; // single step user program bool debugUserProg; // single step user program
double reliability; // likelihood messages are dropped double reliability; // likelihood messages are dropped

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); ASSERT(kernel->interrupt->getLevel() == IntOff);
if (finishing) { // mark that we need to delete current thread if (finishing) { // mark that we need to delete current thread
ASSERT(toBeDestroyed == NULL); ASSERT(toBeDestroyed == NULL);
toBeDestroyed = oldThread; toBeDestroyed = oldThread;
} }
if (oldThread->space != NULL) { // if this thread is a user program, if (oldThread->space != NULL) { // if this thread is a user program,
oldThread->SaveUserState(); // save the user's CPU registers oldThread->SaveUserState(); // save the user's CPU registers
oldThread->space->SaveState(); oldThread->space->SaveState();
} }
oldThread->CheckOverflow(); // check if the old thread oldThread->CheckOverflow(); // check if the old thread
// had an undetected stack overflow // had an undetected stack overflow
kernel->currentThread = nextThread; // switch to the next thread kernel->currentThread = nextThread; // switch to the next thread
nextThread->setStatus(RUNNING); // nextThread is now running nextThread->setStatus(RUNNING); // nextThread is now running
DEBUG(dbgThread, "Switching from: " << oldThread->getName() << " to: " << nextThread->getName()); DEBUG(dbgThread, "Switching from: " << oldThread->getName() << " to: " << nextThread->getName());
// This is a machine-dependent assembly language routine defined // This is a machine-dependent assembly language routine defined
// in switch.s. You may have to think // in switch.s. You may have to think
// a bit to figure out what happens after this, both from the point // 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". // of view of the thread and from the perspective of the "outside world".
SWITCH(oldThread, nextThread); SWITCH(oldThread, nextThread);
// we're back, running oldThread // we're back, running oldThread
// interrupts are off when we return from switch! // interrupts are off when we return from switch!
ASSERT(kernel->interrupt->getLevel() == IntOff); ASSERT(kernel->interrupt->getLevel() == IntOff);
DEBUG(dbgThread, "Now in thread: " << oldThread->getName()); DEBUG(dbgThread, "Now in thread: " << oldThread->getName());
CheckToBeDestroyed(); // check if thread we were running CheckToBeDestroyed(); // check if thread we were running
// before this one has finished // before this one has finished
// and needs to be cleaned up // and needs to be cleaned up
if (oldThread->space != NULL) { // if there is an address space if (oldThread->space != NULL) { // if there is an address space
oldThread->RestoreUserState(); // to restore, do it. oldThread->RestoreUserState(); // to restore, do it.
oldThread->space->RestoreState(); 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); DEBUG(dbgThread, "Forking thread: " << name << " f(a): " << (int) func << " " << arg);
StackAllocate(func, arg); StackAllocate(func, arg);
oldLevel = interrupt->SetLevel(IntOff); oldLevel = interrupt->SetLevel(IntOff);
scheduler->ReadyToRun(this); // ReadyToRun assumes that interrupts scheduler->ReadyToRun(this); // ReadyToRun assumes that interrupts
// are disabled! // are disabled!
(void) interrupt->SetLevel(oldLevel); (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(this == kernel->currentThread);
ASSERT(kernel->interrupt->getLevel() == IntOff); ASSERT(kernel->interrupt->getLevel() == IntOff);
DEBUG(dbgThread, "Sleeping thread: " << name); DEBUG(dbgThread, "Sleeping thread: " << name);
status = BLOCKED; status = BLOCKED;
//cout << "debug Thread::Sleep " << name << "wait for Idle\n"; //cout << "debug Thread::Sleep " << name << "wait for Idle\n";
while ((nextThread = kernel->scheduler->FindNextToRun()) == NULL) { while ((nextThread = kernel->scheduler->FindNextToRun()) == NULL) {
kernel->interrupt->Idle(); // no one to run, wait for an interrupt kernel->interrupt->Idle(); // no one to run, wait for an interrupt
} }
// returns when it's time for us to run // returns when it's time for us to run
kernel->scheduler->Run(nextThread, finishing); 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
DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size); 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);
// 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

@@ -1,18 +1,18 @@
// exception.cc // exception.cc
// Entry point into the Nachos kernel from user programs. // Entry point into the Nachos kernel from user programs.
// There are two kinds of things that can cause control to // There are two kinds of things that can cause control to
// transfer back to here from user code: // transfer back to here from user code:
// //
// syscall -- The user code explicitly requests to call a procedure // syscall -- The user code explicitly requests to call a procedure
// in the Nachos kernel. Right now, the only function we support is // in the Nachos kernel. Right now, the only function we support is
// "Halt". // "Halt".
// //
// exceptions -- The user code does something that the CPU can't handle. // exceptions -- The user code does something that the CPU can't handle.
// For instance, accessing memory that doesn't exist, arithmetic errors, // For instance, accessing memory that doesn't exist, arithmetic errors,
// etc. // etc.
// //
// Interrupts (which can also cause control to transfer from user // Interrupts (which can also cause control to transfer from user
// code into the Nachos kernel) are handled elsewhere. // code into the Nachos kernel) are handled elsewhere.
// //
// For now, this only handles the Halt() system call. // For now, this only handles the Halt() system call.
// Everything else core dumps. // Everything else core dumps.
@@ -27,106 +27,192 @@
#include "ksyscall.h" #include "ksyscall.h"
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// ExceptionHandler // ExceptionHandler
// Entry point into the Nachos kernel. Called when a user program // Entry point into the Nachos kernel. Called when a user program
// is executing, and either does a syscall, or generates an addressing // is executing, and either does a syscall, or generates an addressing
// or arithmetic exception. // or arithmetic exception.
// //
// For system calls, the following is the calling convention: // For system calls, the following is the calling convention:
// //
// system call code -- r2 // system call code -- r2
// arg1 -- r4 // arg1 -- r4
// arg2 -- r5 // arg2 -- r5
// arg3 -- r6 // arg3 -- r6
// arg4 -- r7 // arg4 -- r7
// //
// The result of the system call, if any, must be put back into r2. // The result of the system call, if any, must be put back into r2.
// //
// If you are handling a system call, don't forget to increment the pc // If you are handling a system call, don't forget to increment the pc
// before returning. (Or else you'll loop making the same system call forever!) // before returning. (Or else you'll loop making the same system call forever!)
// //
// "which" is the kind of exception. The list of possible exceptions // "which" is the kind of exception. The list of possible exceptions
// is in machine.h. // is in machine.h.
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void void
ExceptionHandler(ExceptionType which) ExceptionHandler(ExceptionType which)
{ {
int type = kernel->machine->ReadRegister(2); int type = kernel->machine->ReadRegister(2);
int val; int val;
int status, exit, threadID, programID; int status, exit, threadID, programID;
DEBUG(dbgSys, "Received Exception " << which << " type: " << type << "\n"); DEBUG(dbgSys, "Received Exception " << which << " type: " << type << "\n");
switch (which) { switch (which) {
case SyscallException: case SyscallException:
switch(type) { switch(type) {
case SC_Halt: case SC_Halt:
DEBUG(dbgSys, "Shutdown, initiated by user program.\n"); DEBUG(dbgSys, "Shutdown, initiated by user program.\n");
SysHalt(); SysHalt();
cout<<"in exception\n"; cout<<"in exception\n";
ASSERTNOTREACHED(); ASSERTNOTREACHED();
break; break;
case SC_MSG: case SC_MSG:
DEBUG(dbgSys, "Message received.\n"); DEBUG(dbgSys, "Message received.\n");
val = kernel->machine->ReadRegister(4); val = kernel->machine->ReadRegister(4);
{ {
char *msg = &(kernel->machine->mainMemory[val]); char *msg = &(kernel->machine->mainMemory[val]);
cout << msg << endl; cout << msg << endl;
} }
SysHalt(); SysHalt();
ASSERTNOTREACHED(); ASSERTNOTREACHED();
break; break;
case SC_Create: case SC_Create:
val = kernel->machine->ReadRegister(4); val = kernel->machine->ReadRegister(4);
{ {
char *filename = &(kernel->machine->mainMemory[val]); char *filename = &(kernel->machine->mainMemory[val]);
//cout << filename << endl; //cout << filename << endl;
status = SysCreate(filename); status = SysCreate(filename);
kernel->machine->WriteRegister(2, (int) status); kernel->machine->WriteRegister(2, (int) status);
} }
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg)); kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4); kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg)+4); kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return; return;
ASSERTNOTREACHED(); ASSERTNOTREACHED();
break; break;
case SC_Add: case SC_Add:
DEBUG(dbgSys, "Add " << kernel->machine->ReadRegister(4) << " + " << kernel->machine->ReadRegister(5) << "\n"); DEBUG(dbgSys, "Add " << kernel->machine->ReadRegister(4) << " + " << kernel->machine->ReadRegister(5) << "\n");
/* Process SysAdd Systemcall*/ /* Process SysAdd Systemcall*/
int result; int result;
result = SysAdd(/* int op1 */(int)kernel->machine->ReadRegister(4), result = SysAdd(/* int op1 */(int)kernel->machine->ReadRegister(4),
/* int op2 */(int)kernel->machine->ReadRegister(5)); /* int op2 */(int)kernel->machine->ReadRegister(5));
DEBUG(dbgSys, "Add returning with " << result << "\n"); DEBUG(dbgSys, "Add returning with " << result << "\n");
/* Prepare Result */ /* Prepare Result */
kernel->machine->WriteRegister(2, (int)result); kernel->machine->WriteRegister(2, (int)result);
/* Modify return point */ /* Modify return point */
{ {
/* set previous programm counter (debugging only)*/ /* set previous programm counter (debugging only)*/
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg)); kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
/* set programm counter to next instruction (all Instructions are 4 byte wide)*/ /* set programm counter to next instruction (all Instructions are 4 byte wide)*/
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4); kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
/* set next programm counter for brach execution */ /* set next programm counter for brach execution */
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg)+4); kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
} }
cout << "result is " << result << "\n"; cout << "result is " << result << "\n";
return; return;
ASSERTNOTREACHED(); ASSERTNOTREACHED();
break; break;
case SC_Exit: case SC_Exit:
DEBUG(dbgAddr, "Program exit\n"); DEBUG(dbgAddr, "Program exit\n");
val=kernel->machine->ReadRegister(4); val = kernel->machine->ReadRegister(4);
cout << "return value:" << val << endl; cout << "return value:" << val << endl;
kernel->currentThread->Finish(); kernel->currentThread->Finish();
break; break;
default: case SC_PrintInt:
cerr << "Unexpected system call " << type << "\n"; DEBUG(dbgAddr, "Printing int\n");
break; val = (int)kernel->machine->ReadRegister(4);
} SysPrintInt(val);
break;
default: kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
cerr << "Unexpected user mode exception " << (int)which << "\n"; kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
break; kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
}
ASSERTNOTREACHED(); return;
ASSERTNOTREACHED();
break;
case SC_Open:
DEBUG(dbgAddr, "Open file\n");
{
val = kernel->machine->ReadRegister(4);
char *name = &(kernel->machine->mainMemory[val]);
OpenFileId ret = SysOpen(name);
kernel->machine->WriteRegister(2, ret);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Read:
DEBUG(dbgAddr, "Read file\n");
{
val = kernel->machine->ReadRegister(4);
char *buffer = &(kernel->machine->mainMemory[val]);
int size = kernel->machine->ReadRegister(5);
OpenFileId id = (OpenFileId)kernel->machine->ReadRegister(6);
int ret = SysRead(buffer, size, id);
kernel->machine->WriteRegister(2, ret);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Write:
DEBUG(dbgAddr, "Write file\n");
{
val = kernel->machine->ReadRegister(4);
char *buffer = &(kernel->machine->mainMemory[val]);
int size = kernel->machine->ReadRegister(5);
OpenFileId id = (OpenFileId)kernel->machine->ReadRegister(6);
// fprintf(stderr, "buffer: %p\n", buffer);
// cerr << "size: " << size << endl;
// cerr << "id: " << id << endl;
int ret = SysWrite(buffer, size, id);
kernel->machine->WriteRegister(2, ret);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Close:
DEBUG(dbgAddr, "Close file\n");
{
OpenFileId id = (OpenFileId)kernel->machine->ReadRegister(4);
int ret = SysClose(id);
kernel->machine->WriteRegister(2, ret);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
default:
cerr << "Unexpected system call " << type << "\n";
break;
}
break;
default:
cerr << "Unexpected user mode exception " << (int)which << "\n";
break;
}
ASSERTNOTREACHED();
} }

View File

@@ -11,6 +11,8 @@
#ifndef __USERPROG_KSYSCALL_H__ #ifndef __USERPROG_KSYSCALL_H__
#define __USERPROG_KSYSCALL_H__ #define __USERPROG_KSYSCALL_H__
#define INT_BUF_LENGTH 13
#include "kernel.h" #include "kernel.h"
#include "synchconsole.h" #include "synchconsole.h"
@@ -28,10 +30,48 @@ int SysAdd(int op1, int op2)
int SysCreate(char *filename) int SysCreate(char *filename)
{ {
// return value // return value
// 1: success // 1: success
// 0: failed // 0: failed
return kernel->interrupt->CreateFile(filename); return kernel->interrupt->CreateFile(filename);
}
void SysPrintInt(int value) {
kernel->interrupt->PrintInt(value);
}
OpenFileId SysOpen(char *name) {
OpenFileId id = -1;
for (int i = 0; i < 20; i++)
if (kernel->fileSystem->fileDescriptorTable[i] == NULL) {
id = i;
kernel->fileSystem->fileDescriptorTable[i]
= kernel->fileSystem->Open(name);
if (kernel->fileSystem->fileDescriptorTable[i] == NULL)
return -1;
break;
}
return id;
}
int SysWrite(char *buffer, int size, OpenFileId id) {
if (id < 0 || id >= 20 || kernel->fileSystem->fileDescriptorTable[id] == NULL)
return -1;
return kernel->fileSystem->fileDescriptorTable[id]->Write(buffer, size);
}
int SysRead(char *buffer, int size, OpenFileId id) {
if (id < 0 || id >= 20 || kernel->fileSystem->fileDescriptorTable[id] == NULL)
return -1;
return kernel->fileSystem->fileDescriptorTable[id]->Read(buffer, size);
}
int SysClose(OpenFileId id) {
if (id < 0 || id >= 20 || kernel->fileSystem->fileDescriptorTable[id] == NULL)
return 0;
delete kernel->fileSystem->fileDescriptorTable[id];
kernel->fileSystem->fileDescriptorTable[id] = NULL;
return 1;
} }

View File

@@ -106,6 +106,15 @@ SynchConsoleOutput::PutChar(char ch)
lock->Release(); lock->Release();
} }
void
SynchConsoleOutput::PutInt(int value)
{
lock->Acquire();
consoleOutput->PutInt(value);
waitFor->P();
lock->Release();
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// SynchConsoleOutput::CallBack // SynchConsoleOutput::CallBack
// Interrupt handler called when it's safe to send the next // Interrupt handler called when it's safe to send the next

View File

@@ -41,6 +41,7 @@ class SynchConsoleOutput : public CallBackObj {
~SynchConsoleOutput(); ~SynchConsoleOutput();
void PutChar(char ch); // Write a character, waiting if necessary void PutChar(char ch); // Write a character, waiting if necessary
void PutInt(int value);
private: private:
ConsoleOutput *consoleOutput;// the hardware display ConsoleOutput *consoleOutput;// the hardware display

View File

@@ -23,19 +23,22 @@
#define SC_Exec 2 #define SC_Exec 2
#define SC_Join 3 #define SC_Join 3
#define SC_Create 4 #define SC_Create 4
#define SC_Remove 5 #define SC_Remove 5
#define SC_Open 6 #define SC_Open 6
#define SC_Read 7 #define SC_Read 7
#define SC_Write 8 #define SC_Write 8
#define SC_Seek 9 #define SC_Seek 9
#define SC_Close 10 #define SC_Close 10
#define SC_ThreadFork 11 #define SC_ThreadFork 11
#define SC_ThreadYield 12 #define SC_ThreadYield 12
#define SC_ExecV 13 #define SC_ExecV 13
#define SC_ThreadExit 14 #define SC_ThreadExit 14
#define SC_ThreadJoin 15 #define SC_ThreadJoin 15
#define SC_Add 42
#define SC_MSG 100 #define SC_PrintInt 16
#define SC_Add 42
#define SC_MSG 100
#ifndef IN_ASM #ifndef IN_ASM
@@ -109,7 +112,7 @@ typedef int OpenFileId;
*/ */
#define SysConsoleInput 0 #define SysConsoleInput 0
#define SysConsoleOutput 1 #define SysConsoleOutput 1
/* Create a Nachos file, with name "name" */ /* Create a Nachos file, with name "name" */
/* Note: Create does not open the file. */ /* Note: Create does not open the file. */
@@ -177,6 +180,8 @@ int ThreadJoin(ThreadId id);
*/ */
void ThreadExit(int ExitCode); void ThreadExit(int ExitCode);
void PrintInt(int number);
#endif /* IN_ASM */ #endif /* IN_ASM */
#endif /* SYSCALL_H */ #endif /* SYSCALL_H */

7
docker-compose.yaml Normal file
View File

@@ -0,0 +1,7 @@
---
services:
test:
build: .
user: '60139:60139'
volumes:
- './:/work'