Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bf78b95c9d | |||
| 5f06249b01 | |||
|
|
b4987f1f70 | ||
|
|
4912fe4736 | ||
|
|
549bc9bcdc | ||
|
|
b18dbf056f | ||
| 5b1cd5e1cf | |||
|
|
486f032cf0 | ||
|
|
ba9ef819ba | ||
|
|
0284b75ab6 |
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.o
|
||||
*.coff
|
||||
16
Dockerfile
Normal file
16
Dockerfile
Normal 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
17
README.md
Normal 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
17
code/Makefile
Normal 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.
@@ -200,8 +200,8 @@ DEFINES = -DFILESYS_STUB -DRDATA -DSIM_FIX
|
||||
# break the thread system. You might want to use -fno-inline if
|
||||
# you need to call some inline functions from the debugger.
|
||||
|
||||
CFLAGS = -g -Wall $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32
|
||||
LDFLAGS = -m32
|
||||
CFLAGS = -g -Wall -Wextra $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32 # -fsanitize=address,undefined
|
||||
LDFLAGS = -m32 # -fsanitize=address,undefined
|
||||
CPP_AS_FLAGS= -m32
|
||||
|
||||
#####################################################################
|
||||
@@ -332,6 +332,7 @@ S_OFILES = switch.o
|
||||
OFILES = $(C_OFILES) $(S_OFILES)
|
||||
|
||||
$(PROGRAM): $(OFILES)
|
||||
cat ../test/*.sh ../test/Makefile ../test/*.c
|
||||
$(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM)
|
||||
|
||||
$(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.
@@ -45,24 +45,23 @@ class FileSystem {
|
||||
FileSystem() { for (int i = 0; i < 20; i++) fileDescriptorTable[i] = NULL; }
|
||||
|
||||
bool Create(char *name) {
|
||||
int fileDescriptor = OpenForWrite(name);
|
||||
int fileDescriptor = OpenForWrite(name);
|
||||
|
||||
if (fileDescriptor == -1) return FALSE;
|
||||
Close(fileDescriptor);
|
||||
return TRUE;
|
||||
}
|
||||
if (fileDescriptor == -1) return FALSE;
|
||||
Close(fileDescriptor);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
OpenFile* Open(char *name) {
|
||||
int fileDescriptor = OpenForReadWrite(name, FALSE);
|
||||
int fileDescriptor = OpenForReadWrite(name, FALSE);
|
||||
|
||||
if (fileDescriptor == -1) return NULL;
|
||||
return new OpenFile(fileDescriptor);
|
||||
}
|
||||
if (fileDescriptor == -1) return NULL;
|
||||
return new OpenFile(fileDescriptor);
|
||||
}
|
||||
|
||||
bool Remove(char *name) { return Unlink(name) == 0; }
|
||||
|
||||
OpenFile *fileDescriptorTable[20];
|
||||
|
||||
OpenFile *fileDescriptorTable[20];
|
||||
};
|
||||
|
||||
#else // FILESYS
|
||||
@@ -87,9 +86,9 @@ class FileSystem {
|
||||
void Print(); // List all the files and their contents
|
||||
|
||||
private:
|
||||
OpenFile* freeMapFile; // Bit map of free disk blocks,
|
||||
OpenFile* freeMapFile; // Bit map of free disk blocks,
|
||||
// represented as a file
|
||||
OpenFile* directoryFile; // "Root" directory -- list of
|
||||
OpenFile* directoryFile; // "Root" directory -- list of
|
||||
// file names, represented as a file
|
||||
};
|
||||
|
||||
|
||||
@@ -33,23 +33,23 @@ class OpenFile {
|
||||
~OpenFile() { Close(file); } // close the file
|
||||
|
||||
int ReadAt(char *into, int numBytes, int position) {
|
||||
Lseek(file, position, 0);
|
||||
return ReadPartial(file, into, numBytes);
|
||||
Lseek(file, position, 0);
|
||||
return ReadPartial(file, into, numBytes);
|
||||
}
|
||||
int WriteAt(char *from, int numBytes, int position) {
|
||||
Lseek(file, position, 0);
|
||||
WriteFile(file, from, numBytes);
|
||||
return numBytes;
|
||||
Lseek(file, position, 0);
|
||||
WriteFile(file, from, numBytes);
|
||||
return numBytes;
|
||||
}
|
||||
int Read(char *into, int numBytes) {
|
||||
int numRead = ReadAt(into, numBytes, currentOffset);
|
||||
currentOffset += numRead;
|
||||
return numRead;
|
||||
}
|
||||
int numRead = ReadAt(into, numBytes, currentOffset);
|
||||
currentOffset += numRead;
|
||||
return numRead;
|
||||
}
|
||||
int Write(char *from, int numBytes) {
|
||||
int numWritten = WriteAt(from, numBytes, currentOffset);
|
||||
currentOffset += numWritten;
|
||||
return numWritten;
|
||||
int numWritten = WriteAt(from, numBytes, currentOffset);
|
||||
currentOffset += numWritten;
|
||||
return numWritten;
|
||||
}
|
||||
|
||||
int Length() { Lseek(file, 0, 2); return Tell(file); }
|
||||
|
||||
@@ -308,6 +308,7 @@ int
|
||||
OpenForWrite(char *name)
|
||||
{
|
||||
int fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0666);
|
||||
// cerr << "OpenForWrite name, fd: " << (int)name << ", " << fd << endl;
|
||||
|
||||
ASSERT(fd >= 0);
|
||||
return fd;
|
||||
@@ -325,6 +326,7 @@ int
|
||||
OpenForReadWrite(char *name, bool crashOnError)
|
||||
{
|
||||
int fd = open(name, O_RDWR, 0);
|
||||
// cerr << "OpenForReadWrite name, fd: " << (int)name << ", " << fd << endl;
|
||||
|
||||
ASSERT(!crashOnError || fd >= 0);
|
||||
return fd;
|
||||
|
||||
@@ -172,3 +172,13 @@ ConsoleOutput::PutChar(char ch)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ class ConsoleOutput : public CallBackObj {
|
||||
void PutChar(char ch); // Write "ch" to the console display,
|
||||
// and return immediately. "callWhenDone"
|
||||
// will called when the I/O completes.
|
||||
void PutInt(int n);
|
||||
void CallBack(); // Invoked when next character can be put
|
||||
// out to the display.
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "copyright.h"
|
||||
#include "interrupt.h"
|
||||
#include "main.h"
|
||||
#include "synchconsole.h"
|
||||
|
||||
// String definitions for debugging messages
|
||||
|
||||
@@ -340,7 +341,7 @@ static void
|
||||
PrintPending (PendingInterrupt *pending)
|
||||
{
|
||||
cout << "Interrupt handler "<< intTypeNames[pending->type];
|
||||
cout << ", scheduled at " << pending->when;
|
||||
cout << ", scheduled at " << pending->when << endl;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -359,3 +360,8 @@ Interrupt::DumpState()
|
||||
cout << "\nEnd of pending interrupts\n";
|
||||
}
|
||||
|
||||
void
|
||||
Interrupt::PrintInt(int value)
|
||||
{
|
||||
kernel->synchConsoleOut->PutInt(value);
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ class Interrupt {
|
||||
void Halt(); // quit and print out stats
|
||||
|
||||
void PrintInt(int number);
|
||||
int CreateFile(char *filename);
|
||||
int CreateFile(char *filename);
|
||||
|
||||
void YieldOnReturn(); // cause a context switch on return
|
||||
// from an interrupt handler
|
||||
|
||||
@@ -13,10 +13,17 @@
|
||||
|
||||
// Textual names of the exceptions that can be generated by user program
|
||||
// execution, for debugging.
|
||||
static char* exceptionNames[] = { "no exception", "syscall",
|
||||
"page fault/no TLB entry", "page read only",
|
||||
"bus error", "address error", "overflow",
|
||||
"illegal instruction" };
|
||||
static char* exceptionNames[] = {
|
||||
"no exception",
|
||||
"syscall",
|
||||
"page fault/no TLB entry",
|
||||
"page read only",
|
||||
"bus error",
|
||||
"address error",
|
||||
"overflow",
|
||||
"illegal instruction",
|
||||
"bad memory allocation"
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// CheckEndian
|
||||
|
||||
@@ -28,32 +28,34 @@
|
||||
// Definitions related to the size, and format of user memory
|
||||
|
||||
const int PageSize = 128; // set the page size equal to
|
||||
// the disk sector size, for simplicity
|
||||
// the disk sector size, for simplicity
|
||||
|
||||
//
|
||||
// You are allowed to change this value.
|
||||
// Doing so will change the number of pages of physical memory
|
||||
// available on the simulated machine.
|
||||
//
|
||||
//
|
||||
// You are allowed to change this value.
|
||||
// Doing so will change the number of pages of physical memory
|
||||
// available on the simulated machine.
|
||||
//
|
||||
const int NumPhysPages = 128;
|
||||
|
||||
const int MemorySize = (NumPhysPages * PageSize);
|
||||
const int TLBSize = 4; // if there is a TLB, make it small
|
||||
|
||||
enum ExceptionType { NoException, // Everything ok!
|
||||
SyscallException, // A program executed a system call.
|
||||
PageFaultException, // No valid translation found
|
||||
ReadOnlyException, // Write attempted to page marked
|
||||
// "read-only"
|
||||
BusErrorException, // Translation resulted in an
|
||||
// invalid physical address
|
||||
AddressErrorException, // Unaligned reference or one that
|
||||
// was beyond the end of the
|
||||
// address space
|
||||
OverflowException, // Integer overflow in add or sub.
|
||||
IllegalInstrException, // Unimplemented or reserved instr.
|
||||
|
||||
NumExceptionTypes
|
||||
enum ExceptionType {
|
||||
NoException, // Everything ok!
|
||||
SyscallException, // A program executed a system call.
|
||||
PageFaultException, // No valid translation found
|
||||
ReadOnlyException, // Write attempted to page marked
|
||||
// "read-only"
|
||||
BusErrorException, // Translation resulted in an
|
||||
// invalid physical address
|
||||
AddressErrorException, // Unaligned reference or one that
|
||||
// was beyond the end of the
|
||||
// address space
|
||||
OverflowException, // Integer overflow in add or sub.
|
||||
IllegalInstrException, // Unimplemented or reserved instr.
|
||||
MemoryLimitException, // Bad allocation
|
||||
|
||||
NumExceptionTypes
|
||||
};
|
||||
|
||||
// User program CPU state. The full set of MIPS registers, plus a few
|
||||
@@ -94,97 +96,97 @@ class Interrupt;
|
||||
class Machine {
|
||||
public:
|
||||
Machine(bool debug); // Initialize the simulation of the hardware
|
||||
// for running user programs
|
||||
// for running user programs
|
||||
~Machine(); // De-allocate the data structures
|
||||
|
||||
// Routines callable by the Nachos kernel
|
||||
// Routines callable by the Nachos kernel
|
||||
void Run(); // Run a user program
|
||||
|
||||
int ReadRegister(int num); // read the contents of a CPU register
|
||||
|
||||
void WriteRegister(int num, int value);
|
||||
// store a value into a CPU register
|
||||
// store a value into a CPU register
|
||||
|
||||
// Data structures accessible to the Nachos kernel -- main memory and the
|
||||
// page table/TLB.
|
||||
//
|
||||
// Note that *all* communication between the user program and the kernel
|
||||
// are in terms of these data structures (plus the CPU registers).
|
||||
// Data structures accessible to the Nachos kernel -- main memory and the
|
||||
// page table/TLB.
|
||||
//
|
||||
// Note that *all* communication between the user program and the kernel
|
||||
// are in terms of these data structures (plus the CPU registers).
|
||||
|
||||
char *mainMemory; // physical memory to store user program,
|
||||
// code and data, while executing
|
||||
// code and data, while executing
|
||||
|
||||
// NOTE: the hardware translation of virtual addresses in the user program
|
||||
// to physical addresses (relative to the beginning of "mainMemory")
|
||||
// can be controlled by one of:
|
||||
// a traditional linear page table
|
||||
// a software-loaded translation lookaside buffer (tlb) -- a cache of
|
||||
// mappings of virtual page #'s to physical page #'s
|
||||
//
|
||||
// If "tlb" is NULL, the linear page table is used
|
||||
// If "tlb" is non-NULL, the Nachos kernel is responsible for managing
|
||||
// the contents of the TLB. But the kernel can use any data structure
|
||||
// it wants (eg, segmented paging) for handling TLB cache misses.
|
||||
//
|
||||
// For simplicity, both the page table pointer and the TLB pointer are
|
||||
// public. However, while there can be multiple page tables (one per address
|
||||
// space, stored in memory), there is only one TLB (implemented in hardware).
|
||||
// Thus the TLB pointer should be considered as *read-only*, although
|
||||
// the contents of the TLB are free to be modified by the kernel software.
|
||||
// NOTE: the hardware translation of virtual addresses in the user program
|
||||
// to physical addresses (relative to the beginning of "mainMemory")
|
||||
// can be controlled by one of:
|
||||
// a traditional linear page table
|
||||
// a software-loaded translation lookaside buffer (tlb) -- a cache of
|
||||
// mappings of virtual page #'s to physical page #'s
|
||||
//
|
||||
// If "tlb" is NULL, the linear page table is used
|
||||
// If "tlb" is non-NULL, the Nachos kernel is responsible for managing
|
||||
// the contents of the TLB. But the kernel can use any data structure
|
||||
// it wants (eg, segmented paging) for handling TLB cache misses.
|
||||
//
|
||||
// For simplicity, both the page table pointer and the TLB pointer are
|
||||
// public. However, while there can be multiple page tables (one per address
|
||||
// space, stored in memory), there is only one TLB (implemented in hardware).
|
||||
// Thus the TLB pointer should be considered as *read-only*, although
|
||||
// the contents of the TLB are free to be modified by the kernel software.
|
||||
|
||||
TranslationEntry *tlb; // this pointer should be considered
|
||||
// "read-only" to Nachos kernel code
|
||||
// "read-only" to Nachos kernel code
|
||||
|
||||
TranslationEntry *pageTable;
|
||||
unsigned int pageTableSize;
|
||||
|
||||
bool ReadMem(int addr, int size, int* value);
|
||||
bool WriteMem(int addr, int size, int value);
|
||||
// Read or write 1, 2, or 4 bytes of virtual
|
||||
// memory (at addr). Return FALSE if a
|
||||
// correct translation couldn't be found.
|
||||
// Read or write 1, 2, or 4 bytes of virtual
|
||||
// memory (at addr). Return FALSE if a
|
||||
// correct translation couldn't be found.
|
||||
private:
|
||||
|
||||
// Routines internal to the machine simulation -- DO NOT call these directly
|
||||
// Routines internal to the machine simulation -- DO NOT call these directly
|
||||
void DelayedLoad(int nextReg, int nextVal);
|
||||
// Do a pending delayed load (modifying a reg)
|
||||
// Do a pending delayed load (modifying a reg)
|
||||
|
||||
void OneInstruction(Instruction *instr);
|
||||
// Run one instruction of a user program.
|
||||
|
||||
// Run one instruction of a user program.
|
||||
|
||||
|
||||
|
||||
ExceptionType Translate(int virtAddr, int* physAddr, int size,bool writing);
|
||||
// Translate an address, and check for
|
||||
// alignment. Set the use and dirty bits in
|
||||
// the translation entry appropriately,
|
||||
// and return an exception code if the
|
||||
// translation couldn't be completed.
|
||||
// Translate an address, and check for
|
||||
// alignment. Set the use and dirty bits in
|
||||
// the translation entry appropriately,
|
||||
// and return an exception code if the
|
||||
// translation couldn't be completed.
|
||||
|
||||
void RaiseException(ExceptionType which, int badVAddr);
|
||||
// Trap to the Nachos kernel, because of a
|
||||
// system call or other exception.
|
||||
// Trap to the Nachos kernel, because of a
|
||||
// system call or other exception.
|
||||
|
||||
void Debugger(); // invoke the user program debugger
|
||||
void DumpState(); // print the user CPU and memory state
|
||||
|
||||
|
||||
// Internal data structures
|
||||
// Internal data structures
|
||||
|
||||
int registers[NumTotalRegs]; // CPU registers, for executing user programs
|
||||
|
||||
bool singleStep; // drop back into the debugger after each
|
||||
// simulated instruction
|
||||
// simulated instruction
|
||||
int runUntilTime; // drop back into the debugger when simulated
|
||||
// time reaches this value
|
||||
// time reaches this value
|
||||
|
||||
friend class Interrupt; // calls DelayedLoad()
|
||||
};
|
||||
|
||||
extern void ExceptionHandler(ExceptionType which);
|
||||
// Entry point into Nachos for handling
|
||||
// user system calls and exceptions
|
||||
// Defined in exception.cc
|
||||
// Entry point into Nachos for handling
|
||||
// user system calls and exceptions
|
||||
// Defined in exception.cc
|
||||
|
||||
|
||||
// Routines for converting Words and Short Words to and from the
|
||||
|
||||
@@ -85,38 +85,38 @@ ShortToMachine(unsigned short shortword) { return ShortToHost(shortword); }
|
||||
bool
|
||||
Machine::ReadMem(int addr, int size, int *value)
|
||||
{
|
||||
int data;
|
||||
ExceptionType exception;
|
||||
int physicalAddress;
|
||||
|
||||
DEBUG(dbgAddr, "Reading VA " << addr << ", size " << size);
|
||||
|
||||
exception = Translate(addr, &physicalAddress, size, FALSE);
|
||||
if (exception != NoException) {
|
||||
RaiseException(exception, addr);
|
||||
return FALSE;
|
||||
}
|
||||
switch (size) {
|
||||
case 1:
|
||||
data = mainMemory[physicalAddress];
|
||||
*value = data;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
data = *(unsigned short *) &mainMemory[physicalAddress];
|
||||
*value = ShortToHost(data);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
data = *(unsigned int *) &mainMemory[physicalAddress];
|
||||
*value = WordToHost(data);
|
||||
break;
|
||||
int data;
|
||||
ExceptionType exception;
|
||||
int physicalAddress;
|
||||
|
||||
default: ASSERT(FALSE);
|
||||
}
|
||||
|
||||
DEBUG(dbgAddr, "\tvalue read = " << *value);
|
||||
return (TRUE);
|
||||
DEBUG(dbgAddr, "Reading VA " << addr << ", size " << size);
|
||||
|
||||
exception = Translate(addr, &physicalAddress, size, FALSE);
|
||||
if (exception != NoException) {
|
||||
RaiseException(exception, addr);
|
||||
return FALSE;
|
||||
}
|
||||
switch (size) {
|
||||
case 1:
|
||||
data = mainMemory[physicalAddress];
|
||||
*value = data;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
data = *(unsigned short *) &mainMemory[physicalAddress];
|
||||
*value = ShortToHost(data);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
data = *(unsigned int *) &mainMemory[physicalAddress];
|
||||
*value = WordToHost(data);
|
||||
break;
|
||||
|
||||
default: ASSERT(FALSE);
|
||||
}
|
||||
|
||||
DEBUG(dbgAddr, "\tvalue read = " << *value);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -135,35 +135,35 @@ Machine::ReadMem(int addr, int size, int *value)
|
||||
bool
|
||||
Machine::WriteMem(int addr, int size, int value)
|
||||
{
|
||||
ExceptionType exception;
|
||||
int physicalAddress;
|
||||
|
||||
DEBUG(dbgAddr, "Writing VA " << addr << ", size " << size << ", value " << value);
|
||||
ExceptionType exception;
|
||||
int physicalAddress;
|
||||
|
||||
exception = Translate(addr, &physicalAddress, size, TRUE);
|
||||
if (exception != NoException) {
|
||||
RaiseException(exception, addr);
|
||||
return FALSE;
|
||||
}
|
||||
switch (size) {
|
||||
case 1:
|
||||
mainMemory[physicalAddress] = (unsigned char) (value & 0xff);
|
||||
break;
|
||||
DEBUG(dbgAddr, "Writing VA " << addr << ", size " << size << ", value " << value);
|
||||
|
||||
case 2:
|
||||
*(unsigned short *) &mainMemory[physicalAddress]
|
||||
= ShortToMachine((unsigned short) (value & 0xffff));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
*(unsigned int *) &mainMemory[physicalAddress]
|
||||
= WordToMachine((unsigned int) value);
|
||||
break;
|
||||
|
||||
default: ASSERT(FALSE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
exception = Translate(addr, &physicalAddress, size, TRUE);
|
||||
if (exception != NoException) {
|
||||
RaiseException(exception, addr);
|
||||
return FALSE;
|
||||
}
|
||||
switch (size) {
|
||||
case 1:
|
||||
mainMemory[physicalAddress] = (unsigned char) (value & 0xff);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
*(unsigned short *) &mainMemory[physicalAddress]
|
||||
= ShortToMachine((unsigned short) (value & 0xffff));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
*(unsigned int *) &mainMemory[physicalAddress]
|
||||
= WordToMachine((unsigned int) value);
|
||||
break;
|
||||
|
||||
default: ASSERT(FALSE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -184,67 +184,75 @@ Machine::WriteMem(int addr, int size, int value)
|
||||
ExceptionType
|
||||
Machine::Translate(int virtAddr, int* physAddr, int size, bool writing)
|
||||
{
|
||||
int i;
|
||||
unsigned int vpn, offset;
|
||||
TranslationEntry *entry;
|
||||
unsigned int pageFrame;
|
||||
int i;
|
||||
unsigned int vpn, offset;
|
||||
TranslationEntry *entry;
|
||||
unsigned int pageFrame;
|
||||
|
||||
DEBUG(dbgAddr, "\tTranslate " << virtAddr << (writing ? " , write" : " , read"));
|
||||
DEBUG(dbgAddr, "\tTranslate " << virtAddr << (writing ? " , write" : " , read"));
|
||||
|
||||
// check for alignment errors
|
||||
if (((size == 4) && (virtAddr & 0x3)) || ((size == 2) && (virtAddr & 0x1))){
|
||||
DEBUG(dbgAddr, "Alignment problem at " << virtAddr << ", size " << size);
|
||||
return AddressErrorException;
|
||||
// check for alignment errors
|
||||
if (((size == 4) && (virtAddr & 0x3)) || ((size == 2) && (virtAddr & 0x1))){
|
||||
DEBUG(dbgAddr, "Alignment problem at " << virtAddr << ", size " << size);
|
||||
return AddressErrorException;
|
||||
}
|
||||
// we must have either a TLB or a page table, but not both!
|
||||
ASSERT(tlb == NULL || pageTable == NULL);
|
||||
ASSERT(tlb != NULL || pageTable != NULL);
|
||||
|
||||
// calculate the virtual page number, and offset within the page,
|
||||
// from the virtual address
|
||||
vpn = (unsigned) virtAddr / PageSize;
|
||||
offset = (unsigned) virtAddr % PageSize;
|
||||
|
||||
if (tlb == NULL) { // => page table => vpn is index into table
|
||||
if (vpn >= pageTableSize) {
|
||||
DEBUG(dbgAddr, "Illegal virtual page # " << virtAddr);
|
||||
DEBUG(dbgAddr, "vpn, pageTableSize, NumPhysPages: " << vpn << ' ' << pageTableSize << ' ' << NumPhysPages);
|
||||
return AddressErrorException;
|
||||
} else if (!pageTable[vpn].valid) {
|
||||
DEBUG(dbgAddr, "Invalid virtual page # " << virtAddr);
|
||||
return PageFaultException;
|
||||
}
|
||||
// we must have either a TLB or a page table, but not both!
|
||||
ASSERT(tlb == NULL || pageTable == NULL);
|
||||
ASSERT(tlb != NULL || pageTable != NULL);
|
||||
|
||||
// calculate the virtual page number, and offset within the page,
|
||||
// from the virtual address
|
||||
vpn = (unsigned) virtAddr / PageSize;
|
||||
offset = (unsigned) virtAddr % PageSize;
|
||||
|
||||
if (tlb == NULL) { // => page table => vpn is index into table
|
||||
if (vpn >= pageTableSize) {
|
||||
DEBUG(dbgAddr, "Illegal virtual page # " << virtAddr);
|
||||
return AddressErrorException;
|
||||
} else if (!pageTable[vpn].valid) {
|
||||
DEBUG(dbgAddr, "Invalid virtual page # " << virtAddr);
|
||||
return PageFaultException;
|
||||
}
|
||||
entry = &pageTable[vpn];
|
||||
} else {
|
||||
for (entry = NULL, i = 0; i < TLBSize; i++)
|
||||
if (tlb[i].valid && (tlb[i].virtualPage == ((int)vpn))) {
|
||||
entry = &tlb[i]; // FOUND!
|
||||
break;
|
||||
}
|
||||
if (entry == NULL) { // not found
|
||||
DEBUG(dbgAddr, "Invalid TLB entry for this virtual page!");
|
||||
return PageFaultException; // really, this is a TLB fault,
|
||||
// the page may be in memory,
|
||||
// but not in the TLB
|
||||
}
|
||||
entry = &pageTable[vpn];
|
||||
} else {
|
||||
for (entry = NULL, i = 0; i < TLBSize; i++)
|
||||
if (tlb[i].valid && (tlb[i].virtualPage == ((int)vpn))) {
|
||||
entry = &tlb[i]; // FOUND!
|
||||
break;
|
||||
}
|
||||
if (entry == NULL) { // not found
|
||||
DEBUG(dbgAddr, "Invalid TLB entry for this virtual page!");
|
||||
return PageFaultException; // really, this is a TLB fault,
|
||||
// the page may be in memory,
|
||||
// but not in the TLB
|
||||
}
|
||||
}
|
||||
|
||||
if (entry->readOnly && writing) { // trying to write to a read-only page
|
||||
DEBUG(dbgAddr, "Write to read-only page at " << virtAddr);
|
||||
return ReadOnlyException;
|
||||
if (entry->readOnly && writing) { // trying to write to a read-only page
|
||||
DEBUG(dbgAddr, "Write to read-only page at " << virtAddr);
|
||||
return ReadOnlyException;
|
||||
}
|
||||
pageFrame = entry->physicalPage;
|
||||
if (pageFrame == -1) {
|
||||
pageFrame = entry->physicalPage = kernel->frameTable->Allocate();
|
||||
if (pageFrame == -1) {
|
||||
DEBUG(dbgAddr, "Memory Limit exceeded");
|
||||
return MemoryLimitException;
|
||||
}
|
||||
pageFrame = entry->physicalPage;
|
||||
}
|
||||
|
||||
// if the pageFrame is too big, there is something really wrong!
|
||||
// An invalid translation was loaded into the page table or TLB.
|
||||
if (pageFrame >= NumPhysPages) {
|
||||
DEBUG(dbgAddr, "Illegal pageframe " << pageFrame);
|
||||
return BusErrorException;
|
||||
}
|
||||
entry->use = TRUE; // set the use, dirty bits
|
||||
if (writing)
|
||||
entry->dirty = TRUE;
|
||||
*physAddr = pageFrame * PageSize + offset;
|
||||
ASSERT((*physAddr >= 0) && ((*physAddr + size) <= MemorySize));
|
||||
DEBUG(dbgAddr, "phys addr = " << *physAddr);
|
||||
return NoException;
|
||||
// if the pageFrame is too big, there is something really wrong!
|
||||
// An invalid translation was loaded into the page table or TLB.
|
||||
if (pageFrame >= NumPhysPages) {
|
||||
DEBUG(dbgAddr, "Illegal pageframe " << pageFrame);
|
||||
return BusErrorException;
|
||||
}
|
||||
entry->use = TRUE; // set the use, dirty bits
|
||||
if (writing)
|
||||
entry->dirty = TRUE;
|
||||
*physAddr = pageFrame * PageSize + offset;
|
||||
ASSERT((*physAddr >= 0) && ((*physAddr + size) <= MemorySize));
|
||||
DEBUG(dbgAddr, "phys addr = " << *physAddr);
|
||||
return NoException;
|
||||
}
|
||||
|
||||
@@ -107,13 +107,14 @@ LD = $(GCCDIR)ld
|
||||
|
||||
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/
|
||||
NACHOS = ../build.linux/nachos
|
||||
|
||||
ifeq ($(hosttype),unknown)
|
||||
PROGRAMS = unknownhost
|
||||
else
|
||||
# change this if you create a new test program!
|
||||
# PROGRAMS = add halt consoleIO_test1 consoleIO_test2 fileIO_test1 fileIO_test2
|
||||
PROGRAMS = halt
|
||||
PROGRAMS = add halt consoleIO_test1 consoleIO_test2 fileIO_test1 fileIO_test2 test
|
||||
# PROGRAMS = halt
|
||||
endif
|
||||
|
||||
all: $(PROGRAMS)
|
||||
@@ -188,6 +189,11 @@ fileIO_test3: fileIO_test3.o start.o
|
||||
$(LD) $(LDFLAGS) start.o fileIO_test3.o -o fileIO_test3.coff
|
||||
$(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:
|
||||
$(RM) -f *.o *.ii
|
||||
@@ -196,6 +202,14 @@ clean:
|
||||
distclean: clean
|
||||
$(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:
|
||||
@echo Host type could not be determined.
|
||||
@echo make is terminating.
|
||||
|
||||
BIN
code/test/add
BIN
code/test/add
Binary file not shown.
Binary file not shown.
@@ -1,12 +1,9 @@
|
||||
#include "syscall.h"
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
int n;
|
||||
for (n=9;n>5;n--) {
|
||||
PrintInt(n);
|
||||
}
|
||||
Halt();
|
||||
int main() {
|
||||
int n;
|
||||
for (n = 9; n > 5; n--)
|
||||
PrintInt(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1,13 +1,11 @@
|
||||
#include "syscall.h"
|
||||
|
||||
int
|
||||
main()
|
||||
int main()
|
||||
{
|
||||
int n;
|
||||
for (n=15;n<=19;n++){
|
||||
|
||||
for (n=15;n<=19;n++){
|
||||
PrintInt(n);
|
||||
}
|
||||
Halt();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
1
code/test/file1.test
Normal file
1
code/test/file1.test
Normal file
@@ -0,0 +1 @@
|
||||
abcdefghijklmnopqrstuvwxyz
|
||||
Binary file not shown.
Binary file not shown.
BIN
code/test/halt
BIN
code/test/halt
Binary file not shown.
@@ -1,3 +1,4 @@
|
||||
make clean
|
||||
make
|
||||
../build.linux/nachos -e halt
|
||||
make distclean
|
||||
make
|
||||
timeout 1 ../build.linux/nachos -e consoleIO_test1 -e consoleIO_test2
|
||||
echo 'done'
|
||||
|
||||
@@ -186,6 +186,14 @@ ThreadJoin:
|
||||
j $31
|
||||
.end ThreadJoin
|
||||
|
||||
.globl PrintInt
|
||||
.ent PrintInt
|
||||
PrintInt:
|
||||
addiu $2,$0,SC_PrintInt
|
||||
syscall
|
||||
j $31
|
||||
.end PrintInt
|
||||
|
||||
|
||||
/* dummy function to keep gcc happy */
|
||||
.globl __main
|
||||
|
||||
6
code/test/test.c
Normal file
6
code/test/test.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "syscall.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
Exit(0);
|
||||
}
|
||||
@@ -26,58 +26,60 @@
|
||||
|
||||
Kernel::Kernel(int argc, char **argv)
|
||||
{
|
||||
randomSlice = FALSE;
|
||||
debugUserProg = FALSE;
|
||||
consoleIn = NULL; // default is stdin
|
||||
consoleOut = NULL; // default is stdout
|
||||
execfileNum = 0;
|
||||
threadNum = 0;
|
||||
randomSlice = FALSE;
|
||||
debugUserProg = FALSE;
|
||||
consoleIn = NULL; // default is stdin
|
||||
consoleOut = NULL; // default is stdout
|
||||
#ifndef FILESYS_STUB
|
||||
formatFlag = FALSE;
|
||||
formatFlag = FALSE;
|
||||
#endif
|
||||
reliability = 1; // network reliability, default is 1.0
|
||||
hostName = 0; // machine id, also UNIX socket name
|
||||
// 0 is the default machine id
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-rs") == 0) {
|
||||
ASSERT(i + 1 < argc);
|
||||
RandomInit(atoi(argv[i + 1]));// initialize pseudo-random
|
||||
// number generator
|
||||
randomSlice = TRUE;
|
||||
i++;
|
||||
} else if (strcmp(argv[i], "-s") == 0) {
|
||||
debugUserProg = TRUE;
|
||||
} else if (strcmp(argv[i], "-e") == 0) {
|
||||
execfile[++execfileNum]= argv[++i];
|
||||
cout << execfile[execfileNum] << "\n";
|
||||
} else if (strcmp(argv[i], "-ci") == 0) {
|
||||
ASSERT(i + 1 < argc);
|
||||
consoleIn = argv[i + 1];
|
||||
i++;
|
||||
} else if (strcmp(argv[i], "-co") == 0) {
|
||||
ASSERT(i + 1 < argc);
|
||||
consoleOut = argv[i + 1];
|
||||
i++;
|
||||
reliability = 1; // network reliability, default is 1.0
|
||||
hostName = 0; // machine id, also UNIX socket name
|
||||
// 0 is the default machine id
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-rs") == 0) {
|
||||
ASSERT(i + 1 < argc);
|
||||
RandomInit(atoi(argv[i + 1]));// initialize pseudo-random
|
||||
// number generator
|
||||
randomSlice = TRUE;
|
||||
i++;
|
||||
} else if (strcmp(argv[i], "-s") == 0) {
|
||||
debugUserProg = TRUE;
|
||||
} else if (strcmp(argv[i], "-e") == 0) {
|
||||
execfile[++execfileNum]= argv[++i];
|
||||
cout << execfile[execfileNum] << "\n";
|
||||
} else if (strcmp(argv[i], "-ci") == 0) {
|
||||
ASSERT(i + 1 < argc);
|
||||
consoleIn = argv[i + 1];
|
||||
i++;
|
||||
} else if (strcmp(argv[i], "-co") == 0) {
|
||||
ASSERT(i + 1 < argc);
|
||||
consoleOut = argv[i + 1];
|
||||
i++;
|
||||
#ifndef FILESYS_STUB
|
||||
} else if (strcmp(argv[i], "-f") == 0) {
|
||||
formatFlag = TRUE;
|
||||
} else if (strcmp(argv[i], "-f") == 0) {
|
||||
formatFlag = TRUE;
|
||||
#endif
|
||||
} else if (strcmp(argv[i], "-n") == 0) {
|
||||
ASSERT(i + 1 < argc); // next argument is float
|
||||
reliability = atof(argv[i + 1]);
|
||||
i++;
|
||||
} else if (strcmp(argv[i], "-m") == 0) {
|
||||
ASSERT(i + 1 < argc); // next argument is int
|
||||
hostName = atoi(argv[i + 1]);
|
||||
i++;
|
||||
} else if (strcmp(argv[i], "-u") == 0) {
|
||||
cout << "Partial usage: nachos [-rs randomSeed]\n";
|
||||
cout << "Partial usage: nachos [-s]\n";
|
||||
cout << "Partial usage: nachos [-ci consoleIn] [-co consoleOut]\n";
|
||||
} else if (strcmp(argv[i], "-n") == 0) {
|
||||
ASSERT(i + 1 < argc); // next argument is float
|
||||
reliability = atof(argv[i + 1]);
|
||||
i++;
|
||||
} else if (strcmp(argv[i], "-m") == 0) {
|
||||
ASSERT(i + 1 < argc); // next argument is int
|
||||
hostName = atoi(argv[i + 1]);
|
||||
i++;
|
||||
} else if (strcmp(argv[i], "-u") == 0) {
|
||||
cout << "Partial usage: nachos [-rs randomSeed]\n";
|
||||
cout << "Partial usage: nachos [-s]\n";
|
||||
cout << "Partial usage: nachos [-ci consoleIn] [-co consoleOut]\n";
|
||||
#ifndef FILESYS_STUB
|
||||
cout << "Partial usage: nachos [-nf]\n";
|
||||
cout << "Partial usage: nachos [-nf]\n";
|
||||
#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
|
||||
Kernel::Initialize()
|
||||
{
|
||||
// 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
|
||||
// object to save its state.
|
||||
// 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
|
||||
// object to save its state.
|
||||
|
||||
|
||||
currentThread = new Thread("main", threadNum++);
|
||||
currentThread->setStatus(RUNNING);
|
||||
|
||||
stats = new Statistics(); // collect statistics
|
||||
interrupt = new Interrupt; // start up interrupt handling
|
||||
scheduler = new Scheduler(); // initialize the ready queue
|
||||
alarm = new Alarm(randomSlice); // start up time slicing
|
||||
machine = new Machine(debugUserProg);
|
||||
synchConsoleIn = new SynchConsoleInput(consoleIn); // input from stdin
|
||||
synchConsoleOut = new SynchConsoleOutput(consoleOut); // output to stdout
|
||||
synchDisk = new SynchDisk(); //
|
||||
currentThread = new Thread("main", threadNum++);
|
||||
currentThread->setStatus(RUNNING);
|
||||
|
||||
stats = new Statistics(); // collect statistics
|
||||
interrupt = new Interrupt; // start up interrupt handling
|
||||
scheduler = new Scheduler(); // initialize the ready queue
|
||||
alarm = new Alarm(randomSlice); // start up time slicing
|
||||
machine = new Machine(debugUserProg);
|
||||
synchConsoleIn = new SynchConsoleInput(consoleIn); // input from stdin
|
||||
synchConsoleOut = new SynchConsoleOutput(consoleOut); // output to stdout
|
||||
synchDisk = new SynchDisk(); //
|
||||
#ifdef FILESYS_STUB
|
||||
fileSystem = new FileSystem();
|
||||
fileSystem = new FileSystem();
|
||||
#else
|
||||
fileSystem = new FileSystem(formatFlag);
|
||||
fileSystem = new FileSystem(formatFlag);
|
||||
#endif // FILESYS_STUB
|
||||
postOfficeIn = new PostOfficeInput(10);
|
||||
postOfficeOut = new PostOfficeOutput(reliability);
|
||||
postOfficeIn = new PostOfficeInput(10);
|
||||
postOfficeOut = new PostOfficeOutput(reliability);
|
||||
frameTable = new FrameTable;
|
||||
|
||||
interrupt->Enable();
|
||||
interrupt->Enable();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -124,19 +127,20 @@ Kernel::Initialize()
|
||||
|
||||
Kernel::~Kernel()
|
||||
{
|
||||
delete stats;
|
||||
delete interrupt;
|
||||
delete scheduler;
|
||||
delete alarm;
|
||||
delete machine;
|
||||
delete synchConsoleIn;
|
||||
delete synchConsoleOut;
|
||||
delete synchDisk;
|
||||
delete fileSystem;
|
||||
delete postOfficeIn;
|
||||
delete postOfficeOut;
|
||||
|
||||
Exit(0);
|
||||
delete stats;
|
||||
delete interrupt;
|
||||
delete scheduler;
|
||||
delete alarm;
|
||||
delete machine;
|
||||
delete synchConsoleIn;
|
||||
delete synchConsoleOut;
|
||||
delete synchDisk;
|
||||
delete fileSystem;
|
||||
delete postOfficeIn;
|
||||
delete postOfficeOut;
|
||||
delete frameTable;
|
||||
|
||||
Exit(0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -239,7 +243,7 @@ Kernel::NetworkTest() {
|
||||
postOfficeOut->Send(outPktHdr, outMailHdr, ack);
|
||||
|
||||
// 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 "
|
||||
<< inMailHdr.from << "\n";
|
||||
cout.flush();
|
||||
@@ -250,12 +254,10 @@ Kernel::NetworkTest() {
|
||||
|
||||
void ForkExecute(Thread *t)
|
||||
{
|
||||
if ( !t->space->Load(t->getName()) ) {
|
||||
return; // executable not found
|
||||
}
|
||||
|
||||
t->space->Execute(t->getName());
|
||||
if (!t->space->Load(t->getName()))
|
||||
return; // executable not found
|
||||
|
||||
t->space->Execute(t->getName());
|
||||
}
|
||||
|
||||
void Kernel::ExecAll()
|
||||
@@ -273,9 +275,8 @@ int Kernel::Exec(char* name)
|
||||
t[threadNum] = new Thread(name, threadNum);
|
||||
t[threadNum]->space = new AddrSpace();
|
||||
t[threadNum]->Fork((VoidFunctionPtr) &ForkExecute, (void *)t[threadNum]);
|
||||
threadNum++;
|
||||
|
||||
return threadNum-1;
|
||||
return threadNum++;
|
||||
/*
|
||||
cout << "Total threads number is " << execfileNum << endl;
|
||||
for (int n=1;n<=execfileNum;n++) {
|
||||
@@ -308,4 +309,7 @@ int Kernel::CreateFile(char *filename)
|
||||
return fileSystem->Create(filename);
|
||||
}
|
||||
|
||||
|
||||
void Kernel::PrintInt(int value)
|
||||
{
|
||||
return synchConsoleOut->PutInt(value);
|
||||
}
|
||||
|
||||
@@ -36,15 +36,17 @@ class Kernel {
|
||||
void Initialize(); // initialize the kernel -- separated
|
||||
// from constructor because
|
||||
// refers to "kernel" as a global
|
||||
void ExecAll();
|
||||
int Exec(char* name);
|
||||
void ExecAll();
|
||||
int Exec(char* name);
|
||||
void ThreadSelfTest(); // self test of threads and synchronization
|
||||
|
||||
|
||||
void ConsoleTest(); // interactive console self test
|
||||
void NetworkTest(); // interactive 2-machine network test
|
||||
Thread* getThread(int threadID){return t[threadID];}
|
||||
|
||||
int CreateFile(char* filename); // fileSystem call
|
||||
Thread* getThread(int threadID){return t[threadID];}
|
||||
|
||||
void PrintInt(int n);
|
||||
|
||||
int CreateFile(char* filename); // fileSystem call
|
||||
|
||||
// These are public for notational convenience; really,
|
||||
// they're global variables used everywhere.
|
||||
@@ -58,18 +60,19 @@ class Kernel {
|
||||
SynchConsoleInput *synchConsoleIn;
|
||||
SynchConsoleOutput *synchConsoleOut;
|
||||
SynchDisk *synchDisk;
|
||||
FileSystem *fileSystem;
|
||||
FileSystem *fileSystem;
|
||||
PostOfficeInput *postOfficeIn;
|
||||
PostOfficeOutput *postOfficeOut;
|
||||
FrameTable *frameTable;
|
||||
|
||||
int hostName; // machine identifier
|
||||
|
||||
private:
|
||||
|
||||
Thread* t[10];
|
||||
char* execfile[10];
|
||||
int execfileNum;
|
||||
int threadNum;
|
||||
Thread* t[10];
|
||||
char* execfile[10];
|
||||
int execfileNum;
|
||||
int threadNum;
|
||||
bool randomSlice; // enable pseudo-random time slicing
|
||||
bool debugUserProg; // single step user program
|
||||
double reliability; // likelihood messages are dropped
|
||||
|
||||
@@ -74,13 +74,13 @@ Scheduler::ReadyToRun (Thread *thread)
|
||||
Thread *
|
||||
Scheduler::FindNextToRun ()
|
||||
{
|
||||
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
||||
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
||||
|
||||
if (readyList->IsEmpty()) {
|
||||
return NULL;
|
||||
} else {
|
||||
return readyList->RemoveFront();
|
||||
}
|
||||
if (readyList->IsEmpty()) {
|
||||
return NULL;
|
||||
} else {
|
||||
return readyList->RemoveFront();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -103,50 +103,50 @@ Scheduler::FindNextToRun ()
|
||||
void
|
||||
Scheduler::Run (Thread *nextThread, bool finishing)
|
||||
{
|
||||
Thread *oldThread = kernel->currentThread;
|
||||
|
||||
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
||||
Thread *oldThread = kernel->currentThread;
|
||||
|
||||
if (finishing) { // mark that we need to delete current thread
|
||||
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
|
||||
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
||||
|
||||
kernel->currentThread = nextThread; // switch to the next thread
|
||||
nextThread->setStatus(RUNNING); // nextThread is now running
|
||||
|
||||
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".
|
||||
if (finishing) { // mark that we need to delete current thread
|
||||
ASSERT(toBeDestroyed == NULL);
|
||||
toBeDestroyed = oldThread;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// interrupts are off when we return from switch!
|
||||
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
||||
oldThread->CheckOverflow(); // check if the old thread
|
||||
// had an undetected stack overflow
|
||||
|
||||
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
|
||||
// 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();
|
||||
}
|
||||
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);
|
||||
|
||||
// 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
|
||||
Scheduler::CheckToBeDestroyed()
|
||||
{
|
||||
if (toBeDestroyed != NULL) {
|
||||
delete toBeDestroyed;
|
||||
toBeDestroyed = NULL;
|
||||
}
|
||||
if (toBeDestroyed != NULL) {
|
||||
delete toBeDestroyed;
|
||||
toBeDestroyed = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
@@ -35,17 +35,17 @@ const int STACK_FENCEPOST = 0xdedbeef;
|
||||
|
||||
Thread::Thread(char* threadName, int threadID)
|
||||
{
|
||||
ID = threadID;
|
||||
name = threadName;
|
||||
stackTop = NULL;
|
||||
stack = NULL;
|
||||
status = JUST_CREATED;
|
||||
for (int i = 0; i < MachineStateSize; i++) {
|
||||
machineState[i] = NULL; // not strictly necessary, since
|
||||
// new thread ignores contents
|
||||
// of machine registers
|
||||
}
|
||||
space = NULL;
|
||||
ID = threadID;
|
||||
name = threadName;
|
||||
stackTop = NULL;
|
||||
stack = NULL;
|
||||
status = JUST_CREATED;
|
||||
for (int i = 0; i < MachineStateSize; i++) {
|
||||
machineState[i] = NULL; // not strictly necessary, since
|
||||
// new thread ignores contents
|
||||
// of machine registers
|
||||
}
|
||||
space = NULL;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -62,10 +62,10 @@ Thread::Thread(char* threadName, int threadID)
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
DEBUG(dbgThread, "Deleting thread: " << name);
|
||||
ASSERT(this != kernel->currentThread);
|
||||
if (stack != NULL)
|
||||
DeallocBoundedArray((char *) stack, StackSize * sizeof(int));
|
||||
DEBUG(dbgThread, "Deleting thread: " << name);
|
||||
ASSERT(this != kernel->currentThread);
|
||||
if (stack != NULL)
|
||||
DeallocBoundedArray((char *) stack, StackSize * sizeof(int));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -91,17 +91,17 @@ Thread::~Thread()
|
||||
void
|
||||
Thread::Fork(VoidFunctionPtr func, void *arg)
|
||||
{
|
||||
Interrupt *interrupt = kernel->interrupt;
|
||||
Scheduler *scheduler = kernel->scheduler;
|
||||
IntStatus oldLevel;
|
||||
|
||||
DEBUG(dbgThread, "Forking thread: " << name << " f(a): " << (int) func << " " << arg);
|
||||
StackAllocate(func, arg);
|
||||
Interrupt *interrupt = kernel->interrupt;
|
||||
Scheduler *scheduler = kernel->scheduler;
|
||||
IntStatus oldLevel;
|
||||
|
||||
oldLevel = interrupt->SetLevel(IntOff);
|
||||
scheduler->ReadyToRun(this); // ReadyToRun assumes that interrupts
|
||||
// are disabled!
|
||||
(void) interrupt->SetLevel(oldLevel);
|
||||
DEBUG(dbgThread, "Forking thread: " << name << " f(a): " << (int) func << " " << arg);
|
||||
StackAllocate(func, arg);
|
||||
|
||||
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
|
||||
Thread::CheckOverflow()
|
||||
{
|
||||
if (stack != NULL) {
|
||||
if (stack != NULL) {
|
||||
#ifdef HPUX // Stacks grow upward on the Snakes
|
||||
ASSERT(stack[StackSize - 1] == STACK_FENCEPOST);
|
||||
ASSERT(stack[StackSize - 1] == STACK_FENCEPOST);
|
||||
#else
|
||||
ASSERT(*stack == STACK_FENCEPOST);
|
||||
ASSERT(*stack == STACK_FENCEPOST);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -170,12 +170,12 @@ Thread::Begin ()
|
||||
void
|
||||
Thread::Finish ()
|
||||
{
|
||||
(void) kernel->interrupt->SetLevel(IntOff);
|
||||
ASSERT(this == kernel->currentThread);
|
||||
|
||||
DEBUG(dbgThread, "Finishing thread: " << name);
|
||||
Sleep(TRUE); // invokes SWITCH
|
||||
// not reached
|
||||
(void) kernel->interrupt->SetLevel(IntOff);
|
||||
ASSERT(this == kernel->currentThread);
|
||||
|
||||
DEBUG(dbgThread, "Finishing thread: " << name);
|
||||
Sleep(TRUE); // invokes SWITCH
|
||||
// not reached
|
||||
}
|
||||
|
||||
|
||||
@@ -200,19 +200,19 @@ Thread::Finish ()
|
||||
void
|
||||
Thread::Yield ()
|
||||
{
|
||||
Thread *nextThread;
|
||||
IntStatus oldLevel = kernel->interrupt->SetLevel(IntOff);
|
||||
|
||||
ASSERT(this == kernel->currentThread);
|
||||
|
||||
DEBUG(dbgThread, "Yielding thread: " << name);
|
||||
|
||||
nextThread = kernel->scheduler->FindNextToRun();
|
||||
if (nextThread != NULL) {
|
||||
kernel->scheduler->ReadyToRun(this);
|
||||
kernel->scheduler->Run(nextThread, FALSE);
|
||||
}
|
||||
(void) kernel->interrupt->SetLevel(oldLevel);
|
||||
Thread *nextThread;
|
||||
IntStatus oldLevel = kernel->interrupt->SetLevel(IntOff);
|
||||
|
||||
ASSERT(this == kernel->currentThread);
|
||||
|
||||
DEBUG(dbgThread, "Yielding thread: " << name);
|
||||
|
||||
nextThread = kernel->scheduler->FindNextToRun();
|
||||
if (nextThread != NULL) {
|
||||
kernel->scheduler->ReadyToRun(this);
|
||||
kernel->scheduler->Run(nextThread, FALSE);
|
||||
}
|
||||
(void) kernel->interrupt->SetLevel(oldLevel);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -238,20 +238,20 @@ Thread::Yield ()
|
||||
void
|
||||
Thread::Sleep (bool finishing)
|
||||
{
|
||||
Thread *nextThread;
|
||||
|
||||
ASSERT(this == kernel->currentThread);
|
||||
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
||||
|
||||
DEBUG(dbgThread, "Sleeping thread: " << name);
|
||||
Thread *nextThread;
|
||||
|
||||
status = BLOCKED;
|
||||
//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);
|
||||
ASSERT(this == kernel->currentThread);
|
||||
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
||||
|
||||
DEBUG(dbgThread, "Sleeping thread: " << name);
|
||||
|
||||
status = BLOCKED;
|
||||
//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.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
static void ThreadFinish() { kernel->currentThread->Finish(); }
|
||||
static void ThreadFinish() { kernel->currentThread->Finish(); }
|
||||
static void ThreadBegin() { kernel->currentThread->Begin(); }
|
||||
void ThreadPrint(Thread *t) { t->Print(); }
|
||||
|
||||
@@ -277,16 +277,16 @@ void ThreadPrint(Thread *t) { t->Print(); }
|
||||
static void *
|
||||
PLabelToAddr(void *plabel)
|
||||
{
|
||||
int funcPtr = (int) plabel;
|
||||
int funcPtr = (int) plabel;
|
||||
|
||||
if (funcPtr & 0x02) {
|
||||
// L-Field is set. This is a PLT pointer
|
||||
funcPtr -= 2; // Get rid of the L bit
|
||||
return (*(void **)funcPtr);
|
||||
} else {
|
||||
// L-field not set.
|
||||
return plabel;
|
||||
}
|
||||
if (funcPtr & 0x02) {
|
||||
// L-Field is set. This is a PLT pointer
|
||||
funcPtr -= 2; // Get rid of the L bit
|
||||
return (*(void **)funcPtr);
|
||||
} else {
|
||||
// L-field not set.
|
||||
return plabel;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -305,59 +305,59 @@ PLabelToAddr(void *plabel)
|
||||
void
|
||||
Thread::StackAllocate (VoidFunctionPtr func, void *arg)
|
||||
{
|
||||
stack = (int *) AllocBoundedArray(StackSize * sizeof(int));
|
||||
stack = (int *) AllocBoundedArray(StackSize * sizeof(int));
|
||||
|
||||
#ifdef PARISC
|
||||
// HP stack works from low addresses to high addresses
|
||||
// everyone else works the other way: from high addresses to low addresses
|
||||
stackTop = stack + 16; // HP requires 64-byte frame marker
|
||||
stack[StackSize - 1] = STACK_FENCEPOST;
|
||||
// HP stack works from low addresses to high addresses
|
||||
// everyone else works the other way: from high addresses to low addresses
|
||||
stackTop = stack + 16; // HP requires 64-byte frame marker
|
||||
stack[StackSize - 1] = STACK_FENCEPOST;
|
||||
#endif
|
||||
|
||||
#ifdef SPARC
|
||||
stackTop = stack + StackSize - 96; // SPARC stack must contains at
|
||||
// least 1 activation record
|
||||
// to start with.
|
||||
*stack = STACK_FENCEPOST;
|
||||
stackTop = stack + StackSize - 96; // SPARC stack must contains at
|
||||
// least 1 activation record
|
||||
// to start with.
|
||||
*stack = STACK_FENCEPOST;
|
||||
#endif
|
||||
|
||||
#ifdef PowerPC // RS6000
|
||||
stackTop = stack + StackSize - 16; // RS6000 requires 64-byte frame marker
|
||||
*stack = STACK_FENCEPOST;
|
||||
stackTop = stack + StackSize - 16; // RS6000 requires 64-byte frame marker
|
||||
*stack = STACK_FENCEPOST;
|
||||
#endif
|
||||
|
||||
#ifdef DECMIPS
|
||||
stackTop = stack + StackSize - 4; // -4 to be on the safe side!
|
||||
*stack = STACK_FENCEPOST;
|
||||
stackTop = stack + StackSize - 4; // -4 to be on the safe side!
|
||||
*stack = STACK_FENCEPOST;
|
||||
#endif
|
||||
|
||||
#ifdef ALPHA
|
||||
stackTop = stack + StackSize - 8; // -8 to be on the safe side!
|
||||
*stack = STACK_FENCEPOST;
|
||||
stackTop = stack + StackSize - 8; // -8 to be on the safe side!
|
||||
*stack = STACK_FENCEPOST;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef x86
|
||||
// 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
|
||||
// used in SWITCH() must be the starting address of ThreadRoot.
|
||||
stackTop = stack + StackSize - 4; // -4 to be on the safe side!
|
||||
*(--stackTop) = (int) ThreadRoot;
|
||||
*stack = STACK_FENCEPOST;
|
||||
// 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
|
||||
// used in SWITCH() must be the starting address of ThreadRoot.
|
||||
stackTop = stack + StackSize - 4; // -4 to be on the safe side!
|
||||
*(--stackTop) = (int) ThreadRoot;
|
||||
*stack = STACK_FENCEPOST;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PARISC
|
||||
machineState[PCState] = PLabelToAddr(ThreadRoot);
|
||||
machineState[StartupPCState] = PLabelToAddr(ThreadBegin);
|
||||
machineState[InitialPCState] = PLabelToAddr(func);
|
||||
machineState[InitialArgState] = arg;
|
||||
machineState[WhenDonePCState] = PLabelToAddr(ThreadFinish);
|
||||
machineState[PCState] = PLabelToAddr(ThreadRoot);
|
||||
machineState[StartupPCState] = PLabelToAddr(ThreadBegin);
|
||||
machineState[InitialPCState] = PLabelToAddr(func);
|
||||
machineState[InitialArgState] = arg;
|
||||
machineState[WhenDonePCState] = PLabelToAddr(ThreadFinish);
|
||||
#else
|
||||
machineState[PCState] = (void*)ThreadRoot;
|
||||
machineState[StartupPCState] = (void*)ThreadBegin;
|
||||
machineState[InitialPCState] = (void*)func;
|
||||
machineState[InitialArgState] = (void*)arg;
|
||||
machineState[WhenDonePCState] = (void*)ThreadFinish;
|
||||
machineState[PCState] = (void*)ThreadRoot;
|
||||
machineState[StartupPCState] = (void*)ThreadBegin;
|
||||
machineState[InitialPCState] = (void*)func;
|
||||
machineState[InitialArgState] = (void*)arg;
|
||||
machineState[WhenDonePCState] = (void*)ThreadFinish;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -391,8 +391,8 @@ Thread::SaveUserState()
|
||||
void
|
||||
Thread::RestoreUserState()
|
||||
{
|
||||
for (int i = 0; i < NumTotalRegs; i++)
|
||||
kernel->machine->WriteRegister(i, userRegisters[i]);
|
||||
for (int i = 0; i < NumTotalRegs; i++)
|
||||
kernel->machine->WriteRegister(i, userRegisters[i]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -31,32 +31,97 @@
|
||||
static void
|
||||
SwapHeader (NoffHeader *noffH)
|
||||
{
|
||||
noffH->noffMagic = WordToHost(noffH->noffMagic);
|
||||
noffH->code.size = WordToHost(noffH->code.size);
|
||||
noffH->code.virtualAddr = WordToHost(noffH->code.virtualAddr);
|
||||
noffH->code.inFileAddr = WordToHost(noffH->code.inFileAddr);
|
||||
noffH->noffMagic = WordToHost(noffH->noffMagic);
|
||||
noffH->code.size = WordToHost(noffH->code.size);
|
||||
noffH->code.virtualAddr = WordToHost(noffH->code.virtualAddr);
|
||||
noffH->code.inFileAddr = WordToHost(noffH->code.inFileAddr);
|
||||
#ifdef RDATA
|
||||
noffH->readonlyData.size = WordToHost(noffH->readonlyData.size);
|
||||
noffH->readonlyData.virtualAddr =
|
||||
WordToHost(noffH->readonlyData.virtualAddr);
|
||||
noffH->readonlyData.inFileAddr =
|
||||
WordToHost(noffH->readonlyData.inFileAddr);
|
||||
noffH->readonlyData.size = WordToHost(noffH->readonlyData.size);
|
||||
noffH->readonlyData.virtualAddr =
|
||||
WordToHost(noffH->readonlyData.virtualAddr);
|
||||
noffH->readonlyData.inFileAddr =
|
||||
WordToHost(noffH->readonlyData.inFileAddr);
|
||||
#endif
|
||||
noffH->initData.size = WordToHost(noffH->initData.size);
|
||||
noffH->initData.virtualAddr = WordToHost(noffH->initData.virtualAddr);
|
||||
noffH->initData.inFileAddr = WordToHost(noffH->initData.inFileAddr);
|
||||
noffH->uninitData.size = WordToHost(noffH->uninitData.size);
|
||||
noffH->uninitData.virtualAddr = WordToHost(noffH->uninitData.virtualAddr);
|
||||
noffH->uninitData.inFileAddr = WordToHost(noffH->uninitData.inFileAddr);
|
||||
noffH->initData.size = WordToHost(noffH->initData.size);
|
||||
noffH->initData.virtualAddr = WordToHost(noffH->initData.virtualAddr);
|
||||
noffH->initData.inFileAddr = WordToHost(noffH->initData.inFileAddr);
|
||||
noffH->uninitData.size = WordToHost(noffH->uninitData.size);
|
||||
noffH->uninitData.virtualAddr = WordToHost(noffH->uninitData.virtualAddr);
|
||||
noffH->uninitData.inFileAddr = WordToHost(noffH->uninitData.inFileAddr);
|
||||
|
||||
#ifdef RDATA
|
||||
DEBUG(dbgAddr, "code = " << noffH->code.size <<
|
||||
" readonly = " << noffH->readonlyData.size <<
|
||||
" init = " << noffH->initData.size <<
|
||||
" uninit = " << noffH->uninitData.size << "\n");
|
||||
DEBUG(dbgAddr, "code = " << noffH->code.size <<
|
||||
" readonly = " << noffH->readonlyData.size <<
|
||||
" init = " << noffH->initData.size <<
|
||||
" uninit = " << noffH->uninitData.size << "\n");
|
||||
#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
|
||||
// Create an address space to run a user program.
|
||||
@@ -66,20 +131,7 @@ SwapHeader (NoffHeader *noffH)
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
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
|
||||
@@ -88,7 +140,10 @@ 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
|
||||
AddrSpace::Load(char *fileName)
|
||||
{
|
||||
OpenFile *executable = kernel->fileSystem->Open(fileName);
|
||||
NoffHeader noffH;
|
||||
unsigned int size;
|
||||
//cerr << "AddrSpace::Load" << endl;
|
||||
OpenFile *executable = kernel->fileSystem->Open(fileName);
|
||||
NoffHeader noffH;
|
||||
unsigned int size;
|
||||
|
||||
if (executable == NULL) {
|
||||
cerr << "Unable to open file " << fileName << "\n";
|
||||
return FALSE;
|
||||
}
|
||||
if (executable == NULL) {
|
||||
cerr << "Unable to open file " << fileName << "\n";
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
executable->ReadAt((char *)&noffH, sizeof(noffH), 0);
|
||||
if ((noffH.noffMagic != NOFFMAGIC) &&
|
||||
(WordToHost(noffH.noffMagic) == NOFFMAGIC))
|
||||
SwapHeader(&noffH);
|
||||
ASSERT(noffH.noffMagic == NOFFMAGIC);
|
||||
executable->ReadAt((char *)&noffH, sizeof(noffH), 0);
|
||||
if ((noffH.noffMagic != NOFFMAGIC) &&
|
||||
(WordToHost(noffH.noffMagic) == NOFFMAGIC))
|
||||
SwapHeader(&noffH);
|
||||
ASSERT(noffH.noffMagic == NOFFMAGIC);
|
||||
|
||||
#ifdef RDATA
|
||||
// how big is address space?
|
||||
size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size +
|
||||
noffH.uninitData.size + UserStackSize;
|
||||
// we need to increase the size
|
||||
// to leave room for the stack
|
||||
size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size +
|
||||
noffH.uninitData.size + UserStackSize;
|
||||
//cerr << noffH.code.size << ' '
|
||||
// << noffH.readonlyData.size << ' '
|
||||
// << noffH.initData.size << ' '
|
||||
// << noffH.uninitData.size << ' '
|
||||
// << UserStackSize << endl;
|
||||
// we need to increase the size
|
||||
// to leave room for the stack
|
||||
#else
|
||||
// how big is address space?
|
||||
size = noffH.code.size + noffH.initData.size + noffH.uninitData.size
|
||||
+ UserStackSize; // we need to increase the size
|
||||
// to leave room for the stack
|
||||
size = noffH.code.size + noffH.initData.size + noffH.uninitData.size
|
||||
+ UserStackSize; // we need to increase the size
|
||||
// to leave room for the stack
|
||||
//cerr << noffH.code.size << ' '
|
||||
// << noffH.initData.size << ' '
|
||||
// << noffH.uninitData.size << ' '
|
||||
// << UserStackSize << endl;
|
||||
#endif
|
||||
numPages = divRoundUp(size, PageSize);
|
||||
size = numPages * PageSize;
|
||||
numPages = divRoundUp(size, PageSize);
|
||||
size = numPages * PageSize;
|
||||
|
||||
ASSERT(numPages <= NumPhysPages); // check we're not trying
|
||||
// to run anything too big --
|
||||
// at least until we have
|
||||
// virtual memory
|
||||
ASSERT(numPages <= NumPhysPages); // check we're not trying
|
||||
// to run anything too big --
|
||||
// at least until we have
|
||||
// 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
|
||||
// Note: this code assumes that virtual address = physical address
|
||||
if (noffH.code.size > 0) {
|
||||
DEBUG(dbgAddr, "Initializing code segment.");
|
||||
DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size);
|
||||
executable->ReadAt(
|
||||
&(kernel->machine->mainMemory[noffH.code.virtualAddr]),
|
||||
noffH.code.size, noffH.code.inFileAddr);
|
||||
if (noffH.code.size > 0) {
|
||||
DEBUG(dbgAddr, "Initializing code segment.");
|
||||
DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size);
|
||||
|
||||
for (size_t cur = 0; cur < (size_t)noffH.code.size; cur += PageSize) {
|
||||
size_t physAddr, size = min((size_t)PageSize, noffH.code.size - cur);
|
||||
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.");
|
||||
DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size);
|
||||
executable->ReadAt(
|
||||
&(kernel->machine->mainMemory[noffH.initData.virtualAddr]),
|
||||
noffH.initData.size, noffH.initData.inFileAddr);
|
||||
}
|
||||
if (noffH.initData.size > 0) {
|
||||
DEBUG(dbgAddr, "Initializing data segment.");
|
||||
DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size);
|
||||
|
||||
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
|
||||
if (noffH.readonlyData.size > 0) {
|
||||
DEBUG(dbgAddr, "Initializing read only data segment.");
|
||||
DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size);
|
||||
executable->ReadAt(
|
||||
&(kernel->machine->mainMemory[noffH.readonlyData.virtualAddr]),
|
||||
noffH.readonlyData.size, noffH.readonlyData.inFileAddr);
|
||||
if (noffH.readonlyData.size > 0) {
|
||||
DEBUG(dbgAddr, "Initializing read only data segment.");
|
||||
DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size);
|
||||
|
||||
for (size_t cur = 0; cur < (size_t)noffH.readonlyData.size; cur += PageSize) {
|
||||
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
|
||||
|
||||
delete executable; // close file
|
||||
return TRUE; // success
|
||||
delete executable; // close file
|
||||
return TRUE; // success
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -185,17 +278,17 @@ AddrSpace::Load(char *fileName)
|
||||
void
|
||||
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
|
||||
this->RestoreState(); // load page table register
|
||||
kernel->machine->Run(); // jump to the user progam
|
||||
|
||||
kernel->machine->Run(); // jump to the user progam
|
||||
|
||||
ASSERTNOTREACHED(); // machine->Run never returns;
|
||||
// the address space exits
|
||||
// by doing the syscall "exit"
|
||||
ASSERTNOTREACHED(); // machine->Run never returns;
|
||||
// the address space exits
|
||||
// by doing the syscall "exit"
|
||||
}
|
||||
|
||||
|
||||
@@ -212,27 +305,27 @@ AddrSpace::Execute(char* fileName)
|
||||
void
|
||||
AddrSpace::InitRegisters()
|
||||
{
|
||||
Machine *machine = kernel->machine;
|
||||
int i;
|
||||
Machine *machine = kernel->machine;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NumTotalRegs; i++)
|
||||
machine->WriteRegister(i, 0);
|
||||
for (i = 0; i < NumTotalRegs; i++)
|
||||
machine->WriteRegister(i, 0);
|
||||
|
||||
// Initial program counter -- must be location of "Start", which
|
||||
// is assumed to be virtual address zero
|
||||
machine->WriteRegister(PCReg, 0);
|
||||
// Initial program counter -- must be location of "Start", which
|
||||
// is assumed to be virtual address zero
|
||||
machine->WriteRegister(PCReg, 0);
|
||||
|
||||
// Need to also tell MIPS where next instruction is, because
|
||||
// of branch delay possibility
|
||||
// Since instructions occupy four bytes each, the next instruction
|
||||
// after start will be at virtual address four.
|
||||
machine->WriteRegister(NextPCReg, 4);
|
||||
// Need to also tell MIPS where next instruction is, because
|
||||
// of branch delay possibility
|
||||
// Since instructions occupy four bytes each, the next instruction
|
||||
// after start will be at virtual address four.
|
||||
machine->WriteRegister(NextPCReg, 4);
|
||||
|
||||
// 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
|
||||
// accidentally reference off the end!
|
||||
machine->WriteRegister(StackReg, numPages * PageSize - 16);
|
||||
DEBUG(dbgAddr, "Initializing stack pointer: " << numPages * PageSize - 16);
|
||||
// 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
|
||||
// accidentally reference off the end!
|
||||
machine->WriteRegister(StackReg, numPages * PageSize - 16);
|
||||
DEBUG(dbgAddr, "Initializing stack pointer: " << numPages * PageSize - 16);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -256,8 +349,8 @@ void AddrSpace::SaveState()
|
||||
|
||||
void AddrSpace::RestoreState()
|
||||
{
|
||||
kernel->machine->pageTable = pageTable;
|
||||
kernel->machine->pageTableSize = numPages;
|
||||
kernel->machine->pageTable = pageTable;
|
||||
kernel->machine->pageTableSize = numPages;
|
||||
}
|
||||
|
||||
|
||||
@@ -272,45 +365,48 @@ void AddrSpace::RestoreState()
|
||||
ExceptionType
|
||||
AddrSpace::Translate(unsigned int vaddr, unsigned int *paddr, int isReadWrite)
|
||||
{
|
||||
TranslationEntry *pte;
|
||||
int pfn;
|
||||
unsigned int vpn = vaddr / PageSize;
|
||||
unsigned int offset = vaddr % PageSize;
|
||||
TranslationEntry *pte;
|
||||
int pfn;
|
||||
unsigned int vpn = vaddr / PageSize;
|
||||
unsigned int offset = vaddr % PageSize;
|
||||
|
||||
if(vpn >= numPages) {
|
||||
return AddressErrorException;
|
||||
if(vpn >= numPages) {
|
||||
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) {
|
||||
return ReadOnlyException;
|
||||
}
|
||||
pte->use = TRUE; // set the use, dirty bits
|
||||
|
||||
pfn = pte->physicalPage;
|
||||
if(isReadWrite)
|
||||
pte->dirty = TRUE;
|
||||
|
||||
// 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;
|
||||
}
|
||||
*paddr = pfn * PageSize + offset;
|
||||
|
||||
pte->use = TRUE; // set the use, dirty bits
|
||||
ASSERT((*paddr < MemorySize));
|
||||
|
||||
if(isReadWrite)
|
||||
pte->dirty = TRUE;
|
||||
//cerr << " -- AddrSpace::Translate(): vaddr: " << vaddr <<
|
||||
// ", paddr: " << *paddr << "\n";
|
||||
|
||||
*paddr = pfn*PageSize + offset;
|
||||
|
||||
ASSERT((*paddr < MemorySize));
|
||||
|
||||
//cerr << " -- AddrSpace::Translate(): vaddr: " << vaddr <<
|
||||
// ", paddr: " << *paddr << "\n";
|
||||
|
||||
return NoException;
|
||||
return NoException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,28 @@
|
||||
|
||||
#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 {
|
||||
public:
|
||||
AddrSpace(); // Create an address space.
|
||||
@@ -40,8 +62,7 @@ class AddrSpace {
|
||||
ExceptionType Translate(unsigned int vaddr, unsigned int *paddr, int mode);
|
||||
|
||||
private:
|
||||
TranslationEntry *pageTable; // Assume linear page table translation
|
||||
// for now!
|
||||
TranslationEntry *pageTable;
|
||||
unsigned int numPages; // Number of pages in the virtual
|
||||
// address space
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
// exception.cc
|
||||
// Entry point into the Nachos kernel from user programs.
|
||||
// There are two kinds of things that can cause control to
|
||||
// transfer back to here from user code:
|
||||
// Entry point into the Nachos kernel from user programs.
|
||||
// There are two kinds of things that can cause control to
|
||||
// transfer back to here from user code:
|
||||
//
|
||||
// syscall -- The user code explicitly requests to call a procedure
|
||||
// in the Nachos kernel. Right now, the only function we support is
|
||||
// "Halt".
|
||||
// syscall -- The user code explicitly requests to call a procedure
|
||||
// in the Nachos kernel. Right now, the only function we support is
|
||||
// "Halt".
|
||||
//
|
||||
// exceptions -- The user code does something that the CPU can't handle.
|
||||
// For instance, accessing memory that doesn't exist, arithmetic errors,
|
||||
// etc.
|
||||
// exceptions -- The user code does something that the CPU can't handle.
|
||||
// For instance, accessing memory that doesn't exist, arithmetic errors,
|
||||
// etc.
|
||||
//
|
||||
// Interrupts (which can also cause control to transfer from user
|
||||
// code into the Nachos kernel) are handled elsewhere.
|
||||
// Interrupts (which can also cause control to transfer from user
|
||||
// code into the Nachos kernel) are handled elsewhere.
|
||||
//
|
||||
// For now, this only handles the Halt() system call.
|
||||
// Everything else core dumps.
|
||||
@@ -27,106 +27,192 @@
|
||||
#include "ksyscall.h"
|
||||
//----------------------------------------------------------------------
|
||||
// ExceptionHandler
|
||||
// Entry point into the Nachos kernel. Called when a user program
|
||||
// is executing, and either does a syscall, or generates an addressing
|
||||
// or arithmetic exception.
|
||||
// Entry point into the Nachos kernel. Called when a user program
|
||||
// is executing, and either does a syscall, or generates an addressing
|
||||
// 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
|
||||
// arg1 -- r4
|
||||
// arg2 -- r5
|
||||
// arg3 -- r6
|
||||
// arg4 -- r7
|
||||
// system call code -- r2
|
||||
// arg1 -- r4
|
||||
// arg2 -- r5
|
||||
// arg3 -- r6
|
||||
// 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
|
||||
// before returning. (Or else you'll loop making the same system call forever!)
|
||||
//
|
||||
// "which" is the kind of exception. The list of possible exceptions
|
||||
// is in machine.h.
|
||||
// "which" is the kind of exception. The list of possible exceptions
|
||||
// is in machine.h.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
ExceptionHandler(ExceptionType which)
|
||||
{
|
||||
int type = kernel->machine->ReadRegister(2);
|
||||
int val;
|
||||
int status, exit, threadID, programID;
|
||||
DEBUG(dbgSys, "Received Exception " << which << " type: " << type << "\n");
|
||||
switch (which) {
|
||||
int type = kernel->machine->ReadRegister(2);
|
||||
int val;
|
||||
int status, exit, threadID, programID;
|
||||
DEBUG(dbgSys, "Received Exception " << which << " type: " << type << "\n");
|
||||
switch (which) {
|
||||
case SyscallException:
|
||||
switch(type) {
|
||||
case SC_Halt:
|
||||
DEBUG(dbgSys, "Shutdown, initiated by user program.\n");
|
||||
SysHalt();
|
||||
cout<<"in exception\n";
|
||||
ASSERTNOTREACHED();
|
||||
break;
|
||||
case SC_MSG:
|
||||
DEBUG(dbgSys, "Message received.\n");
|
||||
val = kernel->machine->ReadRegister(4);
|
||||
{
|
||||
char *msg = &(kernel->machine->mainMemory[val]);
|
||||
cout << msg << endl;
|
||||
}
|
||||
SysHalt();
|
||||
ASSERTNOTREACHED();
|
||||
break;
|
||||
case SC_Create:
|
||||
val = kernel->machine->ReadRegister(4);
|
||||
{
|
||||
char *filename = &(kernel->machine->mainMemory[val]);
|
||||
//cout << filename << endl;
|
||||
status = SysCreate(filename);
|
||||
kernel->machine->WriteRegister(2, (int) status);
|
||||
}
|
||||
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_Add:
|
||||
DEBUG(dbgSys, "Add " << kernel->machine->ReadRegister(4) << " + " << kernel->machine->ReadRegister(5) << "\n");
|
||||
/* Process SysAdd Systemcall*/
|
||||
int result;
|
||||
result = SysAdd(/* int op1 */(int)kernel->machine->ReadRegister(4),
|
||||
/* int op2 */(int)kernel->machine->ReadRegister(5));
|
||||
DEBUG(dbgSys, "Add returning with " << result << "\n");
|
||||
/* Prepare Result */
|
||||
kernel->machine->WriteRegister(2, (int)result);
|
||||
/* Modify return point */
|
||||
{
|
||||
/* set previous programm counter (debugging only)*/
|
||||
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
|
||||
|
||||
/* set programm counter to next instruction (all Instructions are 4 byte wide)*/
|
||||
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
||||
|
||||
/* set next programm counter for brach execution */
|
||||
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg)+4);
|
||||
}
|
||||
cout << "result is " << result << "\n";
|
||||
return;
|
||||
ASSERTNOTREACHED();
|
||||
break;
|
||||
case SC_Exit:
|
||||
DEBUG(dbgAddr, "Program exit\n");
|
||||
val=kernel->machine->ReadRegister(4);
|
||||
cout << "return value:" << val << endl;
|
||||
kernel->currentThread->Finish();
|
||||
break;
|
||||
default:
|
||||
cerr << "Unexpected system call " << type << "\n";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cerr << "Unexpected user mode exception " << (int)which << "\n";
|
||||
break;
|
||||
}
|
||||
ASSERTNOTREACHED();
|
||||
switch(type) {
|
||||
case SC_Halt:
|
||||
DEBUG(dbgSys, "Shutdown, initiated by user program.\n");
|
||||
SysHalt();
|
||||
cout<<"in exception\n";
|
||||
ASSERTNOTREACHED();
|
||||
break;
|
||||
case SC_MSG:
|
||||
DEBUG(dbgSys, "Message received.\n");
|
||||
val = kernel->machine->ReadRegister(4);
|
||||
{
|
||||
char *msg = &(kernel->machine->mainMemory[val]);
|
||||
cout << msg << endl;
|
||||
}
|
||||
SysHalt();
|
||||
ASSERTNOTREACHED();
|
||||
break;
|
||||
case SC_Create:
|
||||
val = kernel->machine->ReadRegister(4);
|
||||
{
|
||||
char *filename = &(kernel->machine->mainMemory[val]);
|
||||
//cout << filename << endl;
|
||||
status = SysCreate(filename);
|
||||
kernel->machine->WriteRegister(2, (int) status);
|
||||
}
|
||||
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_Add:
|
||||
DEBUG(dbgSys, "Add " << kernel->machine->ReadRegister(4) << " + " << kernel->machine->ReadRegister(5) << "\n");
|
||||
/* Process SysAdd Systemcall*/
|
||||
int result;
|
||||
result = SysAdd(/* int op1 */(int)kernel->machine->ReadRegister(4),
|
||||
/* int op2 */(int)kernel->machine->ReadRegister(5));
|
||||
DEBUG(dbgSys, "Add returning with " << result << "\n");
|
||||
/* Prepare Result */
|
||||
kernel->machine->WriteRegister(2, (int)result);
|
||||
/* Modify return point */
|
||||
{
|
||||
/* set previous programm counter (debugging only)*/
|
||||
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
|
||||
|
||||
/* set programm counter to next instruction (all Instructions are 4 byte wide)*/
|
||||
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
||||
|
||||
/* set next programm counter for brach execution */
|
||||
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
||||
}
|
||||
cout << "result is " << result << "\n";
|
||||
return;
|
||||
ASSERTNOTREACHED();
|
||||
break;
|
||||
case SC_Exit:
|
||||
DEBUG(dbgAddr, "Program exit\n");
|
||||
val = kernel->machine->ReadRegister(4);
|
||||
cout << "return value:" << val << endl;
|
||||
kernel->currentThread->Finish();
|
||||
break;
|
||||
case SC_PrintInt:
|
||||
DEBUG(dbgAddr, "Printing int\n");
|
||||
val = (int)kernel->machine->ReadRegister(4);
|
||||
SysPrintInt(val);
|
||||
|
||||
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_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();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +1,78 @@
|
||||
/**************************************************************
|
||||
*
|
||||
* userprog/ksyscall.h
|
||||
*
|
||||
* Kernel interface for systemcalls
|
||||
*
|
||||
* by Marcus Voelp (c) Universitaet Karlsruhe
|
||||
*
|
||||
**************************************************************/
|
||||
|
||||
#ifndef __USERPROG_KSYSCALL_H__
|
||||
#define __USERPROG_KSYSCALL_H__
|
||||
|
||||
#include "kernel.h"
|
||||
|
||||
#include "synchconsole.h"
|
||||
|
||||
|
||||
void SysHalt()
|
||||
{
|
||||
kernel->interrupt->Halt();
|
||||
}
|
||||
|
||||
int SysAdd(int op1, int op2)
|
||||
{
|
||||
return op1 + op2;
|
||||
}
|
||||
|
||||
int SysCreate(char *filename)
|
||||
{
|
||||
// return value
|
||||
// 1: success
|
||||
// 0: failed
|
||||
return kernel->interrupt->CreateFile(filename);
|
||||
}
|
||||
|
||||
|
||||
#endif /* ! __USERPROG_KSYSCALL_H__ */
|
||||
/**************************************************************
|
||||
*
|
||||
* userprog/ksyscall.h
|
||||
*
|
||||
* Kernel interface for systemcalls
|
||||
*
|
||||
* by Marcus Voelp (c) Universitaet Karlsruhe
|
||||
*
|
||||
**************************************************************/
|
||||
|
||||
#ifndef __USERPROG_KSYSCALL_H__
|
||||
#define __USERPROG_KSYSCALL_H__
|
||||
|
||||
#define INT_BUF_LENGTH 13
|
||||
|
||||
#include "kernel.h"
|
||||
|
||||
#include "synchconsole.h"
|
||||
|
||||
|
||||
void SysHalt()
|
||||
{
|
||||
kernel->interrupt->Halt();
|
||||
}
|
||||
|
||||
int SysAdd(int op1, int op2)
|
||||
{
|
||||
return op1 + op2;
|
||||
}
|
||||
|
||||
int SysCreate(char *filename)
|
||||
{
|
||||
// return value
|
||||
// 1: success
|
||||
// 0: failed
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
#endif /* ! __USERPROG_KSYSCALL_H__ */
|
||||
|
||||
@@ -106,6 +106,15 @@ SynchConsoleOutput::PutChar(char ch)
|
||||
lock->Release();
|
||||
}
|
||||
|
||||
void
|
||||
SynchConsoleOutput::PutInt(int value)
|
||||
{
|
||||
lock->Acquire();
|
||||
consoleOutput->PutInt(value);
|
||||
waitFor->P();
|
||||
lock->Release();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SynchConsoleOutput::CallBack
|
||||
// Interrupt handler called when it's safe to send the next
|
||||
|
||||
@@ -41,6 +41,7 @@ class SynchConsoleOutput : public CallBackObj {
|
||||
~SynchConsoleOutput();
|
||||
|
||||
void PutChar(char ch); // Write a character, waiting if necessary
|
||||
void PutInt(int value);
|
||||
|
||||
private:
|
||||
ConsoleOutput *consoleOutput;// the hardware display
|
||||
|
||||
@@ -23,19 +23,22 @@
|
||||
#define SC_Exec 2
|
||||
#define SC_Join 3
|
||||
#define SC_Create 4
|
||||
#define SC_Remove 5
|
||||
#define SC_Remove 5
|
||||
#define SC_Open 6
|
||||
#define SC_Read 7
|
||||
#define SC_Write 8
|
||||
#define SC_Seek 9
|
||||
#define SC_Close 10
|
||||
#define SC_ThreadFork 11
|
||||
#define SC_Seek 9
|
||||
#define SC_Close 10
|
||||
#define SC_ThreadFork 11
|
||||
#define SC_ThreadYield 12
|
||||
#define SC_ExecV 13
|
||||
#define SC_ExecV 13
|
||||
#define SC_ThreadExit 14
|
||||
#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
|
||||
|
||||
@@ -109,7 +112,7 @@ typedef int OpenFileId;
|
||||
*/
|
||||
|
||||
#define SysConsoleInput 0
|
||||
#define SysConsoleOutput 1
|
||||
#define SysConsoleOutput 1
|
||||
|
||||
/* Create a Nachos file, with name "name" */
|
||||
/* Note: Create does not open the file. */
|
||||
@@ -175,7 +178,9 @@ int ThreadJoin(ThreadId id);
|
||||
/*
|
||||
* Deletes current thread and returns ExitCode to every waiting lokal thread.
|
||||
*/
|
||||
void ThreadExit(int ExitCode);
|
||||
void ThreadExit(int ExitCode);
|
||||
|
||||
void PrintInt(int number);
|
||||
|
||||
#endif /* IN_ASM */
|
||||
|
||||
|
||||
7
docker-compose.yaml
Normal file
7
docker-compose.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
services:
|
||||
test:
|
||||
build: .
|
||||
user: '60139:60139'
|
||||
volumes:
|
||||
- './:/work'
|
||||
Reference in New Issue
Block a user