hw4 test
This commit is contained in:
@@ -200,18 +200,18 @@ DEFINES = -DFILESYS_STUB -DRDATA -DSIM_FIX
|
|||||||
# break the thread system. You might want to use -fno-inline if
|
# break the thread system. You might want to use -fno-inline if
|
||||||
# you need to call some inline functions from the debugger.
|
# you need to call some inline functions from the debugger.
|
||||||
|
|
||||||
CFLAGS = -g -Wall -Wextra $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32 # -fsanitize=address,undefined
|
CFLAGS = -g -Wall $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32 -w
|
||||||
LDFLAGS = -m32 # -fsanitize=address,undefined
|
LDFLAGS = -m32
|
||||||
CPP_AS_FLAGS= -m32
|
CPP_AS_FLAGS= -m32
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
CPP=/lib/cpp
|
CPP=/lib/cpp
|
||||||
CC = g++ -m32 -Wno-deprecated
|
CC = g++ -m32
|
||||||
LD = g++ -m32 -Wno-deprecated
|
LD = g++ -m32
|
||||||
AS = as --32
|
AS = as --32
|
||||||
RM = /bin/rm
|
RM = /bin/rm
|
||||||
|
|
||||||
INCPATH = -I../network -I../filesys -I../userprog -I../threads -I../machine -I../lib -I-
|
INCPATH = -iquote../network -iquote../filesys -iquote../userprog -iquote../threads -iquote../machine -iquote../lib
|
||||||
|
|
||||||
PROGRAM = nachos
|
PROGRAM = nachos
|
||||||
|
|
||||||
@@ -332,7 +332,6 @@ S_OFILES = switch.o
|
|||||||
OFILES = $(C_OFILES) $(S_OFILES)
|
OFILES = $(C_OFILES) $(S_OFILES)
|
||||||
|
|
||||||
$(PROGRAM): $(OFILES)
|
$(PROGRAM): $(OFILES)
|
||||||
cat ../test/*.sh ../test/Makefile ../test/*.c
|
|
||||||
$(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM)
|
$(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM)
|
||||||
|
|
||||||
$(C_OFILES): %.o:
|
$(C_OFILES): %.o:
|
||||||
|
|||||||
@@ -40,56 +40,108 @@
|
|||||||
#ifdef FILESYS_STUB // Temporarily implement file system calls as
|
#ifdef FILESYS_STUB // Temporarily implement file system calls as
|
||||||
// calls to UNIX, until the real file system
|
// calls to UNIX, until the real file system
|
||||||
// implementation is available
|
// implementation is available
|
||||||
|
|
||||||
|
typedef int OpenFileId;
|
||||||
|
|
||||||
class FileSystem {
|
class FileSystem {
|
||||||
public:
|
public:
|
||||||
FileSystem() { for (int i = 0; i < 20; i++) fileDescriptorTable[i] = NULL; }
|
FileSystem() { for (int i = 0; i < 20; i++) fileDescriptorTable[i] = NULL; }
|
||||||
|
|
||||||
bool Create(char *name) {
|
bool Create(char* name) {
|
||||||
int fileDescriptor = OpenForWrite(name);
|
int fileDescriptor = OpenForWrite(name);
|
||||||
|
if (fileDescriptor == -1) return FALSE;
|
||||||
|
Close(fileDescriptor);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
if (fileDescriptor == -1) return FALSE;
|
OpenFile* Open(char* name) {
|
||||||
Close(fileDescriptor);
|
int fileDescriptor = OpenForReadWrite(name, FALSE);
|
||||||
return TRUE;
|
if (fileDescriptor == -1) return NULL;
|
||||||
}
|
return new OpenFile(fileDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
OpenFile* Open(char *name) {
|
OpenFileId OpenFiles(char* name) {
|
||||||
int fileDescriptor = OpenForReadWrite(name, FALSE);
|
OpenFile* file = Open(name);
|
||||||
|
if (!file) return -1;
|
||||||
|
int freeIndex = -1;
|
||||||
|
|
||||||
if (fileDescriptor == -1) return NULL;
|
for (int i = 0; i < 20; i++)
|
||||||
return new OpenFile(fileDescriptor);
|
if (!fileDescriptorTable[i])
|
||||||
}
|
freeIndex = i;
|
||||||
|
|
||||||
bool Remove(char *name) { return Unlink(name) == 0; }
|
if (freeIndex == -1)
|
||||||
|
return -1;
|
||||||
|
OpenFileId fileDescriptor = file->GetFileDescriptor();
|
||||||
|
fileDescriptorTable[freeIndex] = file;
|
||||||
|
return fileDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WriteFile(char* buffer, int size, OpenFileId fd) {
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
if (!fileDescriptorTable[i])
|
||||||
|
continue;
|
||||||
|
if (fileDescriptorTable[i]->GetFileDescriptor() == fd) {
|
||||||
|
return fileDescriptorTable[i]->Write(buffer, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ReadFile(char* buffer, int size, OpenFileId fd) {
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
if (!fileDescriptorTable[i])
|
||||||
|
continue;
|
||||||
|
if (fileDescriptorTable[i]->GetFileDescriptor() == fd)
|
||||||
|
return fileDescriptorTable[i]->Read(buffer, size);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CloseFile(OpenFileId fd) {
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
if (!fileDescriptorTable[i])
|
||||||
|
continue;
|
||||||
|
if (fileDescriptorTable[i]->GetFileDescriptor() == fd) {
|
||||||
|
delete fileDescriptorTable[i];
|
||||||
|
fileDescriptorTable[i] = NULL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Remove(char* name) { return Unlink(name) == 0; }
|
||||||
|
|
||||||
|
OpenFile* fileDescriptorTable[20];
|
||||||
|
|
||||||
OpenFile *fileDescriptorTable[20];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#else // FILESYS
|
#else // FILESYS
|
||||||
class FileSystem {
|
class FileSystem {
|
||||||
public:
|
public:
|
||||||
FileSystem(bool format); // Initialize the file system.
|
FileSystem(bool format); // Initialize the file system.
|
||||||
// Must be called *after* "synchDisk"
|
// Must be called *after* "synchDisk"
|
||||||
// has been initialized.
|
// has been initialized.
|
||||||
// If "format", there is nothing on
|
// If "format", there is nothing on
|
||||||
// the disk, so initialize the directory
|
// the disk, so initialize the directory
|
||||||
// and the bitmap of free blocks.
|
// and the bitmap of free blocks.
|
||||||
|
|
||||||
bool Create(char *name, int initialSize);
|
bool Create(char* name, int initialSize);
|
||||||
// Create a file (UNIX creat)
|
// Create a file (UNIX creat)
|
||||||
|
|
||||||
OpenFile* Open(char *name); // Open a file (UNIX open)
|
OpenFile* Open(char* name); // Open a file (UNIX open)
|
||||||
|
|
||||||
bool Remove(char *name); // Delete a file (UNIX unlink)
|
bool Remove(char* name); // Delete a file (UNIX unlink)
|
||||||
|
|
||||||
void List(); // List all the files in the file system
|
void List(); // List all the files in the file system
|
||||||
|
|
||||||
void Print(); // List all the files and their contents
|
void Print(); // List all the files and their contents
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OpenFile* freeMapFile; // Bit map of free disk blocks,
|
OpenFile* freeMapFile; // Bit map of free disk blocks,
|
||||||
// represented as a file
|
// represented as a file
|
||||||
OpenFile* directoryFile; // "Root" directory -- list of
|
OpenFile* directoryFile; // "Root" directory -- list of
|
||||||
// file names, represented as a file
|
// file names, represented as a file
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FILESYS
|
#endif // FILESYS
|
||||||
|
|||||||
@@ -27,32 +27,38 @@
|
|||||||
#ifdef FILESYS_STUB // Temporarily implement calls to
|
#ifdef FILESYS_STUB // Temporarily implement calls to
|
||||||
// Nachos file system as calls to UNIX!
|
// Nachos file system as calls to UNIX!
|
||||||
// See definitions listed under #else
|
// See definitions listed under #else
|
||||||
|
typedef int OpenFileId;
|
||||||
|
|
||||||
class OpenFile {
|
class OpenFile {
|
||||||
public:
|
public:
|
||||||
OpenFile(int f) { file = f; currentOffset = 0; } // open the file
|
OpenFile(int f) { file = f; currentOffset = 0; } // open the file
|
||||||
~OpenFile() { Close(file); } // close the file
|
~OpenFile() { Close(file); } // close the file
|
||||||
|
|
||||||
int ReadAt(char *into, int numBytes, int position) {
|
int ReadAt(char *into, int numBytes, int position) {
|
||||||
Lseek(file, position, 0);
|
Lseek(file, position, 0);
|
||||||
return ReadPartial(file, into, numBytes);
|
return ReadPartial(file, into, numBytes);
|
||||||
}
|
}
|
||||||
int WriteAt(char *from, int numBytes, int position) {
|
int WriteAt(char *from, int numBytes, int position) {
|
||||||
Lseek(file, position, 0);
|
Lseek(file, position, 0);
|
||||||
WriteFile(file, from, numBytes);
|
WriteFile(file, from, numBytes);
|
||||||
return numBytes;
|
return numBytes;
|
||||||
}
|
}
|
||||||
int Read(char *into, int numBytes) {
|
int Read(char *into, int numBytes) {
|
||||||
int numRead = ReadAt(into, numBytes, currentOffset);
|
int numRead = ReadAt(into, numBytes, currentOffset);
|
||||||
currentOffset += numRead;
|
currentOffset += numRead;
|
||||||
return numRead;
|
return numRead;
|
||||||
}
|
}
|
||||||
int Write(char *from, int numBytes) {
|
int Write(char *from, int numBytes) {
|
||||||
int numWritten = WriteAt(from, numBytes, currentOffset);
|
int numWritten = WriteAt(from, numBytes, currentOffset);
|
||||||
currentOffset += numWritten;
|
currentOffset += numWritten;
|
||||||
return numWritten;
|
return numWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Length() { Lseek(file, 0, 2); return Tell(file); }
|
int Length() { Lseek(file, 0, 2); return Tell(file); }
|
||||||
|
|
||||||
|
OpenFileId GetFileDescriptor() {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int file;
|
int file;
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ const char dbgFile = 'f'; // file system
|
|||||||
const char dbgAddr = 'a'; // address spaces
|
const char dbgAddr = 'a'; // address spaces
|
||||||
const char dbgNet = 'n'; // network emulation
|
const char dbgNet = 'n'; // network emulation
|
||||||
const char dbgSys = 'u'; // systemcall
|
const char dbgSys = 'u'; // systemcall
|
||||||
|
const char dbgSche = 'z';
|
||||||
|
|
||||||
class Debug {
|
class Debug {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -308,7 +308,6 @@ int
|
|||||||
OpenForWrite(char *name)
|
OpenForWrite(char *name)
|
||||||
{
|
{
|
||||||
int fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0666);
|
int fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0666);
|
||||||
// cerr << "OpenForWrite name, fd: " << (int)name << ", " << fd << endl;
|
|
||||||
|
|
||||||
ASSERT(fd >= 0);
|
ASSERT(fd >= 0);
|
||||||
return fd;
|
return fd;
|
||||||
@@ -326,7 +325,6 @@ int
|
|||||||
OpenForReadWrite(char *name, bool crashOnError)
|
OpenForReadWrite(char *name, bool crashOnError)
|
||||||
{
|
{
|
||||||
int fd = open(name, O_RDWR, 0);
|
int fd = open(name, O_RDWR, 0);
|
||||||
// cerr << "OpenForReadWrite name, fd: " << (int)name << ", " << fd << endl;
|
|
||||||
|
|
||||||
ASSERT(!crashOnError || fd >= 0);
|
ASSERT(!crashOnError || fd >= 0);
|
||||||
return fd;
|
return fd;
|
||||||
|
|||||||
@@ -172,13 +172,19 @@ ConsoleOutput::PutChar(char ch)
|
|||||||
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt);
|
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// ConsoleOutput::PutInt()
|
||||||
|
// Write a int to the simulated display, schedule an interrupt
|
||||||
|
// to occur in the future, and return.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void
|
||||||
ConsoleOutput::PutInt(int value)
|
ConsoleOutput::PutInt(int value)
|
||||||
{
|
{
|
||||||
ASSERT(putBusy == FALSE);
|
ASSERT(putBusy == FALSE);
|
||||||
char *printStr = (char*)malloc(sizeof(char)*15);
|
char * printStr = (char*)malloc(sizeof(char) * 15);
|
||||||
sprintf(printStr, "%d\n", value);
|
sprintf(printStr, "%d\n", value);
|
||||||
WriteFile(writeFileNo, printStr, strlen(printStr)*sizeof(char));
|
WriteFile(writeFileNo, printStr, strlen(printStr) * sizeof(char));
|
||||||
putBusy = TRUE;
|
putBusy = TRUE;
|
||||||
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt);
|
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,9 @@ class ConsoleOutput : public CallBackObj {
|
|||||||
void PutChar(char ch); // Write "ch" to the console display,
|
void PutChar(char ch); // Write "ch" to the console display,
|
||||||
// and return immediately. "callWhenDone"
|
// and return immediately. "callWhenDone"
|
||||||
// will called when the I/O completes.
|
// will called when the I/O completes.
|
||||||
void PutInt(int n);
|
|
||||||
|
void PutInt(int value);
|
||||||
|
|
||||||
void CallBack(); // Invoked when next character can be put
|
void CallBack(); // Invoked when next character can be put
|
||||||
// out to the display.
|
// out to the display.
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,8 @@
|
|||||||
|
|
||||||
#include "copyright.h"
|
#include "copyright.h"
|
||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
#include "main.h"
|
|
||||||
#include "synchconsole.h"
|
#include "synchconsole.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
// String definitions for debugging messages
|
// String definitions for debugging messages
|
||||||
|
|
||||||
@@ -341,7 +341,7 @@ static void
|
|||||||
PrintPending (PendingInterrupt *pending)
|
PrintPending (PendingInterrupt *pending)
|
||||||
{
|
{
|
||||||
cout << "Interrupt handler "<< intTypeNames[pending->type];
|
cout << "Interrupt handler "<< intTypeNames[pending->type];
|
||||||
cout << ", scheduled at " << pending->when << endl;
|
cout << ", scheduled at " << pending->when;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -360,8 +360,31 @@ Interrupt::DumpState()
|
|||||||
cout << "\nEnd of pending interrupts\n";
|
cout << "\nEnd of pending interrupts\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void Interrupt::PrintInt(int value)
|
||||||
Interrupt::PrintInt(int value)
|
|
||||||
{
|
{
|
||||||
kernel->synchConsoleOut->PutInt(value);
|
kernel->synchConsoleOut->PutInt(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenFileId
|
||||||
|
Interrupt::OpenFile(char *filename)
|
||||||
|
{
|
||||||
|
return kernel->fileSystem->OpenFiles(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Interrupt::WriteFile(char *buffer, int size, OpenFileId fd)
|
||||||
|
{
|
||||||
|
return kernel->fileSystem->WriteFile(buffer, size, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Interrupt::CloseFile(OpenFileId fd)
|
||||||
|
{
|
||||||
|
return kernel->fileSystem->CloseFile(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Interrupt::ReadFile(char *buffer, int size, OpenFileId fd)
|
||||||
|
{
|
||||||
|
return kernel->fileSystem->ReadFile(buffer, size, fd);
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,35 +37,41 @@
|
|||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "callback.h"
|
#include "callback.h"
|
||||||
|
|
||||||
|
#include "filesys.h"
|
||||||
|
|
||||||
|
typedef int OpenFileId;
|
||||||
|
|
||||||
// Interrupts can be disabled (IntOff) or enabled (IntOn)
|
// Interrupts can be disabled (IntOff) or enabled (IntOn)
|
||||||
enum IntStatus { IntOff, IntOn };
|
enum IntStatus { IntOff, IntOn };
|
||||||
|
|
||||||
// Nachos can be running kernel code (SystemMode), user code (UserMode),
|
// Nachos can be running kernel code (SystemMode), user code (UserMode),
|
||||||
// or there can be no runnable thread, because the ready list
|
// or there can be no runnable thread, because the ready list
|
||||||
// is empty (IdleMode).
|
// is empty (IdleMode).
|
||||||
enum MachineStatus {IdleMode, SystemMode, UserMode};
|
enum MachineStatus { IdleMode, SystemMode, UserMode };
|
||||||
|
|
||||||
// IntType records which hardware device generated an interrupt.
|
// IntType records which hardware device generated an interrupt.
|
||||||
// In Nachos, we support a hardware timer device, a disk, a console
|
// In Nachos, we support a hardware timer device, a disk, a console
|
||||||
// display and keyboard, and a network.
|
// display and keyboard, and a network.
|
||||||
enum IntType { TimerInt, DiskInt, ConsoleWriteInt, ConsoleReadInt,
|
enum IntType {
|
||||||
NetworkSendInt, NetworkRecvInt};
|
TimerInt, DiskInt, ConsoleWriteInt, ConsoleReadInt,
|
||||||
|
NetworkSendInt, NetworkRecvInt
|
||||||
|
};
|
||||||
|
|
||||||
// The following class defines an interrupt that is scheduled
|
// The following class defines an interrupt that is scheduled
|
||||||
// to occur in the future. The internal data structures are
|
// to occur in the future. The internal data structures are
|
||||||
// left public to make it simpler to manipulate.
|
// left public to make it simpler to manipulate.
|
||||||
|
|
||||||
class PendingInterrupt {
|
class PendingInterrupt {
|
||||||
public:
|
public:
|
||||||
PendingInterrupt(CallBackObj *callOnInt, int time, IntType kind);
|
PendingInterrupt(CallBackObj* callOnInt, int time, IntType kind);
|
||||||
// initialize an interrupt that will
|
// initialize an interrupt that will
|
||||||
// occur in the future
|
// occur in the future
|
||||||
|
|
||||||
CallBackObj *callOnInterrupt;// The object (in the hardware device
|
CallBackObj* callOnInterrupt;// The object (in the hardware device
|
||||||
// emulator) to call when the interrupt occurs
|
// emulator) to call when the interrupt occurs
|
||||||
|
|
||||||
int when; // When the interrupt is supposed to fire
|
int when; // When the interrupt is supposed to fire
|
||||||
IntType type; // for debugging
|
IntType type; // for debugging
|
||||||
};
|
};
|
||||||
|
|
||||||
// The following class defines the data structures for the simulation
|
// The following class defines the data structures for the simulation
|
||||||
@@ -74,72 +80,76 @@ class PendingInterrupt {
|
|||||||
// in the future.
|
// in the future.
|
||||||
|
|
||||||
class Interrupt {
|
class Interrupt {
|
||||||
public:
|
public:
|
||||||
Interrupt(); // initialize the interrupt simulation
|
Interrupt(); // initialize the interrupt simulation
|
||||||
~Interrupt(); // de-allocate data structures
|
~Interrupt(); // de-allocate data structures
|
||||||
|
|
||||||
IntStatus SetLevel(IntStatus level);
|
|
||||||
// Disable or enable interrupts
|
|
||||||
// and return previous setting.
|
|
||||||
|
|
||||||
void Enable() { (void) SetLevel(IntOn); }
|
IntStatus SetLevel(IntStatus level);
|
||||||
// Enable interrupts.
|
// Disable or enable interrupts
|
||||||
IntStatus getLevel() {return level;}
|
// and return previous setting.
|
||||||
// Return whether interrupts
|
|
||||||
// are enabled or disabled
|
|
||||||
|
|
||||||
void Idle(); // The ready queue is empty, roll
|
|
||||||
// simulated time forward until the
|
|
||||||
// next interrupt
|
|
||||||
|
|
||||||
void Halt(); // quit and print out stats
|
void Enable() { (void)SetLevel(IntOn); }
|
||||||
|
// Enable interrupts.
|
||||||
|
IntStatus getLevel() { return level; }
|
||||||
|
// Return whether interrupts
|
||||||
|
// are enabled or disabled
|
||||||
|
|
||||||
void PrintInt(int number);
|
void Idle(); // The ready queue is empty, roll
|
||||||
int CreateFile(char *filename);
|
// simulated time forward until the
|
||||||
|
// next interrupt
|
||||||
void YieldOnReturn(); // cause a context switch on return
|
|
||||||
// from an interrupt handler
|
|
||||||
|
|
||||||
MachineStatus getStatus() { return status; }
|
void Halt(); // quit and print out stats
|
||||||
void setStatus(MachineStatus st) { status = st; }
|
|
||||||
// idle, kernel, user
|
|
||||||
|
|
||||||
void DumpState(); // Print interrupt state
|
void PrintInt(int number);
|
||||||
|
int CreateFile(char* filename);
|
||||||
|
OpenFileId OpenFile(char* filename);
|
||||||
|
int WriteFile(char* buffer, int size, OpenFileId fd);
|
||||||
|
int CloseFile(OpenFileId fd);
|
||||||
|
int ReadFile(char* buffer, int size, OpenFileId fd);
|
||||||
|
|
||||||
// NOTE: the following are internal to the hardware simulation code.
|
void YieldOnReturn(); // cause a context switch on return
|
||||||
// DO NOT call these directly. I should make them "private",
|
// from an interrupt handler
|
||||||
// but they need to be public since they are called by the
|
|
||||||
// hardware device simulators.
|
|
||||||
|
|
||||||
void Schedule(CallBackObj *callTo, int when, IntType type);
|
MachineStatus getStatus() { return status; }
|
||||||
// Schedule an interrupt to occur
|
void setStatus(MachineStatus st) { status = st; }
|
||||||
// at time "when". This is called
|
// idle, kernel, user
|
||||||
// by the hardware device simulators.
|
|
||||||
|
|
||||||
void OneTick(); // Advance simulated time
|
|
||||||
|
|
||||||
private:
|
void DumpState(); // Print interrupt state
|
||||||
IntStatus level; // are interrupts enabled or disabled?
|
|
||||||
SortedList<PendingInterrupt *> *pending;
|
|
||||||
// the list of interrupts scheduled
|
|
||||||
// to occur in the future
|
|
||||||
//int writeFileNo; //UNIX file emulating the display
|
|
||||||
bool inHandler; // TRUE if we are running an interrupt handler
|
|
||||||
//bool putBusy; // Is a PrintInt operation in progress
|
|
||||||
//If so, you cannoot do another one
|
|
||||||
bool yieldOnReturn; // TRUE if we are to context switch
|
|
||||||
// on return from the interrupt handler
|
|
||||||
MachineStatus status; // idle, kernel mode, user mode
|
|
||||||
|
|
||||||
// these functions are internal to the interrupt simulation code
|
|
||||||
|
|
||||||
bool CheckIfDue(bool advanceClock);
|
// NOTE: the following are internal to the hardware simulation code.
|
||||||
// Check if any interrupts are supposed
|
// DO NOT call these directly. I should make them "private",
|
||||||
// to occur now, and if so, do them
|
// but they need to be public since they are called by the
|
||||||
|
// hardware device simulators.
|
||||||
|
|
||||||
void ChangeLevel(IntStatus old, // SetLevel, without advancing the
|
void Schedule(CallBackObj* callTo, int when, IntType type);
|
||||||
IntStatus now); // simulated time
|
// Schedule an interrupt to occur
|
||||||
|
// at time "when". This is called
|
||||||
|
// by the hardware device simulators.
|
||||||
|
|
||||||
|
void OneTick(); // Advance simulated time
|
||||||
|
|
||||||
|
private:
|
||||||
|
IntStatus level; // are interrupts enabled or disabled?
|
||||||
|
SortedList<PendingInterrupt*>* pending;
|
||||||
|
// the list of interrupts scheduled
|
||||||
|
// to occur in the future
|
||||||
|
//int writeFileNo; //UNIX file emulating the display
|
||||||
|
bool inHandler; // TRUE if we are running an interrupt handler
|
||||||
|
//bool putBusy; // Is a PrintInt operation in progress
|
||||||
|
//If so, you cannoot do another one
|
||||||
|
bool yieldOnReturn; // TRUE if we are to context switch
|
||||||
|
// on return from the interrupt handler
|
||||||
|
MachineStatus status; // idle, kernel mode, user mode
|
||||||
|
|
||||||
|
// these functions are internal to the interrupt simulation code
|
||||||
|
|
||||||
|
bool CheckIfDue(bool advanceClock);
|
||||||
|
// Check if any interrupts are supposed
|
||||||
|
// to occur now, and if so, do them
|
||||||
|
|
||||||
|
void ChangeLevel(IntStatus old, // SetLevel, without advancing the
|
||||||
|
IntStatus now); // simulated time
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INTERRRUPT_H
|
#endif // INTERRRUPT_H
|
||||||
|
|||||||
@@ -13,17 +13,10 @@
|
|||||||
|
|
||||||
// Textual names of the exceptions that can be generated by user program
|
// Textual names of the exceptions that can be generated by user program
|
||||||
// execution, for debugging.
|
// execution, for debugging.
|
||||||
static char* exceptionNames[] = {
|
static char* exceptionNames[] = { "no exception", "syscall",
|
||||||
"no exception",
|
"page fault/no TLB entry", "page read only",
|
||||||
"syscall",
|
"bus error", "address error", "overflow",
|
||||||
"page fault/no TLB entry",
|
"illegal instruction" };
|
||||||
"page read only",
|
|
||||||
"bus error",
|
|
||||||
"address error",
|
|
||||||
"overflow",
|
|
||||||
"illegal instruction",
|
|
||||||
"bad memory allocation"
|
|
||||||
};
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// CheckEndian
|
// CheckEndian
|
||||||
|
|||||||
@@ -28,34 +28,34 @@
|
|||||||
// Definitions related to the size, and format of user memory
|
// Definitions related to the size, and format of user memory
|
||||||
|
|
||||||
const int PageSize = 128; // set the page size equal to
|
const int PageSize = 128; // set the page size equal to
|
||||||
// the disk sector size, for simplicity
|
// the disk sector size, for simplicity
|
||||||
|
|
||||||
//
|
//
|
||||||
// You are allowed to change this value.
|
// You are allowed to change this value.
|
||||||
// Doing so will change the number of pages of physical memory
|
// Doing so will change the number of pages of physical memory
|
||||||
// available on the simulated machine.
|
// available on the simulated machine.
|
||||||
//
|
//
|
||||||
const int NumPhysPages = 128;
|
const int NumPhysPages = 128;
|
||||||
|
|
||||||
const int MemorySize = (NumPhysPages * PageSize);
|
const int MemorySize = (NumPhysPages * PageSize);
|
||||||
const int TLBSize = 4; // if there is a TLB, make it small
|
const int TLBSize = 4; // if there is a TLB, make it small
|
||||||
|
|
||||||
enum ExceptionType {
|
enum ExceptionType { NoException, // Everything ok!
|
||||||
NoException, // Everything ok!
|
SyscallException, // A program executed a system call.
|
||||||
SyscallException, // A program executed a system call.
|
PageFaultException, // No valid translation found
|
||||||
PageFaultException, // No valid translation found
|
ReadOnlyException, // Write attempted to page marked
|
||||||
ReadOnlyException, // Write attempted to page marked
|
// "read-only"
|
||||||
// "read-only"
|
BusErrorException, // Translation resulted in an
|
||||||
BusErrorException, // Translation resulted in an
|
// invalid physical address
|
||||||
// invalid physical address
|
AddressErrorException, // Unaligned reference or one that
|
||||||
AddressErrorException, // Unaligned reference or one that
|
// was beyond the end of the
|
||||||
// was beyond the end of the
|
// address space
|
||||||
// address space
|
OverflowException, // Integer overflow in add or sub.
|
||||||
OverflowException, // Integer overflow in add or sub.
|
IllegalInstrException, // Unimplemented or reserved instr.
|
||||||
IllegalInstrException, // Unimplemented or reserved instr.
|
|
||||||
MemoryLimitException, // Bad allocation
|
MemoryLimitException, // Insufficient memory
|
||||||
|
|
||||||
NumExceptionTypes
|
NumExceptionTypes
|
||||||
};
|
};
|
||||||
|
|
||||||
// User program CPU state. The full set of MIPS registers, plus a few
|
// User program CPU state. The full set of MIPS registers, plus a few
|
||||||
@@ -96,97 +96,97 @@ class Interrupt;
|
|||||||
class Machine {
|
class Machine {
|
||||||
public:
|
public:
|
||||||
Machine(bool debug); // Initialize the simulation of the hardware
|
Machine(bool debug); // Initialize the simulation of the hardware
|
||||||
// for running user programs
|
// for running user programs
|
||||||
~Machine(); // De-allocate the data structures
|
~Machine(); // De-allocate the data structures
|
||||||
|
|
||||||
// Routines callable by the Nachos kernel
|
// Routines callable by the Nachos kernel
|
||||||
void Run(); // Run a user program
|
void Run(); // Run a user program
|
||||||
|
|
||||||
int ReadRegister(int num); // read the contents of a CPU register
|
int ReadRegister(int num); // read the contents of a CPU register
|
||||||
|
|
||||||
void WriteRegister(int num, int value);
|
void WriteRegister(int num, int value);
|
||||||
// store a value into a CPU register
|
// store a value into a CPU register
|
||||||
|
|
||||||
// Data structures accessible to the Nachos kernel -- main memory and the
|
// Data structures accessible to the Nachos kernel -- main memory and the
|
||||||
// page table/TLB.
|
// page table/TLB.
|
||||||
//
|
//
|
||||||
// Note that *all* communication between the user program and the kernel
|
// Note that *all* communication between the user program and the kernel
|
||||||
// are in terms of these data structures (plus the CPU registers).
|
// are in terms of these data structures (plus the CPU registers).
|
||||||
|
|
||||||
char *mainMemory; // physical memory to store user program,
|
char *mainMemory; // physical memory to store user program,
|
||||||
// code and data, while executing
|
// code and data, while executing
|
||||||
|
|
||||||
// NOTE: the hardware translation of virtual addresses in the user program
|
// NOTE: the hardware translation of virtual addresses in the user program
|
||||||
// to physical addresses (relative to the beginning of "mainMemory")
|
// to physical addresses (relative to the beginning of "mainMemory")
|
||||||
// can be controlled by one of:
|
// can be controlled by one of:
|
||||||
// a traditional linear page table
|
// a traditional linear page table
|
||||||
// a software-loaded translation lookaside buffer (tlb) -- a cache of
|
// a software-loaded translation lookaside buffer (tlb) -- a cache of
|
||||||
// mappings of virtual page #'s to physical page #'s
|
// mappings of virtual page #'s to physical page #'s
|
||||||
//
|
//
|
||||||
// If "tlb" is NULL, the linear page table is used
|
// If "tlb" is NULL, the linear page table is used
|
||||||
// If "tlb" is non-NULL, the Nachos kernel is responsible for managing
|
// If "tlb" is non-NULL, the Nachos kernel is responsible for managing
|
||||||
// the contents of the TLB. But the kernel can use any data structure
|
// the contents of the TLB. But the kernel can use any data structure
|
||||||
// it wants (eg, segmented paging) for handling TLB cache misses.
|
// it wants (eg, segmented paging) for handling TLB cache misses.
|
||||||
//
|
//
|
||||||
// For simplicity, both the page table pointer and the TLB pointer are
|
// For simplicity, both the page table pointer and the TLB pointer are
|
||||||
// public. However, while there can be multiple page tables (one per address
|
// public. However, while there can be multiple page tables (one per address
|
||||||
// space, stored in memory), there is only one TLB (implemented in hardware).
|
// space, stored in memory), there is only one TLB (implemented in hardware).
|
||||||
// Thus the TLB pointer should be considered as *read-only*, although
|
// Thus the TLB pointer should be considered as *read-only*, although
|
||||||
// the contents of the TLB are free to be modified by the kernel software.
|
// the contents of the TLB are free to be modified by the kernel software.
|
||||||
|
|
||||||
TranslationEntry *tlb; // this pointer should be considered
|
TranslationEntry *tlb; // this pointer should be considered
|
||||||
// "read-only" to Nachos kernel code
|
// "read-only" to Nachos kernel code
|
||||||
|
|
||||||
TranslationEntry *pageTable;
|
TranslationEntry *pageTable;
|
||||||
unsigned int pageTableSize;
|
unsigned int pageTableSize;
|
||||||
|
|
||||||
bool ReadMem(int addr, int size, int* value);
|
bool ReadMem(int addr, int size, int* value);
|
||||||
bool WriteMem(int addr, int size, int value);
|
bool WriteMem(int addr, int size, int value);
|
||||||
// Read or write 1, 2, or 4 bytes of virtual
|
// Read or write 1, 2, or 4 bytes of virtual
|
||||||
// memory (at addr). Return FALSE if a
|
// memory (at addr). Return FALSE if a
|
||||||
// correct translation couldn't be found.
|
// correct translation couldn't be found.
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Routines internal to the machine simulation -- DO NOT call these directly
|
// Routines internal to the machine simulation -- DO NOT call these directly
|
||||||
void DelayedLoad(int nextReg, int nextVal);
|
void DelayedLoad(int nextReg, int nextVal);
|
||||||
// Do a pending delayed load (modifying a reg)
|
// Do a pending delayed load (modifying a reg)
|
||||||
|
|
||||||
void OneInstruction(Instruction *instr);
|
void OneInstruction(Instruction *instr);
|
||||||
// Run one instruction of a user program.
|
// Run one instruction of a user program.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ExceptionType Translate(int virtAddr, int* physAddr, int size,bool writing);
|
ExceptionType Translate(int virtAddr, int* physAddr, int size,bool writing);
|
||||||
// Translate an address, and check for
|
// Translate an address, and check for
|
||||||
// alignment. Set the use and dirty bits in
|
// alignment. Set the use and dirty bits in
|
||||||
// the translation entry appropriately,
|
// the translation entry appropriately,
|
||||||
// and return an exception code if the
|
// and return an exception code if the
|
||||||
// translation couldn't be completed.
|
// translation couldn't be completed.
|
||||||
|
|
||||||
void RaiseException(ExceptionType which, int badVAddr);
|
void RaiseException(ExceptionType which, int badVAddr);
|
||||||
// Trap to the Nachos kernel, because of a
|
// Trap to the Nachos kernel, because of a
|
||||||
// system call or other exception.
|
// system call or other exception.
|
||||||
|
|
||||||
void Debugger(); // invoke the user program debugger
|
void Debugger(); // invoke the user program debugger
|
||||||
void DumpState(); // print the user CPU and memory state
|
void DumpState(); // print the user CPU and memory state
|
||||||
|
|
||||||
|
|
||||||
// Internal data structures
|
// Internal data structures
|
||||||
|
|
||||||
int registers[NumTotalRegs]; // CPU registers, for executing user programs
|
int registers[NumTotalRegs]; // CPU registers, for executing user programs
|
||||||
|
|
||||||
bool singleStep; // drop back into the debugger after each
|
bool singleStep; // drop back into the debugger after each
|
||||||
// simulated instruction
|
// simulated instruction
|
||||||
int runUntilTime; // drop back into the debugger when simulated
|
int runUntilTime; // drop back into the debugger when simulated
|
||||||
// time reaches this value
|
// time reaches this value
|
||||||
|
|
||||||
friend class Interrupt; // calls DelayedLoad()
|
friend class Interrupt; // calls DelayedLoad()
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void ExceptionHandler(ExceptionType which);
|
extern void ExceptionHandler(ExceptionType which);
|
||||||
// Entry point into Nachos for handling
|
// Entry point into Nachos for handling
|
||||||
// user system calls and exceptions
|
// user system calls and exceptions
|
||||||
// Defined in exception.cc
|
// Defined in exception.cc
|
||||||
|
|
||||||
|
|
||||||
// Routines for converting Words and Short Words to and from the
|
// Routines for converting Words and Short Words to and from the
|
||||||
|
|||||||
@@ -20,25 +20,25 @@
|
|||||||
// The fields in this class are public to make it easier to update.
|
// The fields in this class are public to make it easier to update.
|
||||||
|
|
||||||
class Statistics {
|
class Statistics {
|
||||||
public:
|
public:
|
||||||
int totalTicks; // Total time running Nachos
|
int totalTicks; // Total time running Nachos
|
||||||
int idleTicks; // Time spent idle (no threads to run)
|
int idleTicks; // Time spent idle (no threads to run)
|
||||||
int systemTicks; // Time spent executing system code
|
int systemTicks; // Time spent executing system code
|
||||||
int userTicks; // Time spent executing user code
|
int userTicks; // Time spent executing user code
|
||||||
// (this is also equal to # of
|
// (this is also equal to # of
|
||||||
// user instructions executed)
|
// user instructions executed)
|
||||||
|
|
||||||
int numDiskReads; // number of disk read requests
|
int numDiskReads; // number of disk read requests
|
||||||
int numDiskWrites; // number of disk write requests
|
int numDiskWrites; // number of disk write requests
|
||||||
int numConsoleCharsRead; // number of characters read from the keyboard
|
int numConsoleCharsRead; // number of characters read from the keyboard
|
||||||
int numConsoleCharsWritten; // number of characters written to the display
|
int numConsoleCharsWritten; // number of characters written to the display
|
||||||
int numPageFaults; // number of virtual memory page faults
|
int numPageFaults; // number of virtual memory page faults
|
||||||
int numPacketsSent; // number of packets sent over the network
|
int numPacketsSent; // number of packets sent over the network
|
||||||
int numPacketsRecvd; // number of packets received over the network
|
int numPacketsRecvd; // number of packets received over the network
|
||||||
|
|
||||||
Statistics(); // initialize everything to zero
|
Statistics(); // initialize everything to zero
|
||||||
|
|
||||||
void Print(); // print collected statistics
|
void Print(); // print collected statistics
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constants used to reflect the relative time an operation would
|
// Constants used to reflect the relative time an operation would
|
||||||
@@ -49,12 +49,15 @@ class Statistics {
|
|||||||
// in the kernel measured by the number of calls to enable interrupts,
|
// in the kernel measured by the number of calls to enable interrupts,
|
||||||
// these time constants are none too exact.
|
// these time constants are none too exact.
|
||||||
|
|
||||||
const int UserTick = 1; // advance for each user-level instruction
|
const int UserTick = 1; // advance for each user-level instruction
|
||||||
const int SystemTick = 10; // advance each time interrupts are enabled
|
const int SystemTick = 10; // advance each time interrupts are enabled
|
||||||
const int RotationTime = 500; // time disk takes to rotate one sector
|
const int RotationTime = 500; // time disk takes to rotate one sector
|
||||||
const int SeekTime = 500; // time disk takes to seek past one track
|
const int SeekTime = 500; // time disk takes to seek past one track
|
||||||
const int ConsoleTime = 100; // time to read or write one character
|
|
||||||
const int NetworkTime = 100; // time to send or receive one packet
|
// MP4 MODIFIED
|
||||||
const int TimerTicks = 100; // (average) time between timer interrupts
|
const int ConsoleTime = 1; // time to read or write one character
|
||||||
|
|
||||||
|
const int NetworkTime = 100; // time to send or receive one packet
|
||||||
|
const int TimerTicks = 100; // (average) time between timer interrupts
|
||||||
|
|
||||||
#endif // STATS_H
|
#endif // STATS_H
|
||||||
|
|||||||
@@ -85,38 +85,38 @@ ShortToMachine(unsigned short shortword) { return ShortToHost(shortword); }
|
|||||||
bool
|
bool
|
||||||
Machine::ReadMem(int addr, int size, int *value)
|
Machine::ReadMem(int addr, int size, int *value)
|
||||||
{
|
{
|
||||||
int data;
|
int data;
|
||||||
ExceptionType exception;
|
ExceptionType exception;
|
||||||
int physicalAddress;
|
int physicalAddress;
|
||||||
|
|
||||||
|
DEBUG(dbgAddr, "Reading VA " << addr << ", size " << size);
|
||||||
|
|
||||||
|
exception = Translate(addr, &physicalAddress, size, FALSE);
|
||||||
|
if (exception != NoException) {
|
||||||
|
RaiseException(exception, addr);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
switch (size) {
|
||||||
|
case 1:
|
||||||
|
data = mainMemory[physicalAddress];
|
||||||
|
*value = data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
data = *(unsigned short *) &mainMemory[physicalAddress];
|
||||||
|
*value = ShortToHost(data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
data = *(unsigned int *) &mainMemory[physicalAddress];
|
||||||
|
*value = WordToHost(data);
|
||||||
|
break;
|
||||||
|
|
||||||
DEBUG(dbgAddr, "Reading VA " << addr << ", size " << size);
|
default: ASSERT(FALSE);
|
||||||
|
}
|
||||||
exception = Translate(addr, &physicalAddress, size, FALSE);
|
|
||||||
if (exception != NoException) {
|
DEBUG(dbgAddr, "\tvalue read = " << *value);
|
||||||
RaiseException(exception, addr);
|
return (TRUE);
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
switch (size) {
|
|
||||||
case 1:
|
|
||||||
data = mainMemory[physicalAddress];
|
|
||||||
*value = data;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
data = *(unsigned short *) &mainMemory[physicalAddress];
|
|
||||||
*value = ShortToHost(data);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4:
|
|
||||||
data = *(unsigned int *) &mainMemory[physicalAddress];
|
|
||||||
*value = WordToHost(data);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: ASSERT(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(dbgAddr, "\tvalue read = " << *value);
|
|
||||||
return (TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -135,35 +135,35 @@ Machine::ReadMem(int addr, int size, int *value)
|
|||||||
bool
|
bool
|
||||||
Machine::WriteMem(int addr, int size, int value)
|
Machine::WriteMem(int addr, int size, int value)
|
||||||
{
|
{
|
||||||
ExceptionType exception;
|
ExceptionType exception;
|
||||||
int physicalAddress;
|
int physicalAddress;
|
||||||
|
|
||||||
|
DEBUG(dbgAddr, "Writing VA " << addr << ", size " << size << ", value " << value);
|
||||||
|
|
||||||
DEBUG(dbgAddr, "Writing VA " << addr << ", size " << size << ", value " << value);
|
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;
|
||||||
|
|
||||||
exception = Translate(addr, &physicalAddress, size, TRUE);
|
case 2:
|
||||||
if (exception != NoException) {
|
*(unsigned short *) &mainMemory[physicalAddress]
|
||||||
RaiseException(exception, addr);
|
= ShortToMachine((unsigned short) (value & 0xffff));
|
||||||
return FALSE;
|
break;
|
||||||
}
|
|
||||||
switch (size) {
|
case 4:
|
||||||
case 1:
|
*(unsigned int *) &mainMemory[physicalAddress]
|
||||||
mainMemory[physicalAddress] = (unsigned char) (value & 0xff);
|
= WordToMachine((unsigned int) value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
default: ASSERT(FALSE);
|
||||||
*(unsigned short *) &mainMemory[physicalAddress]
|
}
|
||||||
= ShortToMachine((unsigned short) (value & 0xffff));
|
|
||||||
break;
|
return TRUE;
|
||||||
|
|
||||||
case 4:
|
|
||||||
*(unsigned int *) &mainMemory[physicalAddress]
|
|
||||||
= WordToMachine((unsigned int) value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: ASSERT(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -184,75 +184,67 @@ Machine::WriteMem(int addr, int size, int value)
|
|||||||
ExceptionType
|
ExceptionType
|
||||||
Machine::Translate(int virtAddr, int* physAddr, int size, bool writing)
|
Machine::Translate(int virtAddr, int* physAddr, int size, bool writing)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned int vpn, offset;
|
unsigned int vpn, offset;
|
||||||
TranslationEntry *entry;
|
TranslationEntry *entry;
|
||||||
unsigned int pageFrame;
|
unsigned int pageFrame;
|
||||||
|
|
||||||
DEBUG(dbgAddr, "\tTranslate " << virtAddr << (writing ? " , write" : " , read"));
|
DEBUG(dbgAddr, "\tTranslate " << virtAddr << (writing ? " , write" : " , read"));
|
||||||
|
|
||||||
// check for alignment errors
|
// check for alignment errors
|
||||||
if (((size == 4) && (virtAddr & 0x3)) || ((size == 2) && (virtAddr & 0x1))){
|
if (((size == 4) && (virtAddr & 0x3)) || ((size == 2) && (virtAddr & 0x1))){
|
||||||
DEBUG(dbgAddr, "Alignment problem at " << virtAddr << ", size " << size);
|
DEBUG(dbgAddr, "Alignment problem at " << virtAddr << ", size " << size);
|
||||||
return AddressErrorException;
|
return AddressErrorException;
|
||||||
}
|
|
||||||
// we must have either a TLB or a page table, but not both!
|
|
||||||
ASSERT(tlb == NULL || pageTable == NULL);
|
|
||||||
ASSERT(tlb != NULL || pageTable != NULL);
|
|
||||||
|
|
||||||
// calculate the virtual page number, and offset within the page,
|
|
||||||
// from the virtual address
|
|
||||||
vpn = (unsigned) virtAddr / PageSize;
|
|
||||||
offset = (unsigned) virtAddr % PageSize;
|
|
||||||
|
|
||||||
if (tlb == NULL) { // => page table => vpn is index into table
|
|
||||||
if (vpn >= pageTableSize) {
|
|
||||||
DEBUG(dbgAddr, "Illegal virtual page # " << virtAddr);
|
|
||||||
DEBUG(dbgAddr, "vpn, pageTableSize, NumPhysPages: " << vpn << ' ' << pageTableSize << ' ' << NumPhysPages);
|
|
||||||
return AddressErrorException;
|
|
||||||
} else if (!pageTable[vpn].valid) {
|
|
||||||
DEBUG(dbgAddr, "Invalid virtual page # " << virtAddr);
|
|
||||||
return PageFaultException;
|
|
||||||
}
|
}
|
||||||
entry = &pageTable[vpn];
|
// we must have either a TLB or a page table, but not both!
|
||||||
} else {
|
ASSERT(tlb == NULL || pageTable == NULL);
|
||||||
for (entry = NULL, i = 0; i < TLBSize; i++)
|
ASSERT(tlb != NULL || pageTable != NULL);
|
||||||
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
|
// calculate the virtual page number, and offset within the page,
|
||||||
DEBUG(dbgAddr, "Write to read-only page at " << virtAddr);
|
// from the virtual address
|
||||||
return ReadOnlyException;
|
vpn = (unsigned) virtAddr / PageSize;
|
||||||
}
|
offset = (unsigned) virtAddr % PageSize;
|
||||||
pageFrame = entry->physicalPage;
|
|
||||||
if (pageFrame == -1) {
|
if (tlb == NULL) { // => page table => vpn is index into table
|
||||||
pageFrame = entry->physicalPage = kernel->frameTable->Allocate();
|
if (vpn >= pageTableSize) {
|
||||||
if (pageFrame == -1) {
|
DEBUG(dbgAddr, "Illegal virtual page # " << virtAddr);
|
||||||
DEBUG(dbgAddr, "Memory Limit exceeded");
|
return AddressErrorException;
|
||||||
return MemoryLimitException;
|
} else if (!pageTable[vpn].valid) {
|
||||||
|
DEBUG(dbgAddr, "Invalid virtual page # " << virtAddr);
|
||||||
|
return PageFaultException;
|
||||||
|
}
|
||||||
|
entry = &pageTable[vpn];
|
||||||
|
} else {
|
||||||
|
for (entry = NULL, i = 0; i < TLBSize; i++)
|
||||||
|
if (tlb[i].valid && (tlb[i].virtualPage == ((int)vpn))) {
|
||||||
|
entry = &tlb[i]; // FOUND!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (entry == NULL) { // not found
|
||||||
|
DEBUG(dbgAddr, "Invalid TLB entry for this virtual page!");
|
||||||
|
return PageFaultException; // really, this is a TLB fault,
|
||||||
|
// the page may be in memory,
|
||||||
|
// but not in the TLB
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// if the pageFrame is too big, there is something really wrong!
|
if (entry->readOnly && writing) { // trying to write to a read-only page
|
||||||
// An invalid translation was loaded into the page table or TLB.
|
DEBUG(dbgAddr, "Write to read-only page at " << virtAddr);
|
||||||
if (pageFrame >= NumPhysPages) {
|
return ReadOnlyException;
|
||||||
DEBUG(dbgAddr, "Illegal pageframe " << pageFrame);
|
}
|
||||||
return BusErrorException;
|
pageFrame = entry->physicalPage;
|
||||||
}
|
|
||||||
entry->use = TRUE; // set the use, dirty bits
|
// if the pageFrame is too big, there is something really wrong!
|
||||||
if (writing)
|
// An invalid translation was loaded into the page table or TLB.
|
||||||
entry->dirty = TRUE;
|
if (pageFrame >= NumPhysPages) {
|
||||||
*physAddr = pageFrame * PageSize + offset;
|
DEBUG(dbgAddr, "Illegal pageframe " << pageFrame);
|
||||||
ASSERT((*physAddr >= 0) && ((*physAddr + size) <= MemorySize));
|
return BusErrorException;
|
||||||
DEBUG(dbgAddr, "phys addr = " << *physAddr);
|
}
|
||||||
return NoException;
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,8 +113,7 @@ ifeq ($(hosttype),unknown)
|
|||||||
PROGRAMS = unknownhost
|
PROGRAMS = unknownhost
|
||||||
else
|
else
|
||||||
# change this if you create a new test program!
|
# change this if you create a new test program!
|
||||||
PROGRAMS = add halt consoleIO_test1 consoleIO_test2 fileIO_test1 fileIO_test2 test
|
PROGRAMS = mp4_consoleIO_1 mp4_consoleIO_2 mp4_consoleIO_3 mp4_consoleIO_4
|
||||||
# PROGRAMS = halt
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: $(PROGRAMS)
|
all: $(PROGRAMS)
|
||||||
@@ -122,78 +121,35 @@ all: $(PROGRAMS)
|
|||||||
start.o: start.S ../userprog/syscall.h
|
start.o: start.S ../userprog/syscall.h
|
||||||
$(CC) $(CFLAGS) $(ASFLAGS) -c start.S
|
$(CC) $(CFLAGS) $(ASFLAGS) -c start.S
|
||||||
|
|
||||||
halt.o: halt.c
|
mp4_consoleIO_1.o: mp4_consoleIO_1.c
|
||||||
$(CC) $(CFLAGS) -c halt.c
|
$(CC) $(CFLAGS) -c mp4_consoleIO_1.c
|
||||||
halt: halt.o start.o
|
|
||||||
$(LD) $(LDFLAGS) start.o halt.o -o halt.coff
|
|
||||||
$(COFF2NOFF) halt.coff halt
|
|
||||||
|
|
||||||
add.o: add.c
|
mp4_consoleIO_1: mp4_consoleIO_1.o start.o
|
||||||
$(CC) $(CFLAGS) -c add.c
|
$(LD) $(LDFLAGS) start.o mp4_consoleIO_1.o -o mp4_consoleIO_1.coff
|
||||||
|
$(COFF2NOFF) mp4_consoleIO_1.coff mp4_consoleIO_1
|
||||||
|
|
||||||
add: add.o start.o
|
|
||||||
$(LD) $(LDFLAGS) start.o add.o -o add.coff
|
|
||||||
$(COFF2NOFF) add.coff add
|
|
||||||
|
|
||||||
shell.o: shell.c
|
mp4_consoleIO_2.o: mp4_consoleIO_2.c
|
||||||
$(CC) $(CFLAGS) -c shell.c
|
$(CC) $(CFLAGS) -c mp4_consoleIO_2.c
|
||||||
shell: shell.o start.o
|
|
||||||
$(LD) $(LDFLAGS) start.o shell.o -o shell.coff
|
|
||||||
$(COFF2NOFF) shell.coff shell
|
|
||||||
|
|
||||||
sort.o: sort.c
|
mp4_consoleIO_2: mp4_consoleIO_2.o start.o
|
||||||
$(CC) $(CFLAGS) -c sort.c
|
$(LD) $(LDFLAGS) start.o mp4_consoleIO_2.o -o mp4_consoleIO_2.coff
|
||||||
sort: sort.o start.o
|
$(COFF2NOFF) mp4_consoleIO_2.coff mp4_consoleIO_2
|
||||||
$(LD) $(LDFLAGS) start.o sort.o -o sort.coff
|
|
||||||
$(COFF2NOFF) sort.coff sort
|
|
||||||
|
|
||||||
segments.o: segments.c
|
mp4_consoleIO_3.o: mp4_consoleIO_3.c
|
||||||
$(CC) $(CFLAGS) -c segments.c
|
$(CC) $(CFLAGS) -c mp4_consoleIO_3.c
|
||||||
segments: segments.o start.o
|
|
||||||
$(LD) $(LDFLAGS) start.o segments.o -o segments.coff
|
|
||||||
$(COFF2NOFF) segments.coff segments
|
|
||||||
|
|
||||||
matmult.o: matmult.c
|
mp4_consoleIO_3: mp4_consoleIO_3.o start.o
|
||||||
$(CC) $(CFLAGS) -c matmult.c
|
$(LD) $(LDFLAGS) start.o mp4_consoleIO_3.o -o mp4_consoleIO_3.coff
|
||||||
matmult: matmult.o start.o
|
$(COFF2NOFF) mp4_consoleIO_3.coff mp4_consoleIO_3
|
||||||
$(LD) $(LDFLAGS) start.o matmult.o -o matmult.coff
|
|
||||||
$(COFF2NOFF) matmult.coff matmult
|
|
||||||
|
|
||||||
consoleIO_test1.o: consoleIO_test1.c
|
mp4_consoleIO_4.o: mp4_consoleIO_4.c
|
||||||
$(CC) $(CFLAGS) -c consoleIO_test1.c
|
$(CC) $(CFLAGS) -c mp4_consoleIO_4.c
|
||||||
consoleIO_test1: consoleIO_test1.o start.o
|
|
||||||
$(LD) $(LDFLAGS) start.o consoleIO_test1.o -o consoleIO_test1.coff
|
|
||||||
$(COFF2NOFF) consoleIO_test1.coff consoleIO_test1
|
|
||||||
|
|
||||||
consoleIO_test2.o: consoleIO_test2.c
|
mp4_consoleIO_4: mp4_consoleIO_4.o start.o
|
||||||
$(CC) $(CFLAGS) -c consoleIO_test2.c
|
$(LD) $(LDFLAGS) start.o mp4_consoleIO_4.o -o mp4_consoleIO_4.coff
|
||||||
consoleIO_test2: consoleIO_test2.o start.o
|
$(COFF2NOFF) mp4_consoleIO_4.coff mp4_consoleIO_4
|
||||||
$(LD) $(LDFLAGS) start.o consoleIO_test2.o -o consoleIO_test2.coff
|
|
||||||
$(COFF2NOFF) consoleIO_test2.coff consoleIO_test2
|
|
||||||
|
|
||||||
fileIO_test1.o: fileIO_test1.c
|
|
||||||
$(CC) $(CFLAGS) -c fileIO_test1.c
|
|
||||||
fileIO_test1: fileIO_test1.o start.o
|
|
||||||
$(LD) $(LDFLAGS) start.o fileIO_test1.o -o fileIO_test1.coff
|
|
||||||
$(COFF2NOFF) fileIO_test1.coff fileIO_test1
|
|
||||||
|
|
||||||
fileIO_test2.o: fileIO_test2.c
|
|
||||||
$(CC) $(CFLAGS) -c fileIO_test2.c
|
|
||||||
fileIO_test2: fileIO_test2.o start.o
|
|
||||||
$(LD) $(LDFLAGS) start.o fileIO_test2.o -o fileIO_test2.coff
|
|
||||||
$(COFF2NOFF) fileIO_test2.coff fileIO_test2
|
|
||||||
|
|
||||||
fileIO_test3.o: fileIO_test3.c
|
|
||||||
$(CC) $(CFLAGS) -c fileIO_test3.c
|
|
||||||
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:
|
clean:
|
||||||
$(RM) -f *.o *.ii
|
$(RM) -f *.o *.ii
|
||||||
@@ -203,12 +159,11 @@ distclean: clean
|
|||||||
$(RM) -f $(PROGRAMS)
|
$(RM) -f $(PROGRAMS)
|
||||||
|
|
||||||
run: $(PROGRAMS)
|
run: $(PROGRAMS)
|
||||||
timeout 1 $(NACHOS) -e consoleIO_test1 -e consoleIO_test2
|
timeout 1 $(NACHOS) -ep mp4_consoleIO_1 70 -ep mp4_consoleIO_3 80 -ep mp4_consoleIO_2 50
|
||||||
echo 'done'
|
echo 'done'
|
||||||
|
|
||||||
debug: $(PROGRAMS)
|
debug: $(PROGRAMS)
|
||||||
timeout 1 $(NACHOS) -e consoleIO_test1 -e consoleIO_test2 -d +
|
timeout 1 $(NACHOS) -d z -ep mp4_consoleIO_1 60 -ep mp4_consoleIO_2 70
|
||||||
|
|
||||||
|
|
||||||
unknownhost:
|
unknownhost:
|
||||||
@echo Host type could not be determined.
|
@echo Host type could not be determined.
|
||||||
|
|||||||
10
code/test/mp4_consoleIO_1.c
Normal file
10
code/test/mp4_consoleIO_1.c
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include "syscall.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
for (n = 0; n < 4; n++) {
|
||||||
|
PrintInt(1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
9
code/test/mp4_consoleIO_2.c
Normal file
9
code/test/mp4_consoleIO_2.c
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include "syscall.h"
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
for (n = 0; n < 5; n++) {
|
||||||
|
PrintInt(2);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
10
code/test/mp4_consoleIO_3.c
Normal file
10
code/test/mp4_consoleIO_3.c
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include "syscall.h"
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
for (n = 0; n < 12; n++) {
|
||||||
|
PrintInt(3);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
9
code/test/mp4_consoleIO_4.c
Normal file
9
code/test/mp4_consoleIO_4.c
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include "syscall.h"
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
for (n = 0; n < 11; n++) {
|
||||||
|
PrintInt(4);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,4 +1,9 @@
|
|||||||
make distclean
|
make distclean
|
||||||
make
|
make
|
||||||
timeout 1 ../build.linux/nachos -e consoleIO_test1 -e consoleIO_test2
|
rm -f *.o *.ii
|
||||||
echo 'done'
|
rm -f *.coff
|
||||||
|
echo "=========================="
|
||||||
|
timeout 1 ../build.linux/nachos -e mp4_consoleIO_1 -e mp4_consoleIO_2
|
||||||
|
echo "=========================="
|
||||||
|
timeout 1 ../build.linux/nachos -e mp4_consoleIO_3 -e mp4_consoleIO_4
|
||||||
|
echo "done"
|
||||||
@@ -58,6 +58,14 @@ MSG:
|
|||||||
j $31
|
j $31
|
||||||
.end MSG
|
.end MSG
|
||||||
|
|
||||||
|
.globl PrintInt
|
||||||
|
.ent PrintInt
|
||||||
|
PrintInt:
|
||||||
|
addiu $2,$0,SC_PrintInt
|
||||||
|
syscall
|
||||||
|
j $31
|
||||||
|
.end PrintInt
|
||||||
|
|
||||||
.globl Add
|
.globl Add
|
||||||
.ent Add
|
.ent Add
|
||||||
Add:
|
Add:
|
||||||
@@ -186,14 +194,6 @@ ThreadJoin:
|
|||||||
j $31
|
j $31
|
||||||
.end ThreadJoin
|
.end ThreadJoin
|
||||||
|
|
||||||
.globl PrintInt
|
|
||||||
.ent PrintInt
|
|
||||||
PrintInt:
|
|
||||||
addiu $2,$0,SC_PrintInt
|
|
||||||
syscall
|
|
||||||
j $31
|
|
||||||
.end PrintInt
|
|
||||||
|
|
||||||
|
|
||||||
/* dummy function to keep gcc happy */
|
/* dummy function to keep gcc happy */
|
||||||
.globl __main
|
.globl __main
|
||||||
|
|||||||
@@ -43,13 +43,15 @@ Alarm::Alarm(bool doRandom)
|
|||||||
// if we're currently running something (in other words, not idle).
|
// if we're currently running something (in other words, not idle).
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void
|
||||||
Alarm::CallBack()
|
Alarm::CallBack()
|
||||||
{
|
{
|
||||||
Interrupt *interrupt = kernel->interrupt;
|
Interrupt* interrupt = kernel->interrupt;
|
||||||
MachineStatus status = interrupt->getStatus();
|
MachineStatus status = interrupt->getStatus();
|
||||||
|
|
||||||
|
// Todo ----
|
||||||
if (status != IdleMode) {
|
if (status != IdleMode) {
|
||||||
interrupt->YieldOnReturn();
|
// interrupt->YieldOnReturn();
|
||||||
}
|
}
|
||||||
|
// ---------
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,9 @@
|
|||||||
// for the initialization (see also comments in main.cc)
|
// for the initialization (see also comments in main.cc)
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
Kernel::Kernel(int argc, char **argv)
|
Kernel::Kernel(int argc, char** argv)
|
||||||
{
|
{
|
||||||
execfileNum = 0;
|
randomSlice = FALSE;
|
||||||
threadNum = 0;
|
|
||||||
randomSlice = FALSE;
|
|
||||||
debugUserProg = FALSE;
|
debugUserProg = FALSE;
|
||||||
consoleIn = NULL; // default is stdin
|
consoleIn = NULL; // default is stdin
|
||||||
consoleOut = NULL; // default is stdout
|
consoleOut = NULL; // default is stdout
|
||||||
@@ -45,32 +43,48 @@ Kernel::Kernel(int argc, char **argv)
|
|||||||
// number generator
|
// number generator
|
||||||
randomSlice = TRUE;
|
randomSlice = TRUE;
|
||||||
i++;
|
i++;
|
||||||
} else if (strcmp(argv[i], "-s") == 0) {
|
}
|
||||||
|
else if (strcmp(argv[i], "-s") == 0) {
|
||||||
debugUserProg = TRUE;
|
debugUserProg = TRUE;
|
||||||
} else if (strcmp(argv[i], "-e") == 0) {
|
}
|
||||||
execfile[++execfileNum]= argv[++i];
|
// Todo ----
|
||||||
|
else if (strcmp(argv[i], "-e") == 0) {
|
||||||
|
execfile[++execfileNum] = argv[++i];
|
||||||
cout << execfile[execfileNum] << "\n";
|
cout << execfile[execfileNum] << "\n";
|
||||||
} else if (strcmp(argv[i], "-ci") == 0) {
|
}
|
||||||
|
else if (strcmp(argv[i], "-ep") == 0) {
|
||||||
|
execfile[++execfileNum] = argv[++i];
|
||||||
|
execPriority[execfileNum] = atoi(argv[++i]);
|
||||||
|
cout << execfile[execfileNum] << " with priority "
|
||||||
|
<< execPriority[execfileNum] << "\n";
|
||||||
|
}
|
||||||
|
// ---------
|
||||||
|
else if (strcmp(argv[i], "-ci") == 0) {
|
||||||
ASSERT(i + 1 < argc);
|
ASSERT(i + 1 < argc);
|
||||||
consoleIn = argv[i + 1];
|
consoleIn = argv[i + 1];
|
||||||
i++;
|
i++;
|
||||||
} else if (strcmp(argv[i], "-co") == 0) {
|
}
|
||||||
|
else if (strcmp(argv[i], "-co") == 0) {
|
||||||
ASSERT(i + 1 < argc);
|
ASSERT(i + 1 < argc);
|
||||||
consoleOut = argv[i + 1];
|
consoleOut = argv[i + 1];
|
||||||
i++;
|
i++;
|
||||||
#ifndef FILESYS_STUB
|
#ifndef FILESYS_STUB
|
||||||
} else if (strcmp(argv[i], "-f") == 0) {
|
}
|
||||||
|
else if (strcmp(argv[i], "-f") == 0) {
|
||||||
formatFlag = TRUE;
|
formatFlag = TRUE;
|
||||||
#endif
|
#endif
|
||||||
} else if (strcmp(argv[i], "-n") == 0) {
|
}
|
||||||
|
else if (strcmp(argv[i], "-n") == 0) {
|
||||||
ASSERT(i + 1 < argc); // next argument is float
|
ASSERT(i + 1 < argc); // next argument is float
|
||||||
reliability = atof(argv[i + 1]);
|
reliability = atof(argv[i + 1]);
|
||||||
i++;
|
i++;
|
||||||
} else if (strcmp(argv[i], "-m") == 0) {
|
}
|
||||||
|
else if (strcmp(argv[i], "-m") == 0) {
|
||||||
ASSERT(i + 1 < argc); // next argument is int
|
ASSERT(i + 1 < argc); // next argument is int
|
||||||
hostName = atoi(argv[i + 1]);
|
hostName = atoi(argv[i + 1]);
|
||||||
i++;
|
i++;
|
||||||
} else if (strcmp(argv[i], "-u") == 0) {
|
}
|
||||||
|
else if (strcmp(argv[i], "-u") == 0) {
|
||||||
cout << "Partial usage: nachos [-rs randomSeed]\n";
|
cout << "Partial usage: nachos [-rs randomSeed]\n";
|
||||||
cout << "Partial usage: nachos [-s]\n";
|
cout << "Partial usage: nachos [-s]\n";
|
||||||
cout << "Partial usage: nachos [-ci consoleIn] [-co consoleOut]\n";
|
cout << "Partial usage: nachos [-ci consoleIn] [-co consoleOut]\n";
|
||||||
@@ -92,32 +106,34 @@ Kernel::Kernel(int argc, char **argv)
|
|||||||
void
|
void
|
||||||
Kernel::Initialize()
|
Kernel::Initialize()
|
||||||
{
|
{
|
||||||
// We didn't explicitly allocate the current thread we are running in.
|
// We didn't explicitly allocate the current thread we are running in.
|
||||||
// But if it ever tries to give up the CPU, we better have a Thread
|
// But if it ever tries to give up the CPU, we better have a Thread
|
||||||
// object to save its state.
|
// object to save its state.
|
||||||
|
|
||||||
|
|
||||||
currentThread = new Thread("main", threadNum++);
|
currentThread = new Thread("main", threadNum++);
|
||||||
currentThread->setStatus(RUNNING);
|
currentThread->setStatus(RUNNING);
|
||||||
|
|
||||||
stats = new Statistics(); // collect statistics
|
stats = new Statistics(); // collect statistics
|
||||||
interrupt = new Interrupt; // start up interrupt handling
|
interrupt = new Interrupt; // start up interrupt handling
|
||||||
scheduler = new Scheduler(); // initialize the ready queue
|
scheduler = new Scheduler(); // initialize the ready queue
|
||||||
alarm = new Alarm(randomSlice); // start up time slicing
|
alarm = new Alarm(randomSlice); // start up time slicing
|
||||||
machine = new Machine(debugUserProg);
|
machine = new Machine(debugUserProg);
|
||||||
synchConsoleIn = new SynchConsoleInput(consoleIn); // input from stdin
|
synchConsoleIn = new SynchConsoleInput(consoleIn); // input from stdin
|
||||||
synchConsoleOut = new SynchConsoleOutput(consoleOut); // output to stdout
|
synchConsoleOut = new SynchConsoleOutput(consoleOut); // output to stdout
|
||||||
synchDisk = new SynchDisk(); //
|
synchDisk = new SynchDisk(); //
|
||||||
#ifdef FILESYS_STUB
|
#ifdef FILESYS_STUB
|
||||||
fileSystem = new FileSystem();
|
fileSystem = new FileSystem();
|
||||||
#else
|
#else
|
||||||
fileSystem = new FileSystem(formatFlag);
|
fileSystem = new FileSystem(formatFlag);
|
||||||
#endif // FILESYS_STUB
|
#endif // FILESYS_STUB
|
||||||
postOfficeIn = new PostOfficeInput(10);
|
|
||||||
postOfficeOut = new PostOfficeOutput(reliability);
|
|
||||||
frameTable = new FrameTable;
|
|
||||||
|
|
||||||
interrupt->Enable();
|
// MP4 MODIFIED
|
||||||
|
// postOfficeIn = new PostOfficeInput(10);
|
||||||
|
// postOfficeOut = new PostOfficeOutput(reliability);
|
||||||
|
|
||||||
|
frameTable = new FrameTable();
|
||||||
|
interrupt->Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -127,20 +143,23 @@ Kernel::Initialize()
|
|||||||
|
|
||||||
Kernel::~Kernel()
|
Kernel::~Kernel()
|
||||||
{
|
{
|
||||||
delete stats;
|
delete stats;
|
||||||
delete interrupt;
|
delete interrupt;
|
||||||
delete scheduler;
|
delete scheduler;
|
||||||
delete alarm;
|
delete alarm;
|
||||||
delete machine;
|
delete machine;
|
||||||
delete synchConsoleIn;
|
delete synchConsoleIn;
|
||||||
delete synchConsoleOut;
|
delete synchConsoleOut;
|
||||||
delete synchDisk;
|
delete synchDisk;
|
||||||
delete fileSystem;
|
delete fileSystem;
|
||||||
delete postOfficeIn;
|
|
||||||
delete postOfficeOut;
|
|
||||||
delete frameTable;
|
|
||||||
|
|
||||||
Exit(0);
|
// MP4 MODIFIED
|
||||||
|
// delete postOfficeIn;
|
||||||
|
// delete postOfficeOut;
|
||||||
|
|
||||||
|
delete frameTable;
|
||||||
|
|
||||||
|
Exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -150,23 +169,23 @@ Kernel::~Kernel()
|
|||||||
|
|
||||||
void
|
void
|
||||||
Kernel::ThreadSelfTest() {
|
Kernel::ThreadSelfTest() {
|
||||||
Semaphore *semaphore;
|
Semaphore* semaphore;
|
||||||
SynchList<int> *synchList;
|
SynchList<int>* synchList;
|
||||||
|
|
||||||
LibSelfTest(); // test library routines
|
LibSelfTest(); // test library routines
|
||||||
|
|
||||||
currentThread->SelfTest(); // test thread switching
|
currentThread->SelfTest(); // test thread switching
|
||||||
|
|
||||||
// test semaphore operation
|
// test semaphore operation
|
||||||
semaphore = new Semaphore("test", 0);
|
semaphore = new Semaphore("test", 0);
|
||||||
semaphore->SelfTest();
|
semaphore->SelfTest();
|
||||||
delete semaphore;
|
delete semaphore;
|
||||||
|
|
||||||
// test locks, condition variables
|
// test locks, condition variables
|
||||||
// using synchronized lists
|
// using synchronized lists
|
||||||
synchList = new SynchList<int>;
|
synchList = new SynchList<int>;
|
||||||
synchList->SelfTest(9);
|
synchList->SelfTest(9);
|
||||||
delete synchList;
|
delete synchList;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,14 +198,14 @@ void
|
|||||||
Kernel::ConsoleTest() {
|
Kernel::ConsoleTest() {
|
||||||
char ch;
|
char ch;
|
||||||
|
|
||||||
cout << "Testing the console device.\n"
|
cout << "Testing the console device.\n"
|
||||||
<< "Typed characters will be echoed, until ^D is typed.\n"
|
<< "Typed characters will be echoed, until ^D is typed.\n"
|
||||||
<< "Note newlines are needed to flush input through UNIX.\n";
|
<< "Note newlines are needed to flush input through UNIX.\n";
|
||||||
cout.flush();
|
cout.flush();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
ch = synchConsoleIn->GetChar();
|
ch = synchConsoleIn->GetChar();
|
||||||
if(ch != EOF) synchConsoleOut->PutChar(ch); // echo it!
|
if (ch != EOF) synchConsoleOut->PutChar(ch); // echo it!
|
||||||
} while (ch != EOF);
|
} while (ch != EOF);
|
||||||
|
|
||||||
cout << "\n";
|
cout << "\n";
|
||||||
@@ -211,28 +230,28 @@ Kernel::NetworkTest() {
|
|||||||
|
|
||||||
if (hostName == 0 || hostName == 1) {
|
if (hostName == 0 || hostName == 1) {
|
||||||
// if we're machine 1, send to 0 and vice versa
|
// if we're machine 1, send to 0 and vice versa
|
||||||
int farHost = (hostName == 0 ? 1 : 0);
|
int farHost = (hostName == 0 ? 1 : 0);
|
||||||
PacketHeader outPktHdr, inPktHdr;
|
PacketHeader outPktHdr, inPktHdr;
|
||||||
MailHeader outMailHdr, inMailHdr;
|
MailHeader outMailHdr, inMailHdr;
|
||||||
char *data = "Hello there!";
|
char* data = "Hello there!";
|
||||||
char *ack = "Got it!";
|
char* ack = "Got it!";
|
||||||
char buffer[MaxMailSize];
|
char buffer[MaxMailSize];
|
||||||
|
|
||||||
// construct packet, mail header for original message
|
// construct packet, mail header for original message
|
||||||
// To: destination machine, mailbox 0
|
// To: destination machine, mailbox 0
|
||||||
// From: our machine, reply to: mailbox 1
|
// From: our machine, reply to: mailbox 1
|
||||||
outPktHdr.to = farHost;
|
outPktHdr.to = farHost;
|
||||||
outMailHdr.to = 0;
|
outMailHdr.to = 0;
|
||||||
outMailHdr.from = 1;
|
outMailHdr.from = 1;
|
||||||
outMailHdr.length = strlen(data) + 1;
|
outMailHdr.length = strlen(data) + 1;
|
||||||
|
|
||||||
// Send the first message
|
// Send the first message
|
||||||
postOfficeOut->Send(outPktHdr, outMailHdr, data);
|
postOfficeOut->Send(outPktHdr, outMailHdr, data);
|
||||||
|
|
||||||
// Wait for the first message from the other machine
|
// Wait for the first message from the other machine
|
||||||
postOfficeIn->Receive(0, &inPktHdr, &inMailHdr, buffer);
|
postOfficeIn->Receive(0, &inPktHdr, &inMailHdr, buffer);
|
||||||
cout << "Got: " << buffer << " : from " << inPktHdr.from << ", box "
|
cout << "Got: " << buffer << " : from " << inPktHdr.from << ", box "
|
||||||
<< inMailHdr.from << "\n";
|
<< inMailHdr.from << "\n";
|
||||||
cout.flush();
|
cout.flush();
|
||||||
|
|
||||||
// Send acknowledgement to the other machine (using "reply to" mailbox
|
// Send acknowledgement to the other machine (using "reply to" mailbox
|
||||||
@@ -240,76 +259,78 @@ Kernel::NetworkTest() {
|
|||||||
outPktHdr.to = inPktHdr.from;
|
outPktHdr.to = inPktHdr.from;
|
||||||
outMailHdr.to = inMailHdr.from;
|
outMailHdr.to = inMailHdr.from;
|
||||||
outMailHdr.length = strlen(ack) + 1;
|
outMailHdr.length = strlen(ack) + 1;
|
||||||
postOfficeOut->Send(outPktHdr, outMailHdr, ack);
|
postOfficeOut->Send(outPktHdr, outMailHdr, ack);
|
||||||
|
|
||||||
// Wait for the ack from the other machine to the first message we sent
|
// Wait for the ack from the other machine to the first message we sent
|
||||||
postOfficeIn->Receive(1, &inPktHdr, &inMailHdr, buffer);
|
postOfficeIn->Receive(1, &inPktHdr, &inMailHdr, buffer);
|
||||||
cout << "Got: " << buffer << " : from " << inPktHdr.from << ", box "
|
cout << "Got: " << buffer << " : from " << inPktHdr.from << ", box "
|
||||||
<< inMailHdr.from << "\n";
|
<< inMailHdr.from << "\n";
|
||||||
cout.flush();
|
cout.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then we're done!
|
// Then we're done!
|
||||||
}
|
}
|
||||||
|
|
||||||
void ForkExecute(Thread *t)
|
void ForkExecute(Thread* t)
|
||||||
{
|
{
|
||||||
if (!t->space->Load(t->getName()))
|
if (!t->space->Load(t->getName())) {
|
||||||
return; // executable not found
|
return; // executable not found
|
||||||
|
}
|
||||||
|
|
||||||
|
t->space->Execute(t->getName());
|
||||||
|
|
||||||
t->space->Execute(t->getName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::ExecAll()
|
void Kernel::ExecAll()
|
||||||
{
|
{
|
||||||
for (int i=1;i<=execfileNum;i++) {
|
for (int i = 1;i <= execfileNum;i++) {
|
||||||
int a = Exec(execfile[i]);
|
int a = Exec(execfile[i], execPriority[i]);
|
||||||
}
|
}
|
||||||
currentThread->Finish();
|
currentThread->Finish();
|
||||||
//Kernel::Exec();
|
//Kernel::Exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Todo ----
|
||||||
int Kernel::Exec(char* name)
|
int Kernel::Exec(char* name, int priority)
|
||||||
{
|
{
|
||||||
t[threadNum] = new Thread(name, threadNum);
|
t[threadNum] = new Thread(name, threadNum);
|
||||||
t[threadNum]->space = new AddrSpace();
|
t[threadNum]->setPriority(priority);
|
||||||
t[threadNum]->Fork((VoidFunctionPtr) &ForkExecute, (void *)t[threadNum]);
|
// ---------
|
||||||
|
t[threadNum]->space = new AddrSpace();
|
||||||
|
t[threadNum]->Fork((VoidFunctionPtr)&ForkExecute, (void*)t[threadNum]);
|
||||||
|
threadNum++;
|
||||||
|
|
||||||
return threadNum++;
|
return threadNum - 1;
|
||||||
/*
|
/*
|
||||||
cout << "Total threads number is " << execfileNum << endl;
|
cout << "Total threads number is " << execfileNum << endl;
|
||||||
for (int n=1;n<=execfileNum;n++) {
|
for (int n=1;n<=execfileNum;n++) {
|
||||||
t[n] = new Thread(execfile[n]);
|
t[n] = new Thread(execfile[n]);
|
||||||
t[n]->space = new AddrSpace();
|
t[n]->space = new AddrSpace();
|
||||||
t[n]->Fork((VoidFunctionPtr) &ForkExecute, (void *)t[n]);
|
t[n]->Fork((VoidFunctionPtr) &ForkExecute, (void *)t[n]);
|
||||||
cout << "Thread " << execfile[n] << " is executing." << endl;
|
cout << "Thread " << execfile[n] << " is executing." << endl;
|
||||||
}
|
}
|
||||||
cout << "debug Kernel::Run finished.\n";
|
cout << "debug Kernel::Run finished.\n";
|
||||||
*/
|
*/
|
||||||
// Thread *t1 = new Thread(execfile[1]);
|
// Thread *t1 = new Thread(execfile[1]);
|
||||||
// Thread *t1 = new Thread("../test/test1");
|
// Thread *t1 = new Thread("../test/test1");
|
||||||
// Thread *t2 = new Thread("../test/test2");
|
// Thread *t2 = new Thread("../test/test2");
|
||||||
|
|
||||||
// AddrSpace *halt = new AddrSpace();
|
// AddrSpace *halt = new AddrSpace();
|
||||||
// t1->space = new AddrSpace();
|
// t1->space = new AddrSpace();
|
||||||
// t2->space = new AddrSpace();
|
// t2->space = new AddrSpace();
|
||||||
|
|
||||||
// halt->Execute("../test/halt");
|
// halt->Execute("../test/halt");
|
||||||
// t1->Fork((VoidFunctionPtr) &ForkExecute, (void *)t1);
|
// t1->Fork((VoidFunctionPtr) &ForkExecute, (void *)t1);
|
||||||
// t2->Fork((VoidFunctionPtr) &ForkExecute, (void *)t2);
|
// t2->Fork((VoidFunctionPtr) &ForkExecute, (void *)t2);
|
||||||
|
|
||||||
// currentThread->Finish();
|
// currentThread->Finish();
|
||||||
// Kernel::Run();
|
// Kernel::Run();
|
||||||
// cout << "after ThreadedKernel:Run();" << endl; // unreachable
|
// cout << "after ThreadedKernel:Run();" << endl; // unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
int Kernel::CreateFile(char *filename)
|
int Kernel::CreateFile(char* filename)
|
||||||
{
|
{
|
||||||
return fileSystem->Create(filename);
|
return fileSystem->Create(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::PrintInt(int value)
|
|
||||||
{
|
|
||||||
return synchConsoleOut->PutInt(value);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -25,31 +25,34 @@ class SynchConsoleInput;
|
|||||||
class SynchConsoleOutput;
|
class SynchConsoleOutput;
|
||||||
class SynchDisk;
|
class SynchDisk;
|
||||||
|
|
||||||
|
// Todo ----
|
||||||
|
// ---------
|
||||||
|
|
||||||
class Kernel {
|
class Kernel {
|
||||||
public:
|
public:
|
||||||
Kernel(int argc, char **argv);
|
Kernel(int argc, char **argv);
|
||||||
// Interpret command line arguments
|
// Interpret command line arguments
|
||||||
~Kernel(); // deallocate the kernel
|
~Kernel(); // deallocate the kernel
|
||||||
|
|
||||||
void Initialize(); // initialize the kernel -- separated
|
void Initialize(); // initialize the kernel -- separated
|
||||||
// from constructor because
|
// from constructor because
|
||||||
// refers to "kernel" as a global
|
// refers to "kernel" as a global
|
||||||
void ExecAll();
|
void ExecAll();
|
||||||
int Exec(char* name);
|
|
||||||
|
// Todo ----
|
||||||
|
int Exec(char* name, int priority);
|
||||||
|
// ---------
|
||||||
|
|
||||||
void ThreadSelfTest(); // self test of threads and synchronization
|
void ThreadSelfTest(); // self test of threads and synchronization
|
||||||
|
|
||||||
void ConsoleTest(); // interactive console self test
|
void ConsoleTest(); // interactive console self test
|
||||||
void NetworkTest(); // interactive 2-machine network test
|
void NetworkTest(); // interactive 2-machine network test
|
||||||
Thread* getThread(int threadID){return t[threadID];}
|
Thread* getThread(int threadID){return t[threadID];}
|
||||||
|
|
||||||
void PrintInt(int n);
|
|
||||||
|
|
||||||
int CreateFile(char* filename); // fileSystem call
|
int CreateFile(char* filename); // fileSystem call
|
||||||
|
|
||||||
// These are public for notational convenience; really,
|
// These are public for notational convenience; really,
|
||||||
// they're global variables used everywhere.
|
// they're global variables used everywhere.
|
||||||
|
|
||||||
Thread *currentThread; // the thread holding the CPU
|
Thread *currentThread; // the thread holding the CPU
|
||||||
Scheduler *scheduler; // the ready list
|
Scheduler *scheduler; // the ready list
|
||||||
@@ -60,17 +63,21 @@ class Kernel {
|
|||||||
SynchConsoleInput *synchConsoleIn;
|
SynchConsoleInput *synchConsoleIn;
|
||||||
SynchConsoleOutput *synchConsoleOut;
|
SynchConsoleOutput *synchConsoleOut;
|
||||||
SynchDisk *synchDisk;
|
SynchDisk *synchDisk;
|
||||||
FileSystem *fileSystem;
|
FileSystem *fileSystem;
|
||||||
PostOfficeInput *postOfficeIn;
|
PostOfficeInput *postOfficeIn;
|
||||||
PostOfficeOutput *postOfficeOut;
|
PostOfficeOutput *postOfficeOut;
|
||||||
FrameTable *frameTable;
|
FrameTable *frameTable;
|
||||||
|
|
||||||
int hostName; // machine identifier
|
int hostName; // machine identifier
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Thread* t[10];
|
Thread* t[10];
|
||||||
|
|
||||||
|
// Todo ----
|
||||||
char* execfile[10];
|
char* execfile[10];
|
||||||
|
int execPriority[10];
|
||||||
|
// ---------
|
||||||
|
|
||||||
int execfileNum;
|
int execfileNum;
|
||||||
int threadNum;
|
int threadNum;
|
||||||
bool randomSlice; // enable pseudo-random time slicing
|
bool randomSlice; // enable pseudo-random time slicing
|
||||||
@@ -85,5 +92,3 @@ class Kernel {
|
|||||||
|
|
||||||
|
|
||||||
#endif // KERNEL_H
|
#endif // KERNEL_H
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -47,8 +47,8 @@
|
|||||||
#include "sysdep.h"
|
#include "sysdep.h"
|
||||||
|
|
||||||
// global variables
|
// global variables
|
||||||
Kernel *kernel;
|
Kernel* kernel;
|
||||||
Debug *debug;
|
Debug* debug;
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -56,11 +56,11 @@ Debug *debug;
|
|||||||
// Delete kernel data structures; called when user hits "ctl-C".
|
// Delete kernel data structures; called when user hits "ctl-C".
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
static void
|
static void
|
||||||
Cleanup(int x)
|
Cleanup(int x)
|
||||||
{
|
{
|
||||||
cerr << "\nCleaning up after signal " << x << "\n";
|
cerr << "\nCleaning up after signal " << x << "\n";
|
||||||
delete kernel;
|
delete kernel;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
@@ -78,42 +78,42 @@ static const int TransferSize = 128;
|
|||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
static void
|
static void
|
||||||
Copy(char *from, char *to)
|
Copy(char* from, char* to)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
OpenFile* openFile;
|
OpenFile* openFile;
|
||||||
int amountRead, fileLength;
|
int amountRead, fileLength;
|
||||||
char *buffer;
|
char* buffer;
|
||||||
|
|
||||||
// Open UNIX file
|
// Open UNIX file
|
||||||
if ((fd = OpenForReadWrite(from,FALSE)) < 0) {
|
if ((fd = OpenForReadWrite(from, FALSE)) < 0) {
|
||||||
printf("Copy: couldn't open input file %s\n", from);
|
printf("Copy: couldn't open input file %s\n", from);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Figure out length of UNIX file
|
// Figure out length of UNIX file
|
||||||
Lseek(fd, 0, 2);
|
Lseek(fd, 0, 2);
|
||||||
fileLength = Tell(fd);
|
fileLength = Tell(fd);
|
||||||
Lseek(fd, 0, 0);
|
Lseek(fd, 0, 0);
|
||||||
|
|
||||||
// Create a Nachos file of the same length
|
// Create a Nachos file of the same length
|
||||||
DEBUG('f', "Copying file " << from << " of size " << fileLength << " to file " << to);
|
DEBUG('f', "Copying file " << from << " of size " << fileLength << " to file " << to);
|
||||||
if (!kernel->fileSystem->Create(to, fileLength)) { // Create Nachos file
|
if (!kernel->fileSystem->Create(to, fileLength)) { // Create Nachos file
|
||||||
printf("Copy: couldn't create output file %s\n", to);
|
printf("Copy: couldn't create output file %s\n", to);
|
||||||
Close(fd);
|
Close(fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
openFile = kernel->fileSystem->Open(to);
|
openFile = kernel->fileSystem->Open(to);
|
||||||
ASSERT(openFile != NULL);
|
ASSERT(openFile != NULL);
|
||||||
|
|
||||||
// Copy the data in TransferSize chunks
|
|
||||||
buffer = new char[TransferSize];
|
|
||||||
while ((amountRead=ReadPartial(fd, buffer, sizeof(char)*TransferSize)) > 0)
|
|
||||||
openFile->Write(buffer, amountRead);
|
|
||||||
delete [] buffer;
|
|
||||||
|
|
||||||
// Close the UNIX and the Nachos files
|
// Copy the data in TransferSize chunks
|
||||||
|
buffer = new char[TransferSize];
|
||||||
|
while ((amountRead = ReadPartial(fd, buffer, sizeof(char) * TransferSize)) > 0)
|
||||||
|
openFile->Write(buffer, amountRead);
|
||||||
|
delete[] buffer;
|
||||||
|
|
||||||
|
// Close the UNIX and the Nachos files
|
||||||
delete openFile;
|
delete openFile;
|
||||||
Close(fd);
|
Close(fd);
|
||||||
}
|
}
|
||||||
@@ -126,22 +126,22 @@ Copy(char *from, char *to)
|
|||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void
|
||||||
Print(char *name)
|
Print(char* name)
|
||||||
{
|
{
|
||||||
OpenFile *openFile;
|
OpenFile* openFile;
|
||||||
int i, amountRead;
|
int i, amountRead;
|
||||||
char *buffer;
|
char* buffer;
|
||||||
|
|
||||||
if ((openFile = kernel->fileSystem->Open(name)) == NULL) {
|
if ((openFile = kernel->fileSystem->Open(name)) == NULL) {
|
||||||
printf("Print: unable to open file %s\n", name);
|
printf("Print: unable to open file %s\n", name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer = new char[TransferSize];
|
buffer = new char[TransferSize];
|
||||||
while ((amountRead = openFile->Read(buffer, TransferSize)) > 0)
|
while ((amountRead = openFile->Read(buffer, TransferSize)) > 0)
|
||||||
for (i = 0; i < amountRead; i++)
|
for (i = 0; i < amountRead; i++)
|
||||||
printf("%c", buffer[i]);
|
printf("%c", buffer[i]);
|
||||||
delete [] buffer;
|
delete[] buffer;
|
||||||
|
|
||||||
delete openFile; // close the Nachos file
|
delete openFile; // close the Nachos file
|
||||||
return;
|
return;
|
||||||
@@ -164,19 +164,19 @@ Print(char *name)
|
|||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char *debugArg = "";
|
char* debugArg = "";
|
||||||
char *userProgName = NULL; // default is not to execute a user prog
|
char* userProgName = NULL; // default is not to execute a user prog
|
||||||
bool threadTestFlag = false;
|
bool threadTestFlag = false;
|
||||||
bool consoleTestFlag = false;
|
bool consoleTestFlag = false;
|
||||||
bool networkTestFlag = false;
|
bool networkTestFlag = false;
|
||||||
#ifndef FILESYS_STUB
|
#ifndef FILESYS_STUB
|
||||||
char *copyUnixFileName = NULL; // UNIX file to be copied into Nachos
|
char* copyUnixFileName = NULL; // UNIX file to be copied into Nachos
|
||||||
char *copyNachosFileName = NULL; // name of copied file in Nachos
|
char* copyNachosFileName = NULL; // name of copied file in Nachos
|
||||||
char *printFileName = NULL;
|
char* printFileName = NULL;
|
||||||
char *removeFileName = NULL;
|
char* removeFileName = NULL;
|
||||||
bool dirListFlag = false;
|
bool dirListFlag = false;
|
||||||
bool dumpFlag = false;
|
bool dumpFlag = false;
|
||||||
#endif //FILESYS_STUB
|
#endif //FILESYS_STUB
|
||||||
@@ -186,65 +186,65 @@ main(int argc, char **argv)
|
|||||||
// the Kernel constructor
|
// the Kernel constructor
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
||||||
if (strcmp(argv[i], "-d") == 0) {
|
if (strcmp(argv[i], "-d") == 0) {
|
||||||
ASSERT(i + 1 < argc); // next argument is debug string
|
ASSERT(i + 1 < argc); // next argument is debug string
|
||||||
debugArg = argv[i + 1];
|
debugArg = argv[i + 1];
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[i], "-z") == 0) {
|
else if (strcmp(argv[i], "-z") == 0) {
|
||||||
cout << copyright << "\n";
|
cout << copyright << "\n";
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[i], "-x") == 0) {
|
else if (strcmp(argv[i], "-x") == 0) {
|
||||||
ASSERT(i + 1 < argc);
|
ASSERT(i + 1 < argc);
|
||||||
userProgName = argv[i + 1];
|
userProgName = argv[i + 1];
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[i], "-K") == 0) {
|
else if (strcmp(argv[i], "-K") == 0) {
|
||||||
threadTestFlag = TRUE;
|
threadTestFlag = TRUE;
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[i], "-C") == 0) {
|
else if (strcmp(argv[i], "-C") == 0) {
|
||||||
consoleTestFlag = TRUE;
|
consoleTestFlag = TRUE;
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[i], "-N") == 0) {
|
else if (strcmp(argv[i], "-N") == 0) {
|
||||||
networkTestFlag = TRUE;
|
networkTestFlag = TRUE;
|
||||||
}
|
}
|
||||||
#ifndef FILESYS_STUB
|
#ifndef FILESYS_STUB
|
||||||
else if (strcmp(argv[i], "-cp") == 0) {
|
else if (strcmp(argv[i], "-cp") == 0) {
|
||||||
ASSERT(i + 2 < argc);
|
ASSERT(i + 2 < argc);
|
||||||
copyUnixFileName = argv[i + 1];
|
copyUnixFileName = argv[i + 1];
|
||||||
copyNachosFileName = argv[i + 2];
|
copyNachosFileName = argv[i + 2];
|
||||||
i += 2;
|
i += 2;
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[i], "-p") == 0) {
|
else if (strcmp(argv[i], "-p") == 0) {
|
||||||
ASSERT(i + 1 < argc);
|
ASSERT(i + 1 < argc);
|
||||||
printFileName = argv[i + 1];
|
printFileName = argv[i + 1];
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[i], "-r") == 0) {
|
else if (strcmp(argv[i], "-r") == 0) {
|
||||||
ASSERT(i + 1 < argc);
|
ASSERT(i + 1 < argc);
|
||||||
removeFileName = argv[i + 1];
|
removeFileName = argv[i + 1];
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[i], "-l") == 0) {
|
else if (strcmp(argv[i], "-l") == 0) {
|
||||||
dirListFlag = true;
|
dirListFlag = true;
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[i], "-D") == 0) {
|
else if (strcmp(argv[i], "-D") == 0) {
|
||||||
dumpFlag = true;
|
dumpFlag = true;
|
||||||
}
|
}
|
||||||
#endif //FILESYS_STUB
|
#endif //FILESYS_STUB
|
||||||
else if (strcmp(argv[i], "-u") == 0) {
|
else if (strcmp(argv[i], "-u") == 0) {
|
||||||
cout << "Partial usage: nachos [-z -d debugFlags]\n";
|
cout << "Partial usage: nachos [-z -d debugFlags]\n";
|
||||||
cout << "Partial usage: nachos [-x programName]\n";
|
cout << "Partial usage: nachos [-x programName]\n";
|
||||||
cout << "Partial usage: nachos [-K] [-C] [-N]\n";
|
cout << "Partial usage: nachos [-K] [-C] [-N]\n";
|
||||||
#ifndef FILESYS_STUB
|
#ifndef FILESYS_STUB
|
||||||
cout << "Partial usage: nachos [-cp UnixFile NachosFile]\n";
|
cout << "Partial usage: nachos [-cp UnixFile NachosFile]\n";
|
||||||
cout << "Partial usage: nachos [-p fileName] [-r fileName]\n";
|
cout << "Partial usage: nachos [-p fileName] [-r fileName]\n";
|
||||||
cout << "Partial usage: nachos [-l] [-D]\n";
|
cout << "Partial usage: nachos [-l] [-D]\n";
|
||||||
#endif //FILESYS_STUB
|
#endif //FILESYS_STUB
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
debug = new Debug(debugArg);
|
debug = new Debug(debugArg);
|
||||||
|
|
||||||
DEBUG(dbgThread, "Entering main");
|
DEBUG(dbgThread, "Entering main");
|
||||||
|
|
||||||
kernel = new Kernel(argc, argv);
|
kernel = new Kernel(argc, argv);
|
||||||
@@ -256,42 +256,42 @@ main(int argc, char **argv)
|
|||||||
// at this point, the kernel is ready to do something
|
// at this point, the kernel is ready to do something
|
||||||
// run some tests, if requested
|
// run some tests, if requested
|
||||||
if (threadTestFlag) {
|
if (threadTestFlag) {
|
||||||
kernel->ThreadSelfTest(); // test threads and synchronization
|
kernel->ThreadSelfTest(); // test threads and synchronization
|
||||||
}
|
}
|
||||||
if (consoleTestFlag) {
|
if (consoleTestFlag) {
|
||||||
kernel->ConsoleTest(); // interactive test of the synchronized console
|
kernel->ConsoleTest(); // interactive test of the synchronized console
|
||||||
}
|
}
|
||||||
if (networkTestFlag) {
|
if (networkTestFlag) {
|
||||||
kernel->NetworkTest(); // two-machine test of the network
|
kernel->NetworkTest(); // two-machine test of the network
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef FILESYS_STUB
|
#ifndef FILESYS_STUB
|
||||||
if (removeFileName != NULL) {
|
if (removeFileName != NULL) {
|
||||||
kernel->fileSystem->Remove(removeFileName);
|
kernel->fileSystem->Remove(removeFileName);
|
||||||
}
|
}
|
||||||
if (copyUnixFileName != NULL && copyNachosFileName != NULL) {
|
if (copyUnixFileName != NULL && copyNachosFileName != NULL) {
|
||||||
Copy(copyUnixFileName,copyNachosFileName);
|
Copy(copyUnixFileName, copyNachosFileName);
|
||||||
}
|
}
|
||||||
if (dumpFlag) {
|
if (dumpFlag) {
|
||||||
kernel->fileSystem->Print();
|
kernel->fileSystem->Print();
|
||||||
}
|
}
|
||||||
if (dirListFlag) {
|
if (dirListFlag) {
|
||||||
kernel->fileSystem->List();
|
kernel->fileSystem->List();
|
||||||
}
|
}
|
||||||
if (printFileName != NULL) {
|
if (printFileName != NULL) {
|
||||||
Print(printFileName);
|
Print(printFileName);
|
||||||
}
|
}
|
||||||
#endif // FILESYS_STUB
|
#endif // FILESYS_STUB
|
||||||
|
|
||||||
// finally, run an initial user program if requested to do so
|
// finally, run an initial user program if requested to do so
|
||||||
|
|
||||||
kernel->ExecAll();
|
kernel->ExecAll();
|
||||||
// If we don't run a user program, we may get here.
|
// If we don't run a user program, we may get here.
|
||||||
// Calling "return" would terminate the program.
|
// Calling "return" would terminate the program.
|
||||||
// Instead, call Halt, which will first clean up, then
|
// Instead, call Halt, which will first clean up, then
|
||||||
// terminate.
|
// terminate.
|
||||||
// kernel->interrupt->Halt();
|
// kernel->interrupt->Halt();
|
||||||
|
|
||||||
ASSERTNOTREACHED();
|
ASSERTNOTREACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Scheduler::Scheduler
|
// Scheduler::Scheduler
|
||||||
@@ -29,11 +30,22 @@
|
|||||||
// Initially, no ready threads.
|
// Initially, no ready threads.
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Todo ----
|
||||||
|
|
||||||
|
int cmp(Thread *a, Thread *b)
|
||||||
|
{
|
||||||
|
int ap = a->getPriority();
|
||||||
|
int bp = b->getPriority();
|
||||||
|
return (ap < bp) - (ap > bp);
|
||||||
|
}
|
||||||
|
|
||||||
Scheduler::Scheduler()
|
Scheduler::Scheduler()
|
||||||
{
|
{
|
||||||
readyList = new List<Thread *>;
|
readyList = new SortedList(cmp);
|
||||||
toBeDestroyed = NULL;
|
// ---------
|
||||||
}
|
|
||||||
|
toBeDestroyed = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Scheduler::~Scheduler
|
// Scheduler::~Scheduler
|
||||||
@@ -41,9 +53,9 @@ Scheduler::Scheduler()
|
|||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
Scheduler::~Scheduler()
|
Scheduler::~Scheduler()
|
||||||
{
|
{
|
||||||
delete readyList;
|
delete readyList;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Scheduler::ReadyToRun
|
// Scheduler::ReadyToRun
|
||||||
@@ -54,13 +66,15 @@ Scheduler::~Scheduler()
|
|||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void
|
||||||
Scheduler::ReadyToRun (Thread *thread)
|
Scheduler::ReadyToRun(Thread* thread)
|
||||||
{
|
{
|
||||||
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
||||||
DEBUG(dbgThread, "Putting thread on ready list: " << thread->getName());
|
DEBUG(dbgThread, "Putting thread on ready list: " << thread->getName());
|
||||||
//cout << "Putting thread on ready list: " << thread->getName() << endl ;
|
//cout << "Putting thread on ready list: " << thread->getName() << endl ;
|
||||||
thread->setStatus(READY);
|
thread->setStatus(READY);
|
||||||
readyList->Append(thread);
|
|
||||||
|
DEBUG(dbgSche, "[A] Tick [" << kernel->stats->totalTicks << "]: Process [" << thread->getName() << "] is inserted into queue.");
|
||||||
|
readyList->Insert(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -71,14 +85,16 @@ Scheduler::ReadyToRun (Thread *thread)
|
|||||||
// Thread is removed from the ready list.
|
// Thread is removed from the ready list.
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
Thread *
|
Thread*
|
||||||
Scheduler::FindNextToRun ()
|
Scheduler::FindNextToRun()
|
||||||
{
|
{
|
||||||
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
||||||
|
|
||||||
if (readyList->IsEmpty()) {
|
if (readyList->IsEmpty()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
|
DEBUG(dbgSche, "[B] Tick [" << kernel->stats->totalTicks << "]: Process [" << readyList->Front()->getName() << "] is removed from queue.");
|
||||||
return readyList->RemoveFront();
|
return readyList->RemoveFront();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,9 +117,9 @@ Scheduler::FindNextToRun ()
|
|||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void
|
||||||
Scheduler::Run (Thread *nextThread, bool finishing)
|
Scheduler::Run(Thread* nextThread, bool finishing)
|
||||||
{
|
{
|
||||||
Thread *oldThread = kernel->currentThread;
|
Thread* oldThread = kernel->currentThread;
|
||||||
|
|
||||||
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
||||||
|
|
||||||
@@ -124,6 +140,7 @@ Scheduler::Run (Thread *nextThread, bool finishing)
|
|||||||
nextThread->setStatus(RUNNING); // nextThread is now running
|
nextThread->setStatus(RUNNING); // nextThread is now running
|
||||||
|
|
||||||
DEBUG(dbgThread, "Switching from: " << oldThread->getName() << " to: " << nextThread->getName());
|
DEBUG(dbgThread, "Switching from: " << oldThread->getName() << " to: " << nextThread->getName());
|
||||||
|
DEBUG(dbgSche, "[C] Tick [" << kernel->stats->totalTicks << "]: Process [" << nextThread->getName() << "] is now selected for execution, thread [" << oldThread->getName() << "] is replaced.");
|
||||||
|
|
||||||
// This is a machine-dependent assembly language routine defined
|
// This is a machine-dependent assembly language routine defined
|
||||||
// in switch.s. You may have to think
|
// in switch.s. You may have to think
|
||||||
@@ -165,7 +182,7 @@ Scheduler::CheckToBeDestroyed()
|
|||||||
toBeDestroyed = NULL;
|
toBeDestroyed = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Scheduler::Print
|
// Scheduler::Print
|
||||||
// Print the scheduler state -- in other words, the contents of
|
// Print the scheduler state -- in other words, the contents of
|
||||||
@@ -174,6 +191,6 @@ Scheduler::CheckToBeDestroyed()
|
|||||||
void
|
void
|
||||||
Scheduler::Print()
|
Scheduler::Print()
|
||||||
{
|
{
|
||||||
cout << "Ready list contents:\n";
|
cout << "Ready list contents:\n";
|
||||||
readyList->Apply(ThreadPrint);
|
readyList->Apply(ThreadPrint);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,22 +23,25 @@ class Scheduler {
|
|||||||
~Scheduler(); // De-allocate ready list
|
~Scheduler(); // De-allocate ready list
|
||||||
|
|
||||||
void ReadyToRun(Thread* thread);
|
void ReadyToRun(Thread* thread);
|
||||||
// Thread can be dispatched.
|
// Thread can be dispatched.
|
||||||
Thread* FindNextToRun(); // Dequeue first thread on the ready
|
Thread* FindNextToRun(); // Dequeue first thread on the ready
|
||||||
// list, if any, and return thread.
|
// list, if any, and return thread.
|
||||||
void Run(Thread* nextThread, bool finishing);
|
void Run(Thread* nextThread, bool finishing);
|
||||||
// Cause nextThread to start running
|
// Cause nextThread to start running
|
||||||
void CheckToBeDestroyed();// Check if thread that had been
|
void CheckToBeDestroyed();// Check if thread that had been
|
||||||
// running needs to be deleted
|
// running needs to be deleted
|
||||||
void Print(); // Print contents of ready list
|
void Print(); // Print contents of ready list
|
||||||
|
|
||||||
// SelfTest for scheduler is implemented in class Thread
|
// SelfTest for scheduler is implemented in class Thread
|
||||||
|
|
||||||
private:
|
private:
|
||||||
List<Thread *> *readyList; // queue of threads that are ready to run,
|
// Todo ----
|
||||||
// but not running
|
SortedList<Thread *> *readyList; // queue of threads that are ready to run,
|
||||||
|
// but not running
|
||||||
|
// ---------
|
||||||
|
|
||||||
Thread *toBeDestroyed; // finishing thread to be destroyed
|
Thread *toBeDestroyed; // finishing thread to be destroyed
|
||||||
// by the next thread that runs
|
// by the next thread that runs
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SCHEDULER_H
|
#endif // SCHEDULER_H
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ Semaphore::Semaphore(char* debugName, int initialValue)
|
|||||||
{
|
{
|
||||||
name = debugName;
|
name = debugName;
|
||||||
value = initialValue;
|
value = initialValue;
|
||||||
queue = new List<Thread *>;
|
queue = new List<Thread*>;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -75,20 +75,20 @@ Semaphore::~Semaphore()
|
|||||||
void
|
void
|
||||||
Semaphore::P()
|
Semaphore::P()
|
||||||
{
|
{
|
||||||
Interrupt *interrupt = kernel->interrupt;
|
Interrupt* interrupt = kernel->interrupt;
|
||||||
Thread *currentThread = kernel->currentThread;
|
Thread* currentThread = kernel->currentThread;
|
||||||
|
|
||||||
// disable interrupts
|
// disable interrupts
|
||||||
IntStatus oldLevel = interrupt->SetLevel(IntOff);
|
IntStatus oldLevel = interrupt->SetLevel(IntOff);
|
||||||
|
|
||||||
while (value == 0) { // semaphore not available
|
while (value == 0) { // semaphore not available
|
||||||
queue->Append(currentThread); // so go to sleep
|
queue->Append(currentThread); // so go to sleep
|
||||||
currentThread->Sleep(FALSE);
|
currentThread->Sleep(FALSE);
|
||||||
}
|
}
|
||||||
value--; // semaphore available, consume its value
|
value--; // semaphore available, consume its value
|
||||||
|
|
||||||
// re-enable interrupts
|
// re-enable interrupts
|
||||||
(void) interrupt->SetLevel(oldLevel);
|
(void)interrupt->SetLevel(oldLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -102,18 +102,18 @@ Semaphore::P()
|
|||||||
void
|
void
|
||||||
Semaphore::V()
|
Semaphore::V()
|
||||||
{
|
{
|
||||||
Interrupt *interrupt = kernel->interrupt;
|
Interrupt* interrupt = kernel->interrupt;
|
||||||
|
|
||||||
// disable interrupts
|
// disable interrupts
|
||||||
IntStatus oldLevel = interrupt->SetLevel(IntOff);
|
IntStatus oldLevel = interrupt->SetLevel(IntOff);
|
||||||
|
|
||||||
if (!queue->IsEmpty()) { // make thread ready.
|
if (!queue->IsEmpty()) { // make thread ready.
|
||||||
kernel->scheduler->ReadyToRun(queue->RemoveFront());
|
kernel->scheduler->ReadyToRun(queue->RemoveFront());
|
||||||
}
|
}
|
||||||
value++;
|
value++;
|
||||||
|
|
||||||
// re-enable interrupts
|
// re-enable interrupts
|
||||||
(void) interrupt->SetLevel(oldLevel);
|
(void)interrupt->SetLevel(oldLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -122,27 +122,27 @@ Semaphore::V()
|
|||||||
// to control two threads ping-ponging back and forth.
|
// to control two threads ping-ponging back and forth.
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
static Semaphore *ping;
|
static Semaphore* ping;
|
||||||
static void
|
static void
|
||||||
SelfTestHelper (Semaphore *pong)
|
SelfTestHelper(Semaphore* pong)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
ping->P();
|
ping->P();
|
||||||
pong->V();
|
pong->V();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Semaphore::SelfTest()
|
Semaphore::SelfTest()
|
||||||
{
|
{
|
||||||
Thread *helper = new Thread("ping", 1);
|
Thread* helper = new Thread("ping", 1);
|
||||||
|
|
||||||
ASSERT(value == 0); // otherwise test won't work!
|
ASSERT(value == 0); // otherwise test won't work!
|
||||||
ping = new Semaphore("ping", 0);
|
ping = new Semaphore("ping", 0);
|
||||||
helper->Fork((VoidFunctionPtr) SelfTestHelper, this);
|
helper->Fork((VoidFunctionPtr)SelfTestHelper, this);
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
ping->V();
|
ping->V();
|
||||||
this->P();
|
this->P();
|
||||||
}
|
}
|
||||||
delete ping;
|
delete ping;
|
||||||
}
|
}
|
||||||
@@ -213,7 +213,7 @@ void Lock::Release()
|
|||||||
Condition::Condition(char* debugName)
|
Condition::Condition(char* debugName)
|
||||||
{
|
{
|
||||||
name = debugName;
|
name = debugName;
|
||||||
waitQueue = new List<Semaphore *>;
|
waitQueue = new List<Semaphore*>;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -241,18 +241,18 @@ Condition::~Condition()
|
|||||||
// "conditionLock" -- lock protecting the use of this condition
|
// "conditionLock" -- lock protecting the use of this condition
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void Condition::Wait(Lock* conditionLock)
|
void Condition::Wait(Lock* conditionLock)
|
||||||
{
|
{
|
||||||
Semaphore *waiter;
|
Semaphore* waiter;
|
||||||
|
|
||||||
ASSERT(conditionLock->IsHeldByCurrentThread());
|
|
||||||
|
|
||||||
waiter = new Semaphore("condition", 0);
|
ASSERT(conditionLock->IsHeldByCurrentThread());
|
||||||
waitQueue->Append(waiter);
|
|
||||||
conditionLock->Release();
|
waiter = new Semaphore("condition", 0);
|
||||||
waiter->P();
|
waitQueue->Append(waiter);
|
||||||
conditionLock->Acquire();
|
conditionLock->Release();
|
||||||
delete waiter;
|
waiter->P();
|
||||||
|
conditionLock->Acquire();
|
||||||
|
delete waiter;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -272,13 +272,13 @@ void Condition::Wait(Lock* conditionLock)
|
|||||||
|
|
||||||
void Condition::Signal(Lock* conditionLock)
|
void Condition::Signal(Lock* conditionLock)
|
||||||
{
|
{
|
||||||
Semaphore *waiter;
|
Semaphore* waiter;
|
||||||
|
|
||||||
ASSERT(conditionLock->IsHeldByCurrentThread());
|
ASSERT(conditionLock->IsHeldByCurrentThread());
|
||||||
|
|
||||||
if (!waitQueue->IsEmpty()) {
|
if (!waitQueue->IsEmpty()) {
|
||||||
waiter = waitQueue->RemoveFront();
|
waiter = waitQueue->RemoveFront();
|
||||||
waiter->V();
|
waiter->V();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,7 +289,7 @@ void Condition::Signal(Lock* conditionLock)
|
|||||||
// "conditionLock" -- lock protecting the use of this condition
|
// "conditionLock" -- lock protecting the use of this condition
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void Condition::Broadcast(Lock* conditionLock)
|
void Condition::Broadcast(Lock* conditionLock)
|
||||||
{
|
{
|
||||||
while (!waitQueue->IsEmpty()) {
|
while (!waitQueue->IsEmpty()) {
|
||||||
Signal(conditionLock);
|
Signal(conditionLock);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// thread.cc
|
// thread.cc
|
||||||
// Routines to manage threads. These are the main operations:
|
// Routines to manage threads. These are the main operations:
|
||||||
//
|
//
|
||||||
// Fork -- create a thread to run a procedure concurrently
|
// Fork -- create a thread to run a procedure concurrently
|
||||||
@@ -9,11 +9,11 @@
|
|||||||
// Finish -- called when the forked procedure finishes, to clean up
|
// Finish -- called when the forked procedure finishes, to clean up
|
||||||
// Yield -- relinquish control over the CPU to another ready thread
|
// Yield -- relinquish control over the CPU to another ready thread
|
||||||
// Sleep -- relinquish control over the CPU, but thread is now blocked.
|
// Sleep -- relinquish control over the CPU, but thread is now blocked.
|
||||||
// In other words, it will not run again, until explicitly
|
// In other words, it will not run again, until explicitly
|
||||||
// put back on the ready queue.
|
// put back on the ready queue.
|
||||||
//
|
//
|
||||||
// Copyright (c) 1992-1996 The Regents of the University of California.
|
// Copyright (c) 1992-1996 The Regents of the University of California.
|
||||||
// All rights reserved. See copyright.h for copyright notice and limitation
|
// All rights reserved. See copyright.h for copyright notice and limitation
|
||||||
// of liability and disclaimer of warranty provisions.
|
// of liability and disclaimer of warranty provisions.
|
||||||
|
|
||||||
#include "copyright.h"
|
#include "copyright.h"
|
||||||
@@ -33,19 +33,20 @@ const int STACK_FENCEPOST = 0xdedbeef;
|
|||||||
// "threadName" is an arbitrary string, useful for debugging.
|
// "threadName" is an arbitrary string, useful for debugging.
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
Thread::Thread(char* threadName, int threadID)
|
Thread::Thread(char *threadName, int threadID)
|
||||||
{
|
{
|
||||||
ID = threadID;
|
ID = threadID;
|
||||||
name = threadName;
|
name = threadName;
|
||||||
stackTop = NULL;
|
stackTop = NULL;
|
||||||
stack = NULL;
|
stack = NULL;
|
||||||
status = JUST_CREATED;
|
status = JUST_CREATED;
|
||||||
for (int i = 0; i < MachineStateSize; i++) {
|
for (int i = 0; i < MachineStateSize; i++)
|
||||||
machineState[i] = NULL; // not strictly necessary, since
|
{
|
||||||
// new thread ignores contents
|
machineState[i] = NULL; // not strictly necessary, since
|
||||||
// of machine registers
|
// new thread ignores contents
|
||||||
}
|
// of machine registers
|
||||||
space = NULL;
|
}
|
||||||
|
space = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -62,15 +63,15 @@ Thread::Thread(char* threadName, int threadID)
|
|||||||
|
|
||||||
Thread::~Thread()
|
Thread::~Thread()
|
||||||
{
|
{
|
||||||
DEBUG(dbgThread, "Deleting thread: " << name);
|
DEBUG(dbgThread, "Deleting thread: " << name);
|
||||||
ASSERT(this != kernel->currentThread);
|
ASSERT(this != kernel->currentThread);
|
||||||
if (stack != NULL)
|
if (stack != NULL)
|
||||||
DeallocBoundedArray((char *) stack, StackSize * sizeof(int));
|
DeallocBoundedArray((char *)stack, StackSize * sizeof(int));
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Thread::Fork
|
// Thread::Fork
|
||||||
// Invoke (*func)(arg), allowing caller and callee to execute
|
// Invoke (*func)(arg), allowing caller and callee to execute
|
||||||
// concurrently.
|
// concurrently.
|
||||||
//
|
//
|
||||||
// NOTE: although our definition allows only a single argument
|
// NOTE: although our definition allows only a single argument
|
||||||
@@ -83,26 +84,25 @@ Thread::~Thread()
|
|||||||
// 2. Initialize the stack so that a call to SWITCH will
|
// 2. Initialize the stack so that a call to SWITCH will
|
||||||
// cause it to run the procedure
|
// cause it to run the procedure
|
||||||
// 3. Put the thread on the ready queue
|
// 3. Put the thread on the ready queue
|
||||||
//
|
//
|
||||||
// "func" is the procedure to run concurrently.
|
// "func" is the procedure to run concurrently.
|
||||||
// "arg" is a single argument to be passed to the procedure.
|
// "arg" is a single argument to be passed to the procedure.
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void Thread::Fork(VoidFunctionPtr func, void *arg)
|
||||||
Thread::Fork(VoidFunctionPtr func, void *arg)
|
|
||||||
{
|
{
|
||||||
Interrupt *interrupt = kernel->interrupt;
|
Interrupt *interrupt = kernel->interrupt;
|
||||||
Scheduler *scheduler = kernel->scheduler;
|
Scheduler *scheduler = kernel->scheduler;
|
||||||
IntStatus oldLevel;
|
IntStatus oldLevel;
|
||||||
|
|
||||||
DEBUG(dbgThread, "Forking thread: " << name << " f(a): " << (int) func << " " << arg);
|
DEBUG(dbgThread, "Forking thread: " << name << " f(a): " << (int)func << " " << arg);
|
||||||
StackAllocate(func, arg);
|
StackAllocate(func, arg);
|
||||||
|
|
||||||
oldLevel = interrupt->SetLevel(IntOff);
|
oldLevel = interrupt->SetLevel(IntOff);
|
||||||
scheduler->ReadyToRun(this); // ReadyToRun assumes that interrupts
|
scheduler->ReadyToRun(this); // ReadyToRun assumes that interrupts
|
||||||
// are disabled!
|
// are disabled!
|
||||||
(void) interrupt->SetLevel(oldLevel);
|
(void)interrupt->SetLevel(oldLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Thread::CheckOverflow
|
// Thread::CheckOverflow
|
||||||
@@ -119,16 +119,16 @@ Thread::Fork(VoidFunctionPtr func, void *arg)
|
|||||||
// Don't do this: void foo() { int bigArray[10000]; ... }
|
// Don't do this: void foo() { int bigArray[10000]; ... }
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void Thread::CheckOverflow()
|
||||||
Thread::CheckOverflow()
|
|
||||||
{
|
{
|
||||||
if (stack != NULL) {
|
if (stack != NULL)
|
||||||
#ifdef HPUX // Stacks grow upward on the Snakes
|
{
|
||||||
ASSERT(stack[StackSize - 1] == STACK_FENCEPOST);
|
#ifdef HPUX // Stacks grow upward on the Snakes
|
||||||
|
ASSERT(stack[StackSize - 1] == STACK_FENCEPOST);
|
||||||
#else
|
#else
|
||||||
ASSERT(*stack == STACK_FENCEPOST);
|
ASSERT(*stack == STACK_FENCEPOST);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -137,28 +137,27 @@ Thread::CheckOverflow()
|
|||||||
// executing the forked procedure.
|
// executing the forked procedure.
|
||||||
//
|
//
|
||||||
// It's main responsibilities are:
|
// It's main responsibilities are:
|
||||||
// 1. deallocate the previously running thread if it finished
|
// 1. deallocate the previously running thread if it finished
|
||||||
// (see Thread::Finish())
|
// (see Thread::Finish())
|
||||||
// 2. enable interrupts (so we can get time-sliced)
|
// 2. enable interrupts (so we can get time-sliced)
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void Thread::Begin()
|
||||||
Thread::Begin ()
|
|
||||||
{
|
{
|
||||||
ASSERT(this == kernel->currentThread);
|
ASSERT(this == kernel->currentThread);
|
||||||
DEBUG(dbgThread, "Beginning thread: " << name);
|
DEBUG(dbgThread, "Beginning thread: " << name);
|
||||||
|
|
||||||
kernel->scheduler->CheckToBeDestroyed();
|
kernel->scheduler->CheckToBeDestroyed();
|
||||||
kernel->interrupt->Enable();
|
kernel->interrupt->Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Thread::Finish
|
// Thread::Finish
|
||||||
// Called by ThreadRoot when a thread is done executing the
|
// Called by ThreadRoot when a thread is done executing the
|
||||||
// forked procedure.
|
// forked procedure.
|
||||||
//
|
//
|
||||||
// NOTE: we can't immediately de-allocate the thread data structure
|
// NOTE: we can't immediately de-allocate the thread data structure
|
||||||
// or the execution stack, because we're still running in the thread
|
// or the execution stack, because we're still running in the thread
|
||||||
// and we're still on the stack! Instead, we tell the scheduler
|
// and we're still on the stack! Instead, we tell the scheduler
|
||||||
// to call the destructor, once it is running in the context of a different thread.
|
// to call the destructor, once it is running in the context of a different thread.
|
||||||
//
|
//
|
||||||
@@ -167,18 +166,16 @@ Thread::Begin ()
|
|||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
//
|
//
|
||||||
void
|
void Thread::Finish()
|
||||||
Thread::Finish ()
|
|
||||||
{
|
{
|
||||||
(void) kernel->interrupt->SetLevel(IntOff);
|
(void)kernel->interrupt->SetLevel(IntOff);
|
||||||
ASSERT(this == kernel->currentThread);
|
ASSERT(this == kernel->currentThread);
|
||||||
|
|
||||||
DEBUG(dbgThread, "Finishing thread: " << name);
|
DEBUG(dbgThread, "Finishing thread: " << name);
|
||||||
Sleep(TRUE); // invokes SWITCH
|
Sleep(TRUE); // invokes SWITCH
|
||||||
// not reached
|
// not reached
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Thread::Yield
|
// Thread::Yield
|
||||||
// Relinquish the CPU if any other thread is ready to run.
|
// Relinquish the CPU if any other thread is ready to run.
|
||||||
@@ -192,33 +189,33 @@ Thread::Finish ()
|
|||||||
// NOTE: we disable interrupts, so that looking at the thread
|
// NOTE: we disable interrupts, so that looking at the thread
|
||||||
// on the front of the ready list, and switching to it, can be done
|
// on the front of the ready list, and switching to it, can be done
|
||||||
// atomically. On return, we re-set the interrupt level to its
|
// atomically. On return, we re-set the interrupt level to its
|
||||||
// original state, in case we are called with interrupts disabled.
|
// original state, in case we are called with interrupts disabled.
|
||||||
//
|
//
|
||||||
// Similar to Thread::Sleep(), but a little different.
|
// Similar to Thread::Sleep(), but a little different.
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void Thread::Yield()
|
||||||
Thread::Yield ()
|
|
||||||
{
|
{
|
||||||
Thread *nextThread;
|
Thread *nextThread;
|
||||||
IntStatus oldLevel = kernel->interrupt->SetLevel(IntOff);
|
IntStatus oldLevel = kernel->interrupt->SetLevel(IntOff);
|
||||||
|
|
||||||
ASSERT(this == kernel->currentThread);
|
ASSERT(this == kernel->currentThread);
|
||||||
|
|
||||||
DEBUG(dbgThread, "Yielding thread: " << name);
|
DEBUG(dbgThread, "Yielding thread: " << name);
|
||||||
|
|
||||||
nextThread = kernel->scheduler->FindNextToRun();
|
nextThread = kernel->scheduler->FindNextToRun();
|
||||||
if (nextThread != NULL) {
|
if (nextThread != NULL)
|
||||||
kernel->scheduler->ReadyToRun(this);
|
{
|
||||||
kernel->scheduler->Run(nextThread, FALSE);
|
kernel->scheduler->ReadyToRun(this);
|
||||||
}
|
kernel->scheduler->Run(nextThread, FALSE);
|
||||||
(void) kernel->interrupt->SetLevel(oldLevel);
|
}
|
||||||
|
(void)kernel->interrupt->SetLevel(oldLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Thread::Sleep
|
// Thread::Sleep
|
||||||
// Relinquish the CPU, because the current thread has either
|
// Relinquish the CPU, because the current thread has either
|
||||||
// finished or is blocked waiting on a synchronization
|
// finished or is blocked waiting on a synchronization
|
||||||
// variable (Semaphore, Lock, or Condition). In the latter case,
|
// variable (Semaphore, Lock, or Condition). In the latter case,
|
||||||
// eventually some thread will wake this thread up, and put it
|
// eventually some thread will wake this thread up, and put it
|
||||||
// back on the ready queue, so that it can be re-scheduled.
|
// back on the ready queue, so that it can be re-scheduled.
|
||||||
@@ -231,34 +228,34 @@ Thread::Yield ()
|
|||||||
//
|
//
|
||||||
// NOTE: we assume interrupts are already disabled, because it
|
// NOTE: we assume interrupts are already disabled, because it
|
||||||
// is called from the synchronization routines which must
|
// is called from the synchronization routines which must
|
||||||
// disable interrupts for atomicity. We need interrupts off
|
// disable interrupts for atomicity. We need interrupts off
|
||||||
// so that there can't be a time slice between pulling the first thread
|
// so that there can't be a time slice between pulling the first thread
|
||||||
// off the ready list, and switching to it.
|
// off the ready list, and switching to it.
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
void
|
void Thread::Sleep(bool finishing)
|
||||||
Thread::Sleep (bool finishing)
|
|
||||||
{
|
{
|
||||||
Thread *nextThread;
|
Thread *nextThread;
|
||||||
|
|
||||||
ASSERT(this == kernel->currentThread);
|
ASSERT(this == kernel->currentThread);
|
||||||
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
ASSERT(kernel->interrupt->getLevel() == IntOff);
|
||||||
|
|
||||||
DEBUG(dbgThread, "Sleeping thread: " << name);
|
DEBUG(dbgThread, "Sleeping thread: " << name);
|
||||||
|
|
||||||
status = BLOCKED;
|
status = BLOCKED;
|
||||||
//cout << "debug Thread::Sleep " << name << "wait for Idle\n";
|
// cout << "debug Thread::Sleep " << name << "wait for Idle\n";
|
||||||
while ((nextThread = kernel->scheduler->FindNextToRun()) == NULL) {
|
while ((nextThread = kernel->scheduler->FindNextToRun()) == NULL)
|
||||||
kernel->interrupt->Idle(); // no one to run, wait for an interrupt
|
{
|
||||||
}
|
kernel->interrupt->Idle(); // no one to run, wait for an interrupt
|
||||||
// returns when it's time for us to run
|
}
|
||||||
kernel->scheduler->Run(nextThread, finishing);
|
// returns when it's time for us to run
|
||||||
|
kernel->scheduler->Run(nextThread, finishing);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// ThreadBegin, ThreadFinish, ThreadPrint
|
// ThreadBegin, ThreadFinish, ThreadPrint
|
||||||
// Dummy functions because C++ does not (easily) allow pointers to member
|
// Dummy functions because C++ does not (easily) allow pointers to member
|
||||||
// functions. So we create a dummy C function
|
// functions. So we create a dummy C function
|
||||||
// (which we can pass a pointer to), that then simply calls the
|
// (which we can pass a pointer to), that then simply calls the
|
||||||
// member function.
|
// member function.
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -277,16 +274,19 @@ void ThreadPrint(Thread *t) { t->Print(); }
|
|||||||
static void *
|
static void *
|
||||||
PLabelToAddr(void *plabel)
|
PLabelToAddr(void *plabel)
|
||||||
{
|
{
|
||||||
int funcPtr = (int) plabel;
|
int funcPtr = (int)plabel;
|
||||||
|
|
||||||
if (funcPtr & 0x02) {
|
if (funcPtr & 0x02)
|
||||||
// L-Field is set. This is a PLT pointer
|
{
|
||||||
funcPtr -= 2; // Get rid of the L bit
|
// L-Field is set. This is a PLT pointer
|
||||||
return (*(void **)funcPtr);
|
funcPtr -= 2; // Get rid of the L bit
|
||||||
} else {
|
return (*(void **)funcPtr);
|
||||||
// L-field not set.
|
}
|
||||||
return plabel;
|
else
|
||||||
}
|
{
|
||||||
|
// L-field not set.
|
||||||
|
return plabel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -302,62 +302,60 @@ PLabelToAddr(void *plabel)
|
|||||||
// "arg" is the parameter to be passed to the procedure
|
// "arg" is the parameter to be passed to the procedure
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void Thread::StackAllocate(VoidFunctionPtr func, void *arg)
|
||||||
Thread::StackAllocate (VoidFunctionPtr func, void *arg)
|
|
||||||
{
|
{
|
||||||
stack = (int *) AllocBoundedArray(StackSize * sizeof(int));
|
stack = (int *)AllocBoundedArray(StackSize * sizeof(int));
|
||||||
|
|
||||||
#ifdef PARISC
|
#ifdef PARISC
|
||||||
// HP stack works from low addresses to high addresses
|
// HP stack works from low addresses to high addresses
|
||||||
// everyone else works the other way: from high addresses to low addresses
|
// everyone else works the other way: from high addresses to low addresses
|
||||||
stackTop = stack + 16; // HP requires 64-byte frame marker
|
stackTop = stack + 16; // HP requires 64-byte frame marker
|
||||||
stack[StackSize - 1] = STACK_FENCEPOST;
|
stack[StackSize - 1] = STACK_FENCEPOST;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SPARC
|
#ifdef SPARC
|
||||||
stackTop = stack + StackSize - 96; // SPARC stack must contains at
|
stackTop = stack + StackSize - 96; // SPARC stack must contains at
|
||||||
// least 1 activation record
|
// least 1 activation record
|
||||||
// to start with.
|
// to start with.
|
||||||
*stack = STACK_FENCEPOST;
|
*stack = STACK_FENCEPOST;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PowerPC // RS6000
|
#ifdef PowerPC // RS6000
|
||||||
stackTop = stack + StackSize - 16; // RS6000 requires 64-byte frame marker
|
stackTop = stack + StackSize - 16; // RS6000 requires 64-byte frame marker
|
||||||
*stack = STACK_FENCEPOST;
|
*stack = STACK_FENCEPOST;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DECMIPS
|
#ifdef DECMIPS
|
||||||
stackTop = stack + StackSize - 4; // -4 to be on the safe side!
|
stackTop = stack + StackSize - 4; // -4 to be on the safe side!
|
||||||
*stack = STACK_FENCEPOST;
|
*stack = STACK_FENCEPOST;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ALPHA
|
#ifdef ALPHA
|
||||||
stackTop = stack + StackSize - 8; // -8 to be on the safe side!
|
stackTop = stack + StackSize - 8; // -8 to be on the safe side!
|
||||||
*stack = STACK_FENCEPOST;
|
*stack = STACK_FENCEPOST;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef x86
|
#ifdef x86
|
||||||
// the x86 passes the return address on the stack. In order for SWITCH()
|
// the x86 passes the return address on the stack. In order for SWITCH()
|
||||||
// to go to ThreadRoot when we switch to this thread, the return addres
|
// to go to ThreadRoot when we switch to this thread, the return addres
|
||||||
// used in SWITCH() must be the starting address of ThreadRoot.
|
// used in SWITCH() must be the starting address of ThreadRoot.
|
||||||
stackTop = stack + StackSize - 4; // -4 to be on the safe side!
|
stackTop = stack + StackSize - 4; // -4 to be on the safe side!
|
||||||
*(--stackTop) = (int) ThreadRoot;
|
*(--stackTop) = (int)ThreadRoot;
|
||||||
*stack = STACK_FENCEPOST;
|
*stack = STACK_FENCEPOST;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PARISC
|
#ifdef PARISC
|
||||||
machineState[PCState] = PLabelToAddr(ThreadRoot);
|
machineState[PCState] = PLabelToAddr(ThreadRoot);
|
||||||
machineState[StartupPCState] = PLabelToAddr(ThreadBegin);
|
machineState[StartupPCState] = PLabelToAddr(ThreadBegin);
|
||||||
machineState[InitialPCState] = PLabelToAddr(func);
|
machineState[InitialPCState] = PLabelToAddr(func);
|
||||||
machineState[InitialArgState] = arg;
|
machineState[InitialArgState] = arg;
|
||||||
machineState[WhenDonePCState] = PLabelToAddr(ThreadFinish);
|
machineState[WhenDonePCState] = PLabelToAddr(ThreadFinish);
|
||||||
#else
|
#else
|
||||||
machineState[PCState] = (void*)ThreadRoot;
|
machineState[PCState] = (void *)ThreadRoot;
|
||||||
machineState[StartupPCState] = (void*)ThreadBegin;
|
machineState[StartupPCState] = (void *)ThreadBegin;
|
||||||
machineState[InitialPCState] = (void*)func;
|
machineState[InitialPCState] = (void *)func;
|
||||||
machineState[InitialArgState] = (void*)arg;
|
machineState[InitialArgState] = (void *)arg;
|
||||||
machineState[WhenDonePCState] = (void*)ThreadFinish;
|
machineState[WhenDonePCState] = (void *)ThreadFinish;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,38 +365,35 @@ Thread::StackAllocate (VoidFunctionPtr func, void *arg)
|
|||||||
// Thread::SaveUserState
|
// Thread::SaveUserState
|
||||||
// Save the CPU state of a user program on a context switch.
|
// Save the CPU state of a user program on a context switch.
|
||||||
//
|
//
|
||||||
// Note that a user program thread has *two* sets of CPU registers --
|
// Note that a user program thread has *two* sets of CPU registers --
|
||||||
// one for its state while executing user code, one for its state
|
// one for its state while executing user code, one for its state
|
||||||
// while executing kernel code. This routine saves the former.
|
// while executing kernel code. This routine saves the former.
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void Thread::SaveUserState()
|
||||||
Thread::SaveUserState()
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NumTotalRegs; i++)
|
for (int i = 0; i < NumTotalRegs; i++)
|
||||||
userRegisters[i] = kernel->machine->ReadRegister(i);
|
userRegisters[i] = kernel->machine->ReadRegister(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Thread::RestoreUserState
|
// Thread::RestoreUserState
|
||||||
// Restore the CPU state of a user program on a context switch.
|
// Restore the CPU state of a user program on a context switch.
|
||||||
//
|
//
|
||||||
// Note that a user program thread has *two* sets of CPU registers --
|
// Note that a user program thread has *two* sets of CPU registers --
|
||||||
// one for its state while executing user code, one for its state
|
// one for its state while executing user code, one for its state
|
||||||
// while executing kernel code. This routine restores the former.
|
// while executing kernel code. This routine restores the former.
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void Thread::RestoreUserState()
|
||||||
Thread::RestoreUserState()
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NumTotalRegs; i++)
|
for (int i = 0; i < NumTotalRegs; i++)
|
||||||
kernel->machine->WriteRegister(i, userRegisters[i]);
|
kernel->machine->WriteRegister(i, userRegisters[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// SimpleThread
|
// SimpleThread
|
||||||
// Loop 5 times, yielding the CPU to another ready thread
|
// Loop 5 times, yielding the CPU to another ready thread
|
||||||
// each iteration.
|
// each iteration.
|
||||||
//
|
//
|
||||||
// "which" is simply a number identifying the thread, for debugging
|
// "which" is simply a number identifying the thread, for debugging
|
||||||
@@ -409,27 +404,40 @@ static void
|
|||||||
SimpleThread(int which)
|
SimpleThread(int which)
|
||||||
{
|
{
|
||||||
int num;
|
int num;
|
||||||
|
|
||||||
for (num = 0; num < 5; num++) {
|
for (num = 0; num < 5; num++)
|
||||||
cout << "*** thread " << which << " looped " << num << " times\n";
|
{
|
||||||
|
cout << "*** thread " << which << " looped " << num << " times\n";
|
||||||
kernel->currentThread->Yield();
|
kernel->currentThread->Yield();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Thread::SelfTest
|
// Thread::SelfTest
|
||||||
// Set up a ping-pong between two threads, by forking a thread
|
// Set up a ping-pong between two threads, by forking a thread
|
||||||
// to call SimpleThread, and then calling SimpleThread ourselves.
|
// to call SimpleThread, and then calling SimpleThread ourselves.
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void Thread::SelfTest()
|
||||||
Thread::SelfTest()
|
|
||||||
{
|
{
|
||||||
DEBUG(dbgThread, "Entering Thread::SelfTest");
|
DEBUG(dbgThread, "Entering Thread::SelfTest");
|
||||||
|
|
||||||
Thread *t = new Thread("forked thread", 1);
|
Thread *t = new Thread("forked thread", 1);
|
||||||
|
|
||||||
t->Fork((VoidFunctionPtr) SimpleThread, (void *) 1);
|
t->Fork((VoidFunctionPtr)SimpleThread, (void *)1);
|
||||||
kernel->currentThread->Yield();
|
kernel->currentThread->Yield();
|
||||||
SimpleThread(0);
|
SimpleThread(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Todo ----
|
||||||
|
int Thread::getPriority() const
|
||||||
|
{
|
||||||
|
return priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thread::setPriority(int p)
|
||||||
|
{
|
||||||
|
ASSERT(p >= 0 && p <= 149);
|
||||||
|
priority = p;
|
||||||
|
}
|
||||||
|
// ---------
|
||||||
|
|||||||
@@ -80,6 +80,10 @@ class Thread {
|
|||||||
int *stackTop; // the current stack pointer
|
int *stackTop; // the current stack pointer
|
||||||
void *machineState[MachineStateSize]; // all registers except for stackTop
|
void *machineState[MachineStateSize]; // all registers except for stackTop
|
||||||
|
|
||||||
|
// Todo ----
|
||||||
|
int priority;
|
||||||
|
// ---------
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Thread(char* debugName, int threadID); // initialize a Thread
|
Thread(char* debugName, int threadID); // initialize a Thread
|
||||||
~Thread(); // deallocate a Thread
|
~Thread(); // deallocate a Thread
|
||||||
@@ -89,6 +93,11 @@ class Thread {
|
|||||||
|
|
||||||
// basic thread operations
|
// basic thread operations
|
||||||
|
|
||||||
|
// Todo ----
|
||||||
|
int getPriority() const;
|
||||||
|
void setPriority(int p);
|
||||||
|
// ---------
|
||||||
|
|
||||||
void Fork(VoidFunctionPtr func, void *arg);
|
void Fork(VoidFunctionPtr func, void *arg);
|
||||||
// Make thread run (*func)(arg)
|
// Make thread run (*func)(arg)
|
||||||
void Yield(); // Relinquish the CPU if any
|
void Yield(); // Relinquish the CPU if any
|
||||||
@@ -97,32 +106,32 @@ class Thread {
|
|||||||
// relinquish the processor
|
// relinquish the processor
|
||||||
void Begin(); // Startup code for the thread
|
void Begin(); // Startup code for the thread
|
||||||
void Finish(); // The thread is done executing
|
void Finish(); // The thread is done executing
|
||||||
|
|
||||||
void CheckOverflow(); // Check if thread stack has overflowed
|
void CheckOverflow(); // Check if thread stack has overflowed
|
||||||
void setStatus(ThreadStatus st) { status = st; }
|
void setStatus(ThreadStatus st) { status = st; }
|
||||||
ThreadStatus getStatus() { return (status); }
|
ThreadStatus getStatus() { return (status); }
|
||||||
char* getName() { return (name); }
|
char* getName() { return (name); }
|
||||||
|
|
||||||
int getID() { return (ID); }
|
int getID() { return (ID); }
|
||||||
void Print() { cout << name; }
|
void Print() { cout << name; }
|
||||||
void SelfTest(); // test whether thread impl is working
|
void SelfTest(); // test whether thread impl is working
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// some of the private data for this class is listed above
|
// some of the private data for this class is listed above
|
||||||
|
|
||||||
int *stack; // Bottom of the stack
|
int *stack; // Bottom of the stack
|
||||||
// NULL if this is the main thread
|
// NULL if this is the main thread
|
||||||
// (If NULL, don't deallocate stack)
|
// (If NULL, don't deallocate stack)
|
||||||
ThreadStatus status; // ready, running or blocked
|
ThreadStatus status; // ready, running or blocked
|
||||||
char* name;
|
char* name;
|
||||||
int ID;
|
int ID;
|
||||||
void StackAllocate(VoidFunctionPtr func, void *arg);
|
void StackAllocate(VoidFunctionPtr func, void *arg);
|
||||||
// Allocate a stack for thread.
|
// Allocate a stack for thread.
|
||||||
// Used internally by Fork()
|
// Used internally by Fork()
|
||||||
|
|
||||||
// A thread running a user program actually has *two* sets of CPU registers --
|
// A thread running a user program actually has *two* sets of CPU registers --
|
||||||
// one for its state while executing user code, one for its state
|
// one for its state while executing user code, one for its state
|
||||||
// while executing kernel code.
|
// while executing kernel code.
|
||||||
|
|
||||||
int userRegisters[NumTotalRegs]; // user-level CPU register state
|
int userRegisters[NumTotalRegs]; // user-level CPU register state
|
||||||
|
|
||||||
|
|||||||
@@ -27,101 +27,35 @@
|
|||||||
// object file header, in case the file was generated on a little
|
// object file header, in case the file was generated on a little
|
||||||
// endian machine, and we're now running on a big endian machine.
|
// endian machine, and we're now running on a big endian machine.
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
static void
|
||||||
static void
|
SwapHeader(NoffHeader* noffH)
|
||||||
SwapHeader (NoffHeader *noffH)
|
|
||||||
{
|
{
|
||||||
noffH->noffMagic = WordToHost(noffH->noffMagic);
|
noffH->noffMagic = WordToHost(noffH->noffMagic);
|
||||||
noffH->code.size = WordToHost(noffH->code.size);
|
noffH->code.size = WordToHost(noffH->code.size);
|
||||||
noffH->code.virtualAddr = WordToHost(noffH->code.virtualAddr);
|
noffH->code.virtualAddr = WordToHost(noffH->code.virtualAddr);
|
||||||
noffH->code.inFileAddr = WordToHost(noffH->code.inFileAddr);
|
noffH->code.inFileAddr = WordToHost(noffH->code.inFileAddr);
|
||||||
#ifdef RDATA
|
#ifdef RDATA
|
||||||
noffH->readonlyData.size = WordToHost(noffH->readonlyData.size);
|
noffH->readonlyData.size = WordToHost(noffH->readonlyData.size);
|
||||||
noffH->readonlyData.virtualAddr =
|
noffH->readonlyData.virtualAddr =
|
||||||
WordToHost(noffH->readonlyData.virtualAddr);
|
WordToHost(noffH->readonlyData.virtualAddr);
|
||||||
noffH->readonlyData.inFileAddr =
|
noffH->readonlyData.inFileAddr =
|
||||||
WordToHost(noffH->readonlyData.inFileAddr);
|
WordToHost(noffH->readonlyData.inFileAddr);
|
||||||
#endif
|
#endif
|
||||||
noffH->initData.size = WordToHost(noffH->initData.size);
|
noffH->initData.size = WordToHost(noffH->initData.size);
|
||||||
noffH->initData.virtualAddr = WordToHost(noffH->initData.virtualAddr);
|
noffH->initData.virtualAddr = WordToHost(noffH->initData.virtualAddr);
|
||||||
noffH->initData.inFileAddr = WordToHost(noffH->initData.inFileAddr);
|
noffH->initData.inFileAddr = WordToHost(noffH->initData.inFileAddr);
|
||||||
noffH->uninitData.size = WordToHost(noffH->uninitData.size);
|
noffH->uninitData.size = WordToHost(noffH->uninitData.size);
|
||||||
noffH->uninitData.virtualAddr = WordToHost(noffH->uninitData.virtualAddr);
|
noffH->uninitData.virtualAddr = WordToHost(noffH->uninitData.virtualAddr);
|
||||||
noffH->uninitData.inFileAddr = WordToHost(noffH->uninitData.inFileAddr);
|
noffH->uninitData.inFileAddr = WordToHost(noffH->uninitData.inFileAddr);
|
||||||
|
|
||||||
#ifdef RDATA
|
#ifdef RDATA
|
||||||
DEBUG(dbgAddr, "code = " << noffH->code.size <<
|
DEBUG(dbgAddr, "code = " << noffH->code.size <<
|
||||||
" readonly = " << noffH->readonlyData.size <<
|
" readonly = " << noffH->readonlyData.size <<
|
||||||
" init = " << noffH->initData.size <<
|
" init = " << noffH->initData.size <<
|
||||||
" uninit = " << noffH->uninitData.size << "\n");
|
" uninit = " << noffH->uninitData.size << "\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameTable::Node::Node(int idx):
|
|
||||||
next(nullptr), idx(idx) {}
|
|
||||||
|
|
||||||
FrameTable::FrameTable()
|
|
||||||
{
|
|
||||||
available = NumPhysPages;
|
|
||||||
useCount = new int[NumPhysPages];
|
|
||||||
begin = end = new FrameTable::Node;
|
|
||||||
for (int i = 0; i < NumPhysPages; i++) {
|
|
||||||
useCount[i] = 0;
|
|
||||||
end->idx = i;
|
|
||||||
end->next = new FrameTable::Node;
|
|
||||||
end = end->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FrameTable::~FrameTable()
|
|
||||||
{
|
|
||||||
delete[] useCount;
|
|
||||||
while (begin != end) {
|
|
||||||
FrameTable::Node *tmpNode = begin;
|
|
||||||
begin = begin->next;
|
|
||||||
delete tmpNode;
|
|
||||||
}
|
|
||||||
delete begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
int FrameTable::Allocate()
|
|
||||||
{
|
|
||||||
if (available == 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
int ret = begin->idx;
|
|
||||||
Node *tmp = begin;
|
|
||||||
begin = begin->next;
|
|
||||||
delete tmp;
|
|
||||||
|
|
||||||
--available;
|
|
||||||
useCount[ret]++;
|
|
||||||
|
|
||||||
bzero(kernel->machine->mainMemory + ret * PageSize, PageSize);
|
|
||||||
|
|
||||||
//cerr << "Allocated at page: " << ret << endl;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameTable::Release(int phyPageNum)
|
|
||||||
{
|
|
||||||
useCount[phyPageNum]--;
|
|
||||||
|
|
||||||
if (useCount[phyPageNum] > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
++available;
|
|
||||||
|
|
||||||
//cerr << "Release page: " << end->idx << endl;
|
|
||||||
end->idx = phyPageNum;
|
|
||||||
end->next = new FrameTable::Node;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t FrameTable::RemainSize()
|
|
||||||
{
|
|
||||||
return available;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// AddrSpace::AddrSpace
|
// AddrSpace::AddrSpace
|
||||||
// Create an address space to run a user program.
|
// Create an address space to run a user program.
|
||||||
@@ -129,9 +63,24 @@ size_t FrameTable::RemainSize()
|
|||||||
// memory. For now, this is really simple (1:1), since we are
|
// memory. For now, this is really simple (1:1), since we are
|
||||||
// only uniprogramming, and we have a single unsegmented page table
|
// only uniprogramming, and we have a single unsegmented page table
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
AddrSpace::AddrSpace()
|
AddrSpace::AddrSpace()
|
||||||
{}
|
{
|
||||||
|
pageTable = NULL; // initialize with NULL
|
||||||
|
/*
|
||||||
|
pageTable = new TranslationEntry[NumPhysPages];
|
||||||
|
for (int i = 0; i < NumPhysPages; i++) {
|
||||||
|
pageTable[i].virtualPage = i; // for now, virt page # = phys page #
|
||||||
|
pageTable[i].physicalPage = i;
|
||||||
|
pageTable[i].valid = TRUE;
|
||||||
|
pageTable[i].use = FALSE;
|
||||||
|
pageTable[i].dirty = FALSE;
|
||||||
|
pageTable[i].readOnly = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// zero out the entire address space
|
||||||
|
bzero(kernel->machine->mainMemory, MemorySize);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// AddrSpace::~AddrSpace
|
// AddrSpace::~AddrSpace
|
||||||
@@ -140,10 +89,9 @@ AddrSpace::AddrSpace()
|
|||||||
|
|
||||||
AddrSpace::~AddrSpace()
|
AddrSpace::~AddrSpace()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NumPhysPages; i++)
|
/* delete pageTable; */
|
||||||
if (pageTable[i].use == TRUE)
|
// release frame table by page table
|
||||||
kernel->frameTable->Release(pageTable[i].physicalPage);
|
kernel->frameTable->Release(pageTable, numPages);
|
||||||
delete[] pageTable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -156,114 +104,140 @@ AddrSpace::~AddrSpace()
|
|||||||
//
|
//
|
||||||
// "fileName" is the file containing the object code to load into memory
|
// "fileName" is the file containing the object code to load into memory
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
bool
|
||||||
bool
|
AddrSpace::Load(char* fileName)
|
||||||
AddrSpace::Load(char *fileName)
|
|
||||||
{
|
{
|
||||||
//cerr << "AddrSpace::Load" << endl;
|
OpenFile* executable = kernel->fileSystem->Open(fileName);
|
||||||
OpenFile *executable = kernel->fileSystem->Open(fileName);
|
NoffHeader noffH;
|
||||||
NoffHeader noffH;
|
unsigned int size;
|
||||||
unsigned int size;
|
|
||||||
|
|
||||||
if (executable == NULL) {
|
if (executable == NULL) {
|
||||||
cerr << "Unable to open file " << fileName << "\n";
|
cerr << "Unable to open file " << fileName << "\n";
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
executable->ReadAt((char *)&noffH, sizeof(noffH), 0);
|
executable->ReadAt((char*)&noffH, sizeof(noffH), 0);
|
||||||
if ((noffH.noffMagic != NOFFMAGIC) &&
|
if ((noffH.noffMagic != NOFFMAGIC) &&
|
||||||
(WordToHost(noffH.noffMagic) == NOFFMAGIC))
|
(WordToHost(noffH.noffMagic) == NOFFMAGIC))
|
||||||
SwapHeader(&noffH);
|
SwapHeader(&noffH);
|
||||||
ASSERT(noffH.noffMagic == NOFFMAGIC);
|
ASSERT(noffH.noffMagic == NOFFMAGIC);
|
||||||
|
|
||||||
#ifdef RDATA
|
#ifdef RDATA
|
||||||
// how big is address space?
|
// how big is address space?
|
||||||
size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size +
|
size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size +
|
||||||
noffH.uninitData.size + UserStackSize;
|
noffH.uninitData.size + UserStackSize;
|
||||||
//cerr << noffH.code.size << ' '
|
// we need to increase the size
|
||||||
// << noffH.readonlyData.size << ' '
|
// to leave room for the stack
|
||||||
// << noffH.initData.size << ' '
|
|
||||||
// << noffH.uninitData.size << ' '
|
|
||||||
// << UserStackSize << endl;
|
|
||||||
// we need to increase the size
|
|
||||||
// to leave room for the stack
|
|
||||||
#else
|
#else
|
||||||
// how big is address space?
|
// how big is address space?
|
||||||
size = noffH.code.size + noffH.initData.size + noffH.uninitData.size
|
size = noffH.code.size + noffH.initData.size + noffH.uninitData.size
|
||||||
+ UserStackSize; // we need to increase the size
|
+ UserStackSize; // we need to increase the size
|
||||||
// to leave room for the stack
|
// to leave room for the stack
|
||||||
//cerr << noffH.code.size << ' '
|
|
||||||
// << noffH.initData.size << ' '
|
|
||||||
// << noffH.uninitData.size << ' '
|
|
||||||
// << UserStackSize << endl;
|
|
||||||
#endif
|
#endif
|
||||||
numPages = divRoundUp(size, PageSize);
|
numPages = divRoundUp(size, PageSize);
|
||||||
size = numPages * PageSize;
|
size = numPages * PageSize;
|
||||||
|
|
||||||
ASSERT(numPages <= NumPhysPages); // check we're not trying
|
pageTable = kernel->frameTable->Allocate(numPages);
|
||||||
// to run anything too big --
|
if (!pageTable) {
|
||||||
// at least until we have
|
kernel->interrupt->setStatus(SystemMode);
|
||||||
// virtual memory
|
ExceptionHandler(MemoryLimitException);
|
||||||
|
kernel->interrupt->setStatus(UserMode);
|
||||||
pageTable = new TranslationEntry[numPages];
|
|
||||||
for (int i = 0; i < numPages; i++) {
|
|
||||||
pageTable[i].virtualPage = i;
|
|
||||||
pageTable[i].physicalPage = -1;
|
|
||||||
pageTable[i].valid = TRUE;
|
|
||||||
pageTable[i].use = FALSE;
|
|
||||||
pageTable[i].dirty = FALSE;
|
|
||||||
pageTable[i].readOnly = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size);
|
|
||||||
|
|
||||||
// then, copy in the code and data segments into memory
|
|
||||||
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);
|
|
||||||
|
|
||||||
for (size_t cur = 0; cur < (size_t)noffH.initData.size; cur += PageSize) {
|
DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size);
|
||||||
size_t physAddr, size = min((size_t)PageSize, noffH.initData.size - cur);
|
|
||||||
Translate(noffH.initData.virtualAddr + cur, &physAddr, 1);
|
|
||||||
|
|
||||||
executable->ReadAt(
|
// then, copy in the code and data segments into memory
|
||||||
&(kernel->machine->mainMemory[physAddr]), size,
|
uint paddr; // physical address
|
||||||
noffH.initData.inFileAddr + cur);
|
ExceptionType ex; // occurring exception
|
||||||
|
int sz, // total size to load
|
||||||
|
vaddr, // base virtual address
|
||||||
|
fpos, // base file position
|
||||||
|
to_load; // size to load on each time
|
||||||
|
|
||||||
|
if (noffH.code.size > 0) {
|
||||||
|
DEBUG(dbgAddr, "Initializing code segment.");
|
||||||
|
DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size);
|
||||||
|
|
||||||
|
sz = noffH.code.size;
|
||||||
|
vaddr = noffH.code.virtualAddr;
|
||||||
|
fpos = noffH.code.inFileAddr;
|
||||||
|
|
||||||
|
for (uint offset = 0; offset < sz; offset += PageSize) {
|
||||||
|
ex = Translate(vaddr + offset, &paddr, 1);
|
||||||
|
|
||||||
|
if (ex != NoException) {
|
||||||
|
kernel->interrupt->setStatus(SystemMode);
|
||||||
|
ExceptionHandler(ex);
|
||||||
|
kernel->interrupt->setStatus(UserMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
to_load = offset + PageSize < sz ? PageSize : sz - offset;
|
||||||
|
|
||||||
|
executable->ReadAt(
|
||||||
|
&(kernel->machine->mainMemory[paddr]),
|
||||||
|
to_load, fpos + offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noffH.initData.size > 0) {
|
||||||
|
DEBUG(dbgAddr, "Initializing data segment.");
|
||||||
|
DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size);
|
||||||
|
|
||||||
|
sz = noffH.initData.size;
|
||||||
|
vaddr = noffH.initData.virtualAddr;
|
||||||
|
fpos = noffH.initData.inFileAddr;
|
||||||
|
|
||||||
|
for (uint offset = 0; offset < sz; offset += PageSize) {
|
||||||
|
ex = Translate(vaddr + offset, &paddr, 1);
|
||||||
|
|
||||||
|
if (ex != NoException) {
|
||||||
|
kernel->interrupt->setStatus(SystemMode);
|
||||||
|
ExceptionHandler(ex);
|
||||||
|
kernel->interrupt->setStatus(UserMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
to_load = offset + PageSize < sz ? PageSize : sz - offset;
|
||||||
|
|
||||||
|
executable->ReadAt(
|
||||||
|
&(kernel->machine->mainMemory[paddr]),
|
||||||
|
to_load, fpos + offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef RDATA
|
#ifdef RDATA
|
||||||
if (noffH.readonlyData.size > 0) {
|
if (noffH.readonlyData.size > 0) {
|
||||||
DEBUG(dbgAddr, "Initializing read only data segment.");
|
DEBUG(dbgAddr, "Initializing read only data segment.");
|
||||||
DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size);
|
DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size);
|
||||||
|
|
||||||
for (size_t cur = 0; cur < (size_t)noffH.readonlyData.size; cur += PageSize) {
|
sz = noffH.readonlyData.size;
|
||||||
size_t physAddr, size = min((size_t)PageSize, noffH.readonlyData.size - cur);
|
vaddr = noffH.readonlyData.virtualAddr;
|
||||||
Translate(noffH.readonlyData.virtualAddr + cur, &physAddr, 1);
|
fpos = noffH.readonlyData.inFileAddr;
|
||||||
|
|
||||||
executable->ReadAt(
|
// read only flag for page table
|
||||||
&(kernel->machine->mainMemory[physAddr]),
|
for (int i = 0, lim = divRoundUp(sz, PageSize),
|
||||||
size, noffH.readonlyData.inFileAddr + cur);
|
from = vaddr / PageSize; i < lim; ++i)
|
||||||
|
pageTable[from + i].readOnly = TRUE;
|
||||||
|
|
||||||
|
for (uint offset = 0; offset < sz; offset += PageSize) {
|
||||||
|
ex = Translate(vaddr + offset, &paddr, 0); // read only
|
||||||
|
|
||||||
|
if (ex != NoException) {
|
||||||
|
kernel->interrupt->setStatus(SystemMode);
|
||||||
|
ExceptionHandler(ex);
|
||||||
|
kernel->interrupt->setStatus(UserMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
to_load = offset + PageSize < sz ? PageSize : sz - offset;
|
||||||
|
|
||||||
|
executable->ReadAt(
|
||||||
|
&(kernel->machine->mainMemory[paddr]),
|
||||||
|
to_load, fpos + offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
delete executable; // close file
|
delete executable; // close file
|
||||||
return TRUE; // success
|
return TRUE; // success
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -274,21 +248,20 @@ AddrSpace::Load(char *fileName)
|
|||||||
// the address space
|
// the address space
|
||||||
//
|
//
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
void
|
||||||
void
|
AddrSpace::Execute(char* fileName)
|
||||||
AddrSpace::Execute(char* fileName)
|
|
||||||
{
|
{
|
||||||
//cerr << "AddrSpace::Execute" << endl;
|
|
||||||
kernel->currentThread->space = this;
|
|
||||||
|
|
||||||
this->InitRegisters(); // set the initial register values
|
kernel->currentThread->space = this;
|
||||||
this->RestoreState(); // load page table register
|
|
||||||
|
|
||||||
kernel->machine->Run(); // jump to the user progam
|
this->InitRegisters(); // set the initial register values
|
||||||
|
this->RestoreState(); // load page table register
|
||||||
|
|
||||||
ASSERTNOTREACHED(); // machine->Run never returns;
|
kernel->machine->Run(); // jump to the user program
|
||||||
// the address space exits
|
|
||||||
// by doing the syscall "exit"
|
ASSERTNOTREACHED(); // machine->Run never returns;
|
||||||
|
// the address space exits
|
||||||
|
// by doing the syscall "exit"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -301,31 +274,30 @@ AddrSpace::Execute(char* fileName)
|
|||||||
// will be saved/restored into the currentThread->userRegisters
|
// will be saved/restored into the currentThread->userRegisters
|
||||||
// when this thread is context switched out.
|
// when this thread is context switched out.
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void
|
||||||
AddrSpace::InitRegisters()
|
AddrSpace::InitRegisters()
|
||||||
{
|
{
|
||||||
Machine *machine = kernel->machine;
|
Machine* machine = kernel->machine;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < NumTotalRegs; i++)
|
for (i = 0; i < NumTotalRegs; i++)
|
||||||
machine->WriteRegister(i, 0);
|
machine->WriteRegister(i, 0);
|
||||||
|
|
||||||
// Initial program counter -- must be location of "Start", which
|
// Initial program counter -- must be location of "Start", which
|
||||||
// is assumed to be virtual address zero
|
// is assumed to be virtual address zero
|
||||||
machine->WriteRegister(PCReg, 0);
|
machine->WriteRegister(PCReg, 0);
|
||||||
|
|
||||||
// Need to also tell MIPS where next instruction is, because
|
// Need to also tell MIPS where next instruction is, because
|
||||||
// of branch delay possibility
|
// of branch delay possibility
|
||||||
// Since instructions occupy four bytes each, the next instruction
|
// Since instructions occupy four bytes each, the next instruction
|
||||||
// after start will be at virtual address four.
|
// after start will be at virtual address four.
|
||||||
machine->WriteRegister(NextPCReg, 4);
|
machine->WriteRegister(NextPCReg, 4);
|
||||||
|
|
||||||
// Set the stack register to the end of the address space, where we
|
// Set the stack register to the end of the address space, where we
|
||||||
// allocated the stack; but subtract off a bit, to make sure we don't
|
// allocated the stack; but subtract off a bit, to make sure we don't
|
||||||
// accidentally reference off the end!
|
// accidentally reference off the end!
|
||||||
machine->WriteRegister(StackReg, numPages * PageSize - 16);
|
machine->WriteRegister(StackReg, numPages * PageSize - 16);
|
||||||
DEBUG(dbgAddr, "Initializing stack pointer: " << numPages * PageSize - 16);
|
DEBUG(dbgAddr, "Initializing stack pointer: " << numPages * PageSize - 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -335,9 +307,9 @@ AddrSpace::InitRegisters()
|
|||||||
//
|
//
|
||||||
// For now, don't need to save anything!
|
// For now, don't need to save anything!
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
void AddrSpace::SaveState()
|
||||||
void AddrSpace::SaveState()
|
{
|
||||||
{}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// AddrSpace::RestoreState
|
// AddrSpace::RestoreState
|
||||||
@@ -346,11 +318,10 @@ void AddrSpace::SaveState()
|
|||||||
//
|
//
|
||||||
// For now, tell the machine where to find the page table.
|
// For now, tell the machine where to find the page table.
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
void AddrSpace::RestoreState()
|
||||||
void AddrSpace::RestoreState()
|
|
||||||
{
|
{
|
||||||
kernel->machine->pageTable = pageTable;
|
kernel->machine->pageTable = pageTable;
|
||||||
kernel->machine->pageTableSize = numPages;
|
kernel->machine->pageTableSize = numPages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -363,50 +334,84 @@ void AddrSpace::RestoreState()
|
|||||||
// Return any exceptions caused by the address translation.
|
// Return any exceptions caused by the address translation.
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
ExceptionType
|
ExceptionType
|
||||||
AddrSpace::Translate(unsigned int vaddr, unsigned int *paddr, int isReadWrite)
|
AddrSpace::Translate(unsigned int vaddr, unsigned int* paddr, int isReadWrite)
|
||||||
{
|
{
|
||||||
TranslationEntry *pte;
|
TranslationEntry* pte;
|
||||||
int pfn;
|
int pfn;
|
||||||
unsigned int vpn = vaddr / PageSize;
|
unsigned int vpn = vaddr / PageSize;
|
||||||
unsigned int offset = vaddr % PageSize;
|
unsigned int offset = vaddr % PageSize;
|
||||||
|
|
||||||
if(vpn >= numPages) {
|
if (vpn >= numPages) {
|
||||||
return AddressErrorException;
|
return AddressErrorException;
|
||||||
}
|
|
||||||
|
|
||||||
pte = &pageTable[vpn];
|
|
||||||
|
|
||||||
if(isReadWrite && pte->readOnly) {
|
|
||||||
return ReadOnlyException;
|
|
||||||
}
|
|
||||||
|
|
||||||
pfn = pte->physicalPage;
|
|
||||||
if (pfn == -1) {
|
|
||||||
pfn = pte->physicalPage = kernel->frameTable->Allocate();
|
|
||||||
if (pfn == -1) {
|
|
||||||
DEBUG(dbgAddr, "Memory Limit exceeded");
|
|
||||||
return MemoryLimitException;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// if the pageFrame is too big, there is something really wrong!
|
pte = &pageTable[vpn];
|
||||||
// An invalid translation was loaded into the page table or TLB.
|
|
||||||
if (pfn >= NumPhysPages) {
|
|
||||||
DEBUG(dbgAddr, "Illegal physical page " << pfn);
|
|
||||||
return BusErrorException;
|
|
||||||
}
|
|
||||||
|
|
||||||
pte->use = TRUE; // set the use, dirty bits
|
if (isReadWrite && pte->readOnly) {
|
||||||
|
return ReadOnlyException;
|
||||||
|
}
|
||||||
|
|
||||||
if(isReadWrite)
|
pfn = pte->physicalPage;
|
||||||
pte->dirty = TRUE;
|
|
||||||
|
|
||||||
*paddr = pfn * PageSize + offset;
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT((*paddr < MemorySize));
|
pte->use = TRUE; // set the use, dirty bits
|
||||||
|
|
||||||
//cerr << " -- AddrSpace::Translate(): vaddr: " << vaddr <<
|
if (isReadWrite)
|
||||||
// ", paddr: " << *paddr << "\n";
|
pte->dirty = TRUE;
|
||||||
|
|
||||||
return NoException;
|
*paddr = pfn * PageSize + offset;
|
||||||
|
|
||||||
|
ASSERT((*paddr < MemorySize));
|
||||||
|
|
||||||
|
//cerr << " -- AddrSpace::Translate(): vaddr: " << vaddr <<
|
||||||
|
// ", paddr: " << *paddr << "\n";
|
||||||
|
|
||||||
|
return NoException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FrameTable::FrameTable() {
|
||||||
|
for (int i = 0; i < NumPhysPages; ++i)
|
||||||
|
available.Append(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameTable::~FrameTable() {}
|
||||||
|
|
||||||
|
uint FrameTable::RemainSize() { return available.NumInList(); }
|
||||||
|
|
||||||
|
PageTable FrameTable::Allocate(uint pageNum) {
|
||||||
|
// if not enough memory
|
||||||
|
if (RemainSize() < pageNum)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
PageTable ptb = new TranslationEntry[pageNum];
|
||||||
|
|
||||||
|
for (int i = 0; i < pageNum; ++i) {
|
||||||
|
ptb[i].virtualPage = i;
|
||||||
|
int f = available.RemoveFront(); // frame number
|
||||||
|
ptb[i].physicalPage = f;
|
||||||
|
// initialize flags
|
||||||
|
ptb[i].valid = TRUE;
|
||||||
|
ptb[i].use = FALSE;
|
||||||
|
ptb[i].dirty = FALSE;
|
||||||
|
ptb[i].readOnly = FALSE;
|
||||||
|
// zero out the entire address space
|
||||||
|
bzero(kernel->machine->mainMemory + f * PageSize, PageSize);
|
||||||
|
}
|
||||||
|
return ptb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameTable::Release(PageTable ptb, int pageNum) {
|
||||||
|
if (!ptb)
|
||||||
|
return; // nothing to release
|
||||||
|
for (int i = 0; i < pageNum; ++i)
|
||||||
|
available.Append(ptb[i].physicalPage);
|
||||||
|
delete[] ptb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,57 +18,84 @@
|
|||||||
|
|
||||||
#define UserStackSize 1024 // increase this as necessary!
|
#define UserStackSize 1024 // increase this as necessary!
|
||||||
|
|
||||||
class FrameTable {
|
|
||||||
public:
|
|
||||||
FrameTable();
|
|
||||||
~FrameTable();
|
|
||||||
|
|
||||||
int Allocate();
|
|
||||||
void Release(int phyPageNum);
|
|
||||||
size_t RemainSize();
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Node {
|
|
||||||
Node *next;
|
|
||||||
int idx;
|
|
||||||
Node(int idx = -1);
|
|
||||||
};
|
|
||||||
|
|
||||||
Node *begin, *end;
|
|
||||||
|
|
||||||
size_t available;
|
|
||||||
int *useCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AddrSpace {
|
class AddrSpace {
|
||||||
public:
|
public:
|
||||||
AddrSpace(); // Create an address space.
|
AddrSpace(); // Create an address space.
|
||||||
~AddrSpace(); // De-allocate an address space
|
~AddrSpace(); // De-allocate an address space
|
||||||
|
|
||||||
bool Load(char *fileName); // Load a program into addr space from
|
bool Load(char* fileName); // Load a program into addr space from
|
||||||
// a file
|
// a file
|
||||||
// return false if not found
|
// return false if not found
|
||||||
|
|
||||||
void Execute(char *fileName); // Run a program
|
void Execute(char* fileName); // Run a program
|
||||||
// assumes the program has already
|
// assumes the program has already
|
||||||
// been loaded
|
// been loaded
|
||||||
|
|
||||||
void SaveState(); // Save/restore address space-specific
|
void SaveState(); // Save/restore address space-specific
|
||||||
void RestoreState(); // info on a context switch
|
void RestoreState(); // info on a context switch
|
||||||
|
|
||||||
// Translate virtual address _vaddr_
|
// Translate virtual address _vaddr_
|
||||||
// to physical address _paddr_. _mode_
|
// to physical address _paddr_. _mode_
|
||||||
// is 0 for Read, 1 for Write.
|
// is 0 for Read, 1 for Write.
|
||||||
ExceptionType Translate(unsigned int vaddr, unsigned int *paddr, int mode);
|
ExceptionType Translate(unsigned int vaddr, unsigned int* paddr, int mode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TranslationEntry *pageTable;
|
TranslationEntry* pageTable; // Assume linear page table translation
|
||||||
unsigned int numPages; // Number of pages in the virtual
|
// for now!
|
||||||
// address space
|
unsigned int numPages; // Number of pages in the virtual
|
||||||
|
// address space
|
||||||
|
|
||||||
void InitRegisters(); // Initialize user-level CPU registers,
|
void InitRegisters(); // Initialize user-level CPU registers,
|
||||||
// before jumping to user code
|
// before jumping to user code
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ADDRSPACE_H
|
#endif // ADDRSPACE_H
|
||||||
|
|
||||||
|
#ifndef FRAME_TABLE_H
|
||||||
|
#define FRAME_TABLE_H
|
||||||
|
|
||||||
|
#include "machine.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data structure of Virtual Memory
|
||||||
|
*/
|
||||||
|
typedef TranslationEntry* PageTable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data structure of Physical Memory
|
||||||
|
*/
|
||||||
|
class FrameTable {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Initialize a frame table
|
||||||
|
*/
|
||||||
|
FrameTable();
|
||||||
|
~FrameTable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate pageNum of frames (pages) and collect
|
||||||
|
* corresponding translation information into a page table.
|
||||||
|
*
|
||||||
|
* @param pageNum numbers of pages
|
||||||
|
* @return a new Page table, NULL if not enough memory space
|
||||||
|
*/
|
||||||
|
PageTable Allocate(uint pageNum);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release the physical memory frame
|
||||||
|
* which the info stored in PageTable
|
||||||
|
*/
|
||||||
|
void Release(PageTable ptb, int pageNum);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the remaining numbers of entry of the frame table
|
||||||
|
*/
|
||||||
|
uint RemainSize();
|
||||||
|
|
||||||
|
private:
|
||||||
|
List<int> available;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FRAME_TABLE_H */
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// exception.cc
|
// exception.cc
|
||||||
// Entry point into the Nachos kernel from user programs.
|
// Entry point into the Nachos kernel from user programs.
|
||||||
// There are two kinds of things that can cause control to
|
// There are two kinds of things that can cause control to
|
||||||
// transfer back to here from user code:
|
// transfer back to here from user code:
|
||||||
//
|
//
|
||||||
// syscall -- The user code explicitly requests to call a procedure
|
// syscall -- The user code explicitly requests to call a procedure
|
||||||
// in the Nachos kernel. Right now, the only function we support is
|
// in the Nachos kernel. Right now, the only function we support is
|
||||||
// "Halt".
|
// "Halt".
|
||||||
//
|
//
|
||||||
// exceptions -- The user code does something that the CPU can't handle.
|
// exceptions -- The user code does something that the CPU can't handle.
|
||||||
// For instance, accessing memory that doesn't exist, arithmetic errors,
|
// For instance, accessing memory that doesn't exist, arithmetic errors,
|
||||||
// etc.
|
// etc.
|
||||||
//
|
//
|
||||||
// Interrupts (which can also cause control to transfer from user
|
// Interrupts (which can also cause control to transfer from user
|
||||||
// code into the Nachos kernel) are handled elsewhere.
|
// code into the Nachos kernel) are handled elsewhere.
|
||||||
//
|
//
|
||||||
// For now, this only handles the Halt() system call.
|
// For now, this only handles the Halt() system call.
|
||||||
// Everything else core dumps.
|
// Everything else core dumps.
|
||||||
@@ -27,192 +27,170 @@
|
|||||||
#include "ksyscall.h"
|
#include "ksyscall.h"
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// ExceptionHandler
|
// ExceptionHandler
|
||||||
// Entry point into the Nachos kernel. Called when a user program
|
// Entry point into the Nachos kernel. Called when a user program
|
||||||
// is executing, and either does a syscall, or generates an addressing
|
// is executing, and either does a syscall, or generates an addressing
|
||||||
// or arithmetic exception.
|
// or arithmetic exception.
|
||||||
//
|
//
|
||||||
// For system calls, the following is the calling convention:
|
// For system calls, the following is the calling convention:
|
||||||
//
|
//
|
||||||
// system call code -- r2
|
// system call code -- r2
|
||||||
// arg1 -- r4
|
// arg1 -- r4
|
||||||
// arg2 -- r5
|
// arg2 -- r5
|
||||||
// arg3 -- r6
|
// arg3 -- r6
|
||||||
// arg4 -- r7
|
// arg4 -- r7
|
||||||
//
|
//
|
||||||
// The result of the system call, if any, must be put back into r2.
|
// The result of the system call, if any, must be put back into r2.
|
||||||
//
|
//
|
||||||
// If you are handling a system call, don't forget to increment the pc
|
// If you are handling a system call, don't forget to increment the pc
|
||||||
// before returning. (Or else you'll loop making the same system call forever!)
|
// before returning. (Or else you'll loop making the same system call forever!)
|
||||||
//
|
//
|
||||||
// "which" is the kind of exception. The list of possible exceptions
|
// "which" is the kind of exception. The list of possible exceptions
|
||||||
// is in machine.h.
|
// is in machine.h.
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void
|
||||||
ExceptionHandler(ExceptionType which)
|
ExceptionHandler(ExceptionType which)
|
||||||
{
|
{
|
||||||
int type = kernel->machine->ReadRegister(2);
|
int type = kernel->machine->ReadRegister(2);
|
||||||
int val;
|
int val;
|
||||||
int status, exit, threadID, programID;
|
int status, exit, threadID, programID;
|
||||||
DEBUG(dbgSys, "Received Exception " << which << " type: " << type << "\n");
|
int fd, size;
|
||||||
switch (which) {
|
DEBUG(dbgSys, "Received Exception " << which << " type: " << type << "\n");
|
||||||
case SyscallException:
|
switch (which) {
|
||||||
switch(type) {
|
case SyscallException:
|
||||||
case SC_Halt:
|
switch (type) {
|
||||||
DEBUG(dbgSys, "Shutdown, initiated by user program.\n");
|
case SC_Halt:
|
||||||
SysHalt();
|
DEBUG(dbgSys, "Shutdown, initiated by user program.\n");
|
||||||
cout<<"in exception\n";
|
SysHalt();
|
||||||
ASSERTNOTREACHED();
|
cout << "in exception\n";
|
||||||
break;
|
ASSERTNOTREACHED();
|
||||||
case SC_MSG:
|
break;
|
||||||
DEBUG(dbgSys, "Message received.\n");
|
case SC_MSG:
|
||||||
val = kernel->machine->ReadRegister(4);
|
DEBUG(dbgSys, "Message received.\n");
|
||||||
{
|
val = kernel->machine->ReadRegister(4);
|
||||||
char *msg = &(kernel->machine->mainMemory[val]);
|
{
|
||||||
cout << msg << endl;
|
char* msg = &(kernel->machine->mainMemory[val]);
|
||||||
}
|
cout << msg << endl;
|
||||||
SysHalt();
|
}
|
||||||
ASSERTNOTREACHED();
|
SysHalt();
|
||||||
break;
|
ASSERTNOTREACHED();
|
||||||
case SC_Create:
|
break;
|
||||||
val = kernel->machine->ReadRegister(4);
|
case SC_PrintInt:
|
||||||
{
|
val = kernel->machine->ReadRegister(4);
|
||||||
char *filename = &(kernel->machine->mainMemory[val]);
|
SysPrintInt(val);
|
||||||
//cout << filename << endl;
|
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
|
||||||
status = SysCreate(filename);
|
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
||||||
kernel->machine->WriteRegister(2, (int) status);
|
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
||||||
}
|
return;
|
||||||
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
|
case SC_Create:
|
||||||
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
val = kernel->machine->ReadRegister(4);
|
||||||
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
{
|
||||||
return;
|
char* filename = &(kernel->machine->mainMemory[val]);
|
||||||
ASSERTNOTREACHED();
|
//cout << filename << endl;
|
||||||
break;
|
status = SysCreate(filename);
|
||||||
case SC_Add:
|
kernel->machine->WriteRegister(2, (int)status);
|
||||||
DEBUG(dbgSys, "Add " << kernel->machine->ReadRegister(4) << " + " << kernel->machine->ReadRegister(5) << "\n");
|
}
|
||||||
/* Process SysAdd Systemcall*/
|
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
|
||||||
int result;
|
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
||||||
result = SysAdd(/* int op1 */(int)kernel->machine->ReadRegister(4),
|
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
||||||
/* int op2 */(int)kernel->machine->ReadRegister(5));
|
return;
|
||||||
DEBUG(dbgSys, "Add returning with " << result << "\n");
|
ASSERTNOTREACHED();
|
||||||
/* Prepare Result */
|
break;
|
||||||
kernel->machine->WriteRegister(2, (int)result);
|
case SC_Open:
|
||||||
/* Modify return point */
|
val = kernel->machine->ReadRegister(4);
|
||||||
{
|
{
|
||||||
/* set previous programm counter (debugging only)*/
|
char* filename = &(kernel->machine->mainMemory[val]);
|
||||||
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
|
//cout << filename << endl;
|
||||||
|
fd = SysOpen(filename);
|
||||||
/* set programm counter to next instruction (all Instructions are 4 byte wide)*/
|
kernel->machine->WriteRegister(2, (int)fd);
|
||||||
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
}
|
||||||
|
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
|
||||||
/* set next programm counter for brach execution */
|
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
||||||
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
||||||
}
|
return;
|
||||||
cout << "result is " << result << "\n";
|
ASSERTNOTREACHED();
|
||||||
return;
|
break;
|
||||||
ASSERTNOTREACHED();
|
case SC_Write:
|
||||||
break;
|
val = kernel->machine->ReadRegister(4);
|
||||||
case SC_Exit:
|
size = kernel->machine->ReadRegister(5);
|
||||||
DEBUG(dbgAddr, "Program exit\n");
|
fd = kernel->machine->ReadRegister(6);
|
||||||
val = kernel->machine->ReadRegister(4);
|
{
|
||||||
cout << "return value:" << val << endl;
|
char* buffer = &(kernel->machine->mainMemory[val]);
|
||||||
kernel->currentThread->Finish();
|
size = SysWrite(buffer, size, fd);
|
||||||
break;
|
kernel->machine->WriteRegister(2, (int)size);
|
||||||
case SC_PrintInt:
|
}
|
||||||
DEBUG(dbgAddr, "Printing int\n");
|
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
|
||||||
val = (int)kernel->machine->ReadRegister(4);
|
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
||||||
SysPrintInt(val);
|
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
||||||
|
return;
|
||||||
|
ASSERTNOTREACHED();
|
||||||
|
break;
|
||||||
|
case SC_Close:
|
||||||
|
fd = kernel->machine->ReadRegister(4);
|
||||||
|
{
|
||||||
|
val = SysClose(fd);
|
||||||
|
kernel->machine->WriteRegister(2, (int)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_Read:
|
||||||
|
val = kernel->machine->ReadRegister(4);
|
||||||
|
size = kernel->machine->ReadRegister(5);
|
||||||
|
fd = kernel->machine->ReadRegister(6);
|
||||||
|
{
|
||||||
|
char* buffer = &(kernel->machine->mainMemory[val]);
|
||||||
|
size = SysRead(buffer, size, fd);
|
||||||
|
kernel->machine->WriteRegister(2, (int)size);
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
|
||||||
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);
|
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");
|
|
||||||
|
|
||||||
{
|
/* set next programm counter for brach execution */
|
||||||
val = kernel->machine->ReadRegister(4);
|
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
||||||
char *name = &(kernel->machine->mainMemory[val]);
|
}
|
||||||
OpenFileId ret = SysOpen(name);
|
cout << "result is " << result << "\n";
|
||||||
kernel->machine->WriteRegister(2, ret);
|
return;
|
||||||
}
|
ASSERTNOTREACHED();
|
||||||
|
break;
|
||||||
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
|
case SC_Exit:
|
||||||
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
DEBUG(dbgAddr, "Program exit\n");
|
||||||
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
|
val = kernel->machine->ReadRegister(4);
|
||||||
|
cout << "return value:" << val << endl;
|
||||||
return;
|
kernel->currentThread->Finish();
|
||||||
ASSERTNOTREACHED();
|
break;
|
||||||
break;
|
default:
|
||||||
case SC_Read:
|
cerr << "Unexpected system call " << type << "\n";
|
||||||
DEBUG(dbgAddr, "Read file\n");
|
break;
|
||||||
|
}
|
||||||
{
|
break;
|
||||||
val = kernel->machine->ReadRegister(4);
|
default:
|
||||||
char *buffer = &(kernel->machine->mainMemory[val]);
|
cerr << "Unexpected user mode exception " << (int)which << "\n";
|
||||||
int size = kernel->machine->ReadRegister(5);
|
break;
|
||||||
OpenFileId id = (OpenFileId)kernel->machine->ReadRegister(6);
|
}
|
||||||
int ret = SysRead(buffer, size, id);
|
ASSERTNOTREACHED();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
11
code/userprog/hw4_consoleIO_1.c
Normal file
11
code/userprog/hw4_consoleIO_1.c
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#include "syscall.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
for (n = 0; n < 4; n++) {
|
||||||
|
PrintInt(1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
11
code/userprog/hw4_consoleIO_2.c
Normal file
11
code/userprog/hw4_consoleIO_2.c
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#include "syscall.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
for (n = 0; n < 5; n++) {
|
||||||
|
PrintInt(2);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
12
code/userprog/hw4_consoleIO_3.c
Normal file
12
code/userprog/hw4_consoleIO_3.c
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#include "syscall.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for (n = 0; n < 12; n++) {
|
||||||
|
PrintInt(3);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
12
code/userprog/hw4_consoleIO_4.c
Normal file
12
code/userprog/hw4_consoleIO_4.c
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#include "syscall.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for (n = 0; n < 11; n++) {
|
||||||
|
PrintInt(4);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,78 +1,71 @@
|
|||||||
/**************************************************************
|
/**************************************************************
|
||||||
*
|
*
|
||||||
* userprog/ksyscall.h
|
* userprog/ksyscall.h
|
||||||
*
|
*
|
||||||
* Kernel interface for systemcalls
|
* Kernel interface for systemcalls
|
||||||
*
|
*
|
||||||
* by Marcus Voelp (c) Universitaet Karlsruhe
|
* by Marcus Voelp (c) Universitaet Karlsruhe
|
||||||
*
|
*
|
||||||
**************************************************************/
|
**************************************************************/
|
||||||
|
|
||||||
#ifndef __USERPROG_KSYSCALL_H__
|
#ifndef __USERPROG_KSYSCALL_H__
|
||||||
#define __USERPROG_KSYSCALL_H__
|
#define __USERPROG_KSYSCALL_H__
|
||||||
|
|
||||||
#define INT_BUF_LENGTH 13
|
#include "kernel.h"
|
||||||
|
|
||||||
#include "kernel.h"
|
#include "synchconsole.h"
|
||||||
|
|
||||||
#include "synchconsole.h"
|
typedef int OpenFileId;
|
||||||
|
|
||||||
|
void SysHalt()
|
||||||
void SysHalt()
|
{
|
||||||
{
|
kernel->interrupt->Halt();
|
||||||
kernel->interrupt->Halt();
|
}
|
||||||
}
|
|
||||||
|
int SysAdd(int op1, int op2)
|
||||||
int SysAdd(int op1, int op2)
|
{
|
||||||
{
|
return op1 + op2;
|
||||||
return op1 + op2;
|
}
|
||||||
}
|
|
||||||
|
int SysCreate(char* filename)
|
||||||
int SysCreate(char *filename)
|
{
|
||||||
{
|
// return value
|
||||||
// return value
|
// 1: success
|
||||||
// 1: success
|
// 0: failed
|
||||||
// 0: failed
|
return kernel->interrupt->CreateFile(filename);
|
||||||
return kernel->interrupt->CreateFile(filename);
|
}
|
||||||
}
|
|
||||||
|
void SysPrintInt(int value)
|
||||||
void SysPrintInt(int value) {
|
{
|
||||||
kernel->interrupt->PrintInt(value);
|
kernel->interrupt->PrintInt(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenFileId SysOpen(char *name) {
|
// -1: open fail
|
||||||
OpenFileId id = -1;
|
// fd
|
||||||
for (int i = 0; i < 20; i++)
|
OpenFileId SysOpen(char* filename)
|
||||||
if (kernel->fileSystem->fileDescriptorTable[i] == NULL) {
|
{
|
||||||
id = i;
|
return kernel->interrupt->OpenFile(filename);
|
||||||
kernel->fileSystem->fileDescriptorTable[i]
|
}
|
||||||
= kernel->fileSystem->Open(name);
|
|
||||||
if (kernel->fileSystem->fileDescriptorTable[i] == NULL)
|
// -1: write fail
|
||||||
return -1;
|
// size
|
||||||
break;
|
int SysWrite(char* buffer, int size, OpenFileId fd)
|
||||||
}
|
{
|
||||||
return id;
|
return kernel->interrupt->WriteFile(buffer, size, fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SysWrite(char *buffer, int size, OpenFileId id) {
|
// 1: close success
|
||||||
if (id < 0 || id >= 20 || kernel->fileSystem->fileDescriptorTable[id] == NULL)
|
// 0: close fail
|
||||||
return -1;
|
int SysClose(OpenFileId fd)
|
||||||
return kernel->fileSystem->fileDescriptorTable[id]->Write(buffer, size);
|
{
|
||||||
}
|
return kernel->interrupt->CloseFile(fd);
|
||||||
|
}
|
||||||
int SysRead(char *buffer, int size, OpenFileId id) {
|
|
||||||
if (id < 0 || id >= 20 || kernel->fileSystem->fileDescriptorTable[id] == NULL)
|
// -1: read fail
|
||||||
return -1;
|
// size
|
||||||
return kernel->fileSystem->fileDescriptorTable[id]->Read(buffer, size);
|
int SysRead(char* buffer, int size, OpenFileId fd)
|
||||||
}
|
{
|
||||||
|
return kernel->interrupt->ReadFile(buffer, size, fd);
|
||||||
int SysClose(OpenFileId id) {
|
}
|
||||||
if (id < 0 || id >= 20 || kernel->fileSystem->fileDescriptorTable[id] == NULL)
|
|
||||||
return 0;
|
#endif /* ! __USERPROG_KSYSCALL_H__ */
|
||||||
delete kernel->fileSystem->fileDescriptorTable[id];
|
|
||||||
kernel->fileSystem->fileDescriptorTable[id] = NULL;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* ! __USERPROG_KSYSCALL_H__ */
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* noff.h
|
/* noff.h
|
||||||
* Data structures defining the Nachos Object Code Format
|
* Data structures defining the Nachos Object Code Format
|
||||||
*
|
*
|
||||||
* Basically, we only know about three types of segments:
|
* Basically, we only know about three types of segments:
|
||||||
@@ -6,23 +6,22 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define NOFFMAGIC 0xbadfad /* magic number denoting Nachos
|
#define NOFFMAGIC 0xbadfad /* magic number denoting Nachos
|
||||||
* object code file
|
/* object code file*/
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct segment {
|
typedef struct segment {
|
||||||
int virtualAddr; /* location of segment in virt addr space */
|
int virtualAddr; /* location of segment in virt addr space */
|
||||||
int inFileAddr; /* location of segment in this file */
|
int inFileAddr; /* location of segment in this file */
|
||||||
int size; /* size of segment */
|
int size; /* size of segment */
|
||||||
} Segment;
|
} Segment;
|
||||||
|
|
||||||
typedef struct noffHeader {
|
typedef struct noffHeader {
|
||||||
int noffMagic; /* should be NOFFMAGIC */
|
int noffMagic; /* should be NOFFMAGIC */
|
||||||
Segment code; /* executable code segment */
|
Segment code; /* executable code segment */
|
||||||
Segment initData; /* initialized data segment */
|
Segment initData; /* initialized data segment */
|
||||||
#ifdef RDATA
|
#ifdef RDATA
|
||||||
Segment readonlyData; /* read only data */
|
Segment readonlyData; /* read only data */
|
||||||
#endif
|
#endif
|
||||||
Segment uninitData; /* uninitialized data segment --
|
Segment uninitData; /* uninitialized data segment --
|
||||||
* should be zero'ed before use
|
* should be zero'ed before use
|
||||||
*/
|
*/
|
||||||
} NoffHeader;
|
} NoffHeader;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
// otherwise, read from this file
|
// otherwise, read from this file
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
SynchConsoleInput::SynchConsoleInput(char *inputFile)
|
SynchConsoleInput::SynchConsoleInput(char* inputFile)
|
||||||
{
|
{
|
||||||
consoleInput = new ConsoleInput(inputFile, this);
|
consoleInput = new ConsoleInput(inputFile, this);
|
||||||
lock = new Lock("console in");
|
lock = new Lock("console in");
|
||||||
@@ -30,9 +30,9 @@ SynchConsoleInput::SynchConsoleInput(char *inputFile)
|
|||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
SynchConsoleInput::~SynchConsoleInput()
|
SynchConsoleInput::~SynchConsoleInput()
|
||||||
{
|
{
|
||||||
delete consoleInput;
|
delete consoleInput;
|
||||||
delete lock;
|
delete lock;
|
||||||
delete waitFor;
|
delete waitFor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ SynchConsoleInput::CallBack()
|
|||||||
// otherwise, read from this file
|
// otherwise, read from this file
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
SynchConsoleOutput::SynchConsoleOutput(char *outputFile)
|
SynchConsoleOutput::SynchConsoleOutput(char* outputFile)
|
||||||
{
|
{
|
||||||
consoleOutput = new ConsoleOutput(outputFile, this);
|
consoleOutput = new ConsoleOutput(outputFile, this);
|
||||||
lock = new Lock("console out");
|
lock = new Lock("console out");
|
||||||
@@ -86,9 +86,9 @@ SynchConsoleOutput::SynchConsoleOutput(char *outputFile)
|
|||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
SynchConsoleOutput::~SynchConsoleOutput()
|
SynchConsoleOutput::~SynchConsoleOutput()
|
||||||
{
|
{
|
||||||
delete consoleOutput;
|
delete consoleOutput;
|
||||||
delete lock;
|
delete lock;
|
||||||
delete waitFor;
|
delete waitFor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,13 +106,18 @@ SynchConsoleOutput::PutChar(char ch)
|
|||||||
lock->Release();
|
lock->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// SynchConsoleOutput::PutInt
|
||||||
|
// Write a int to the console display, waiting if necessary.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void
|
||||||
SynchConsoleOutput::PutInt(int value)
|
SynchConsoleOutput::PutInt(int value)
|
||||||
{
|
{
|
||||||
lock->Acquire();
|
lock->Acquire();
|
||||||
consoleOutput->PutInt(value);
|
consoleOutput->PutInt(value);
|
||||||
waitFor->P();
|
waitFor->P();
|
||||||
lock->Release();
|
lock->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|||||||
@@ -21,34 +21,34 @@
|
|||||||
// a console device
|
// a console device
|
||||||
|
|
||||||
class SynchConsoleInput : public CallBackObj {
|
class SynchConsoleInput : public CallBackObj {
|
||||||
public:
|
public:
|
||||||
SynchConsoleInput(char *inputFile); // Initialize the console device
|
SynchConsoleInput(char* inputFile); // Initialize the console device
|
||||||
~SynchConsoleInput(); // Deallocate console device
|
~SynchConsoleInput(); // Deallocate console device
|
||||||
|
|
||||||
char GetChar(); // Read a character, waiting if necessary
|
char GetChar(); // Read a character, waiting if necessary
|
||||||
|
|
||||||
private:
|
|
||||||
ConsoleInput *consoleInput; // the hardware keyboard
|
|
||||||
Lock *lock; // only one reader at a time
|
|
||||||
Semaphore *waitFor; // wait for callBack
|
|
||||||
|
|
||||||
void CallBack(); // called when a keystroke is available
|
private:
|
||||||
|
ConsoleInput* consoleInput; // the hardware keyboard
|
||||||
|
Lock* lock; // only one reader at a time
|
||||||
|
Semaphore* waitFor; // wait for callBack
|
||||||
|
|
||||||
|
void CallBack(); // called when a keystroke is available
|
||||||
};
|
};
|
||||||
|
|
||||||
class SynchConsoleOutput : public CallBackObj {
|
class SynchConsoleOutput : public CallBackObj {
|
||||||
public:
|
public:
|
||||||
SynchConsoleOutput(char *outputFile); // Initialize the console device
|
SynchConsoleOutput(char* outputFile); // Initialize the console device
|
||||||
~SynchConsoleOutput();
|
~SynchConsoleOutput();
|
||||||
|
|
||||||
void PutChar(char ch); // Write a character, waiting if necessary
|
void PutChar(char ch); // Write a character, waiting if necessary
|
||||||
void PutInt(int value);
|
void PutInt(int value);
|
||||||
|
|
||||||
private:
|
|
||||||
ConsoleOutput *consoleOutput;// the hardware display
|
|
||||||
Lock *lock; // only one writer at a time
|
|
||||||
Semaphore *waitFor; // wait for callBack
|
|
||||||
|
|
||||||
void CallBack(); // called when more data can be written
|
private:
|
||||||
|
ConsoleOutput* consoleOutput;// the hardware display
|
||||||
|
Lock* lock; // only one writer at a time
|
||||||
|
Semaphore* waitFor; // wait for callBack
|
||||||
|
|
||||||
|
void CallBack(); // called when more data can be written
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SYNCHCONSOLE_H
|
#endif // SYNCHCONSOLE_H
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
/* syscalls.h
|
/* syscalls.h
|
||||||
* Nachos system call interface. These are Nachos kernel operations
|
* Nachos system call interface. These are Nachos kernel operations
|
||||||
* that can be invoked from user programs, by trapping to the kernel
|
* that can be invoked from user programs, by trapping to the kernel
|
||||||
* via the "syscall" instruction.
|
* via the "syscall" instruction.
|
||||||
*
|
*
|
||||||
* This file is included by user programs and by the Nachos kernel.
|
* This file is included by user programs and by the Nachos kernel.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1992-1993 The Regents of the University of California.
|
* Copyright (c) 1992-1993 The Regents of the University of California.
|
||||||
* All rights reserved. See copyright.h for copyright notice and limitation
|
* All rights reserved. See copyright.h for copyright notice and limitation
|
||||||
* of liability and disclaimer of warranty provisions.
|
* of liability and disclaimer of warranty provisions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -15,83 +15,86 @@
|
|||||||
|
|
||||||
#include "copyright.h"
|
#include "copyright.h"
|
||||||
#include "errno.h"
|
#include "errno.h"
|
||||||
/* system call codes -- used by the stubs to tell the kernel which system call
|
/* system call codes -- used by the stubs to tell the kernel which system call
|
||||||
* is being asked for
|
* is being asked for
|
||||||
*/
|
*/
|
||||||
#define SC_Halt 0
|
#define SC_Halt 0
|
||||||
#define SC_Exit 1
|
#define SC_Exit 1
|
||||||
#define SC_Exec 2
|
#define SC_Exec 2
|
||||||
#define SC_Join 3
|
#define SC_Join 3
|
||||||
#define SC_Create 4
|
#define SC_Create 4
|
||||||
#define SC_Remove 5
|
#define SC_Remove 5
|
||||||
#define SC_Open 6
|
#define SC_Open 6
|
||||||
#define SC_Read 7
|
#define SC_Read 7
|
||||||
#define SC_Write 8
|
#define SC_Write 8
|
||||||
#define SC_Seek 9
|
#define SC_Seek 9
|
||||||
#define SC_Close 10
|
#define SC_Close 10
|
||||||
#define SC_ThreadFork 11
|
#define SC_ThreadFork 11
|
||||||
#define SC_ThreadYield 12
|
#define SC_ThreadYield 12
|
||||||
#define SC_ExecV 13
|
#define SC_ExecV 13
|
||||||
#define SC_ThreadExit 14
|
#define SC_ThreadExit 14
|
||||||
#define SC_ThreadJoin 15
|
#define SC_ThreadJoin 15
|
||||||
|
#define SC_Add 42
|
||||||
#define SC_PrintInt 16
|
#define SC_MSG 100
|
||||||
|
#define SC_PrintInt 16
|
||||||
#define SC_Add 42
|
|
||||||
#define SC_MSG 100
|
|
||||||
|
|
||||||
#ifndef IN_ASM
|
#ifndef IN_ASM
|
||||||
|
|
||||||
/* The system call interface. These are the operations the Nachos
|
/* The system call interface. These are the operations the Nachos
|
||||||
* kernel needs to support, to be able to run user programs.
|
* kernel needs to support, to be able to run user programs.
|
||||||
*
|
*
|
||||||
* Each of these is invoked by a user program by simply calling the
|
* Each of these is invoked by a user program by simply calling the
|
||||||
* procedure; an assembly language stub stuffs the system call code
|
* procedure; an assembly language stub stuffs the system call code
|
||||||
* into a register, and traps to the kernel. The kernel procedures
|
* into a register, and traps to the kernel. The kernel procedures
|
||||||
* are then invoked in the Nachos kernel, after appropriate error checking,
|
* are then invoked in the Nachos kernel, after appropriate error checking,
|
||||||
* from the system call entry point in exception.cc.
|
* from the system call entry point in exception.cc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Stop Nachos, and print out performance stats */
|
||||||
|
void Halt();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show the int value on console
|
||||||
|
*/
|
||||||
|
void PrintInt(int value);
|
||||||
|
|
||||||
/* Stop Nachos, and print out performance stats */
|
|
||||||
void Halt();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add the two operants and return the result
|
* Add the two operants and return the result
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int Add(int op1, int op2);
|
int Add(int op1, int op2);
|
||||||
/*
|
/*
|
||||||
* Just for simply showing message, not a safe way for console IO
|
* Just for simply showing message, not a safe way for console IO
|
||||||
*/
|
*/
|
||||||
void MSG(char *msg);
|
void MSG(char* msg);
|
||||||
|
|
||||||
/* Address space control operations: Exit, Exec, Execv, and Join */
|
/* Address space control operations: Exit, Exec, Execv, and Join */
|
||||||
|
|
||||||
/* This user program is done (status = 0 means exited normally). */
|
/* This user program is done (status = 0 means exited normally). */
|
||||||
void Exit(int status);
|
void Exit(int status);
|
||||||
|
|
||||||
/* A unique identifier for an executing user program (address space) */
|
/* A unique identifier for an executing user program (address space) */
|
||||||
typedef int SpaceId;
|
typedef int SpaceId;
|
||||||
|
|
||||||
/* A unique identifier for a thread within a task */
|
/* A unique identifier for a thread within a task */
|
||||||
typedef int ThreadId;
|
typedef int ThreadId;
|
||||||
|
|
||||||
/* Run the specified executable, with no args */
|
/* Run the specified executable, with no args */
|
||||||
/* This can be implemented as a call to ExecV.
|
/* This can be implemented as a call to ExecV.
|
||||||
*/
|
*/
|
||||||
SpaceId Exec(char* exec_name);
|
SpaceId Exec(char* exec_name);
|
||||||
|
|
||||||
/* Run the executable, stored in the Nachos file "argv[0]", with
|
/* Run the executable, stored in the Nachos file "argv[0]", with
|
||||||
* parameters stored in argv[1..argc-1] and return the
|
* parameters stored in argv[1..argc-1] and return the
|
||||||
* address space identifier
|
* address space identifier
|
||||||
*/
|
*/
|
||||||
SpaceId ExecV(int argc, char* argv[]);
|
SpaceId ExecV(int argc, char* argv[]);
|
||||||
|
|
||||||
/* Only return once the user program "id" has finished.
|
/* Only return once the user program "id" has finished.
|
||||||
* Return the exit status.
|
* Return the exit status.
|
||||||
*/
|
*/
|
||||||
int Join(SpaceId id);
|
int Join(SpaceId id);
|
||||||
|
|
||||||
|
|
||||||
/* File system operations: Create, Remove, Open, Read, Write, Close
|
/* File system operations: Create, Remove, Open, Read, Write, Close
|
||||||
* These functions are patterned after UNIX -- files represent
|
* These functions are patterned after UNIX -- files represent
|
||||||
@@ -101,45 +104,45 @@ int Join(SpaceId id);
|
|||||||
* can be used to support these system calls if the regular Nachos
|
* can be used to support these system calls if the regular Nachos
|
||||||
* file system has not been implemented.
|
* file system has not been implemented.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* A unique identifier for an open Nachos file. */
|
|
||||||
typedef int OpenFileId;
|
|
||||||
|
|
||||||
/* when an address space starts up, it has two open files, representing
|
/* A unique identifier for an open Nachos file. */
|
||||||
|
typedef int OpenFileId;
|
||||||
|
|
||||||
|
/* when an address space starts up, it has two open files, representing
|
||||||
* keyboard input and display output (in UNIX terms, stdin and stdout).
|
* keyboard input and display output (in UNIX terms, stdin and stdout).
|
||||||
* Read and Write can be used directly on these, without first opening
|
* Read and Write can be used directly on these, without first opening
|
||||||
* the console device.
|
* the console device.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SysConsoleInput 0
|
#define SysConsoleInput 0
|
||||||
#define SysConsoleOutput 1
|
#define SysConsoleOutput 1
|
||||||
|
|
||||||
/* Create a Nachos file, with name "name" */
|
/* Create a Nachos file, with name "name" */
|
||||||
/* Note: Create does not open the file. */
|
/* Note: Create does not open the file. */
|
||||||
/* Return 1 on success, negative error code on failure */
|
/* Return 1 on success, negative error code on failure */
|
||||||
int Create(char *name);
|
int Create(char* name);
|
||||||
|
|
||||||
/* Remove a Nachos file, with name "name" */
|
/* Remove a Nachos file, with name "name" */
|
||||||
int Remove(char *name);
|
int Remove(char* name);
|
||||||
|
|
||||||
/* Open the Nachos file "name", and return an "OpenFileId" that can
|
/* Open the Nachos file "name", and return an "OpenFileId" that can
|
||||||
* be used to read and write to the file.
|
* be used to read and write to the file.
|
||||||
*/
|
*/
|
||||||
OpenFileId Open(char *name);
|
OpenFileId Open(char* name);
|
||||||
|
|
||||||
/* Write "size" bytes from "buffer" to the open file.
|
/* Write "size" bytes from "buffer" to the open file.
|
||||||
* Return the number of bytes actually read on success.
|
* Return the number of bytes actually read on success.
|
||||||
* On failure, a negative error code is returned.
|
* On failure, a negative error code is returned.
|
||||||
*/
|
*/
|
||||||
int Write(char *buffer, int size, OpenFileId id);
|
int Write(char* buffer, int size, OpenFileId id);
|
||||||
|
|
||||||
/* Read "size" bytes from the open file into "buffer".
|
/* Read "size" bytes from the open file into "buffer".
|
||||||
* Return the number of bytes actually read -- if the open file isn't
|
* Return the number of bytes actually read -- if the open file isn't
|
||||||
* long enough, or if it is an I/O device, and there aren't enough
|
* long enough, or if it is an I/O device, and there aren't enough
|
||||||
* characters to read, return whatever is available (for I/O devices,
|
* characters to read, return whatever is available (for I/O devices,
|
||||||
* you should always wait until you can return at least one character).
|
* you should always wait until you can return at least one character).
|
||||||
*/
|
*/
|
||||||
int Read(char *buffer, int size, OpenFileId id);
|
int Read(char* buffer, int size, OpenFileId id);
|
||||||
|
|
||||||
/* Set the seek position of the open file "id"
|
/* Set the seek position of the open file "id"
|
||||||
* to the byte "position".
|
* to the byte "position".
|
||||||
@@ -153,21 +156,21 @@ int Close(OpenFileId id);
|
|||||||
|
|
||||||
|
|
||||||
/* User-level thread operations: Fork and Yield. To allow multiple
|
/* User-level thread operations: Fork and Yield. To allow multiple
|
||||||
* threads to run within a user program.
|
* threads to run within a user program.
|
||||||
*
|
*
|
||||||
* Could define other operations, such as LockAcquire, LockRelease, etc.
|
* Could define other operations, such as LockAcquire, LockRelease, etc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Fork a thread to run a procedure ("func") in the *same* address space
|
/* Fork a thread to run a procedure ("func") in the *same* address space
|
||||||
* as the current thread.
|
* as the current thread.
|
||||||
* Return a positive ThreadId on success, negative error code on failure
|
* Return a positive ThreadId on success, negative error code on failure
|
||||||
*/
|
*/
|
||||||
ThreadId ThreadFork(void (*func)());
|
ThreadId ThreadFork(void (*func)());
|
||||||
|
|
||||||
/* Yield the CPU to another runnable thread, whether in this address space
|
/* Yield the CPU to another runnable thread, whether in this address space
|
||||||
* or not.
|
* or not.
|
||||||
*/
|
*/
|
||||||
void ThreadYield();
|
void ThreadYield();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Blocks current thread until lokal thread ThreadID exits with ThreadExit.
|
* Blocks current thread until lokal thread ThreadID exits with ThreadExit.
|
||||||
@@ -180,8 +183,6 @@ int ThreadJoin(ThreadId id);
|
|||||||
*/
|
*/
|
||||||
void ThreadExit(int ExitCode);
|
void ThreadExit(int ExitCode);
|
||||||
|
|
||||||
void PrintInt(int number);
|
|
||||||
|
|
||||||
#endif /* IN_ASM */
|
#endif /* IN_ASM */
|
||||||
|
|
||||||
#endif /* SYSCALL_H */
|
#endif /* SYSCALL_H */
|
||||||
|
|||||||
@@ -2,6 +2,6 @@
|
|||||||
services:
|
services:
|
||||||
test:
|
test:
|
||||||
build: .
|
build: .
|
||||||
user: '60139:60139'
|
user: ytshih
|
||||||
volumes:
|
volumes:
|
||||||
- './:/work'
|
- './:/work'
|
||||||
|
|||||||
Reference in New Issue
Block a user