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