This commit is contained in:
2024-12-30 05:59:42 +08:00
parent bf78b95c9d
commit 72320ede22
42 changed files with 1758 additions and 1556 deletions

View File

@@ -27,101 +27,35 @@
// object file header, in case the file was generated on a little
// endian machine, and we're now running on a big endian machine.
//----------------------------------------------------------------------
static void
SwapHeader (NoffHeader *noffH)
static void
SwapHeader(NoffHeader* noffH)
{
noffH->noffMagic = WordToHost(noffH->noffMagic);
noffH->code.size = WordToHost(noffH->code.size);
noffH->code.virtualAddr = WordToHost(noffH->code.virtualAddr);
noffH->code.inFileAddr = WordToHost(noffH->code.inFileAddr);
noffH->noffMagic = WordToHost(noffH->noffMagic);
noffH->code.size = WordToHost(noffH->code.size);
noffH->code.virtualAddr = WordToHost(noffH->code.virtualAddr);
noffH->code.inFileAddr = WordToHost(noffH->code.inFileAddr);
#ifdef RDATA
noffH->readonlyData.size = WordToHost(noffH->readonlyData.size);
noffH->readonlyData.virtualAddr =
WordToHost(noffH->readonlyData.virtualAddr);
noffH->readonlyData.inFileAddr =
WordToHost(noffH->readonlyData.inFileAddr);
noffH->readonlyData.size = WordToHost(noffH->readonlyData.size);
noffH->readonlyData.virtualAddr =
WordToHost(noffH->readonlyData.virtualAddr);
noffH->readonlyData.inFileAddr =
WordToHost(noffH->readonlyData.inFileAddr);
#endif
noffH->initData.size = WordToHost(noffH->initData.size);
noffH->initData.virtualAddr = WordToHost(noffH->initData.virtualAddr);
noffH->initData.inFileAddr = WordToHost(noffH->initData.inFileAddr);
noffH->uninitData.size = WordToHost(noffH->uninitData.size);
noffH->uninitData.virtualAddr = WordToHost(noffH->uninitData.virtualAddr);
noffH->uninitData.inFileAddr = WordToHost(noffH->uninitData.inFileAddr);
noffH->initData.size = WordToHost(noffH->initData.size);
noffH->initData.virtualAddr = WordToHost(noffH->initData.virtualAddr);
noffH->initData.inFileAddr = WordToHost(noffH->initData.inFileAddr);
noffH->uninitData.size = WordToHost(noffH->uninitData.size);
noffH->uninitData.virtualAddr = WordToHost(noffH->uninitData.virtualAddr);
noffH->uninitData.inFileAddr = WordToHost(noffH->uninitData.inFileAddr);
#ifdef RDATA
DEBUG(dbgAddr, "code = " << noffH->code.size <<
" readonly = " << noffH->readonlyData.size <<
" init = " << noffH->initData.size <<
" uninit = " << noffH->uninitData.size << "\n");
DEBUG(dbgAddr, "code = " << noffH->code.size <<
" readonly = " << noffH->readonlyData.size <<
" init = " << noffH->initData.size <<
" uninit = " << noffH->uninitData.size << "\n");
#endif
}
FrameTable::Node::Node(int idx):
next(nullptr), idx(idx) {}
FrameTable::FrameTable()
{
available = NumPhysPages;
useCount = new int[NumPhysPages];
begin = end = new FrameTable::Node;
for (int i = 0; i < NumPhysPages; i++) {
useCount[i] = 0;
end->idx = i;
end->next = new FrameTable::Node;
end = end->next;
}
}
FrameTable::~FrameTable()
{
delete[] useCount;
while (begin != end) {
FrameTable::Node *tmpNode = begin;
begin = begin->next;
delete tmpNode;
}
delete begin;
}
int FrameTable::Allocate()
{
if (available == 0)
return -1;
int ret = begin->idx;
Node *tmp = begin;
begin = begin->next;
delete tmp;
--available;
useCount[ret]++;
bzero(kernel->machine->mainMemory + ret * PageSize, PageSize);
//cerr << "Allocated at page: " << ret << endl;
return ret;
}
void FrameTable::Release(int phyPageNum)
{
useCount[phyPageNum]--;
if (useCount[phyPageNum] > 0)
return;
++available;
//cerr << "Release page: " << end->idx << endl;
end->idx = phyPageNum;
end->next = new FrameTable::Node;
}
size_t FrameTable::RemainSize()
{
return available;
}
//----------------------------------------------------------------------
// AddrSpace::AddrSpace
// Create an address space to run a user program.
@@ -129,9 +63,24 @@ size_t FrameTable::RemainSize()
// memory. For now, this is really simple (1:1), since we are
// only uniprogramming, and we have a single unsegmented page table
//----------------------------------------------------------------------
AddrSpace::AddrSpace()
{}
{
pageTable = NULL; // initialize with NULL
/*
pageTable = new TranslationEntry[NumPhysPages];
for (int i = 0; i < NumPhysPages; i++) {
pageTable[i].virtualPage = i; // for now, virt page # = phys page #
pageTable[i].physicalPage = i;
pageTable[i].valid = TRUE;
pageTable[i].use = FALSE;
pageTable[i].dirty = FALSE;
pageTable[i].readOnly = FALSE;
}
// zero out the entire address space
bzero(kernel->machine->mainMemory, MemorySize);
*/
}
//----------------------------------------------------------------------
// AddrSpace::~AddrSpace
@@ -140,10 +89,9 @@ AddrSpace::AddrSpace()
AddrSpace::~AddrSpace()
{
for (int i = 0; i < NumPhysPages; i++)
if (pageTable[i].use == TRUE)
kernel->frameTable->Release(pageTable[i].physicalPage);
delete[] pageTable;
/* delete pageTable; */
// release frame table by page table
kernel->frameTable->Release(pageTable, numPages);
}
@@ -156,114 +104,140 @@ AddrSpace::~AddrSpace()
//
// "fileName" is the file containing the object code to load into memory
//----------------------------------------------------------------------
bool
AddrSpace::Load(char *fileName)
bool
AddrSpace::Load(char* fileName)
{
//cerr << "AddrSpace::Load" << endl;
OpenFile *executable = kernel->fileSystem->Open(fileName);
NoffHeader noffH;
unsigned int size;
OpenFile* executable = kernel->fileSystem->Open(fileName);
NoffHeader noffH;
unsigned int size;
if (executable == NULL) {
cerr << "Unable to open file " << fileName << "\n";
return FALSE;
}
if (executable == NULL) {
cerr << "Unable to open file " << fileName << "\n";
return FALSE;
}
executable->ReadAt((char *)&noffH, sizeof(noffH), 0);
if ((noffH.noffMagic != NOFFMAGIC) &&
(WordToHost(noffH.noffMagic) == NOFFMAGIC))
SwapHeader(&noffH);
ASSERT(noffH.noffMagic == NOFFMAGIC);
executable->ReadAt((char*)&noffH, sizeof(noffH), 0);
if ((noffH.noffMagic != NOFFMAGIC) &&
(WordToHost(noffH.noffMagic) == NOFFMAGIC))
SwapHeader(&noffH);
ASSERT(noffH.noffMagic == NOFFMAGIC);
#ifdef RDATA
// how big is address space?
size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size +
noffH.uninitData.size + UserStackSize;
//cerr << noffH.code.size << ' '
// << noffH.readonlyData.size << ' '
// << noffH.initData.size << ' '
// << noffH.uninitData.size << ' '
// << UserStackSize << endl;
// we need to increase the size
// to leave room for the stack
// how big is address space?
size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size +
noffH.uninitData.size + UserStackSize;
// we need to increase the size
// to leave room for the stack
#else
// how big is address space?
size = noffH.code.size + noffH.initData.size + noffH.uninitData.size
+ UserStackSize; // we need to increase the size
// to leave room for the stack
//cerr << noffH.code.size << ' '
// << noffH.initData.size << ' '
// << noffH.uninitData.size << ' '
// << UserStackSize << endl;
// how big is address space?
size = noffH.code.size + noffH.initData.size + noffH.uninitData.size
+ UserStackSize; // we need to increase the size
// to leave room for the stack
#endif
numPages = divRoundUp(size, PageSize);
size = numPages * PageSize;
numPages = divRoundUp(size, PageSize);
size = numPages * PageSize;
ASSERT(numPages <= NumPhysPages); // check we're not trying
// to run anything too big --
// at least until we have
// virtual memory
pageTable = new TranslationEntry[numPages];
for (int i = 0; i < numPages; i++) {
pageTable[i].virtualPage = i;
pageTable[i].physicalPage = -1;
pageTable[i].valid = TRUE;
pageTable[i].use = FALSE;
pageTable[i].dirty = FALSE;
pageTable[i].readOnly = FALSE;
}
DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size);
// then, copy in the code and data segments into memory
if (noffH.code.size > 0) {
DEBUG(dbgAddr, "Initializing code segment.");
DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size);
for (size_t cur = 0; cur < (size_t)noffH.code.size; cur += PageSize) {
size_t physAddr, size = min((size_t)PageSize, noffH.code.size - cur);
Translate(noffH.code.virtualAddr + cur, &physAddr, 1);
//cerr << "physAddr, size: " << physAddr << ' ' << size << endl;
executable->ReadAt(
&(kernel->machine->mainMemory[physAddr]), size,
noffH.code.inFileAddr + cur);
pageTable = kernel->frameTable->Allocate(numPages);
if (!pageTable) {
kernel->interrupt->setStatus(SystemMode);
ExceptionHandler(MemoryLimitException);
kernel->interrupt->setStatus(UserMode);
}
}
if (noffH.initData.size > 0) {
DEBUG(dbgAddr, "Initializing data segment.");
DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size);
for (size_t cur = 0; cur < (size_t)noffH.initData.size; cur += PageSize) {
size_t physAddr, size = min((size_t)PageSize, noffH.initData.size - cur);
Translate(noffH.initData.virtualAddr + cur, &physAddr, 1);
DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size);
executable->ReadAt(
&(kernel->machine->mainMemory[physAddr]), size,
noffH.initData.inFileAddr + cur);
// then, copy in the code and data segments into memory
uint paddr; // physical address
ExceptionType ex; // occurring exception
int sz, // total size to load
vaddr, // base virtual address
fpos, // base file position
to_load; // size to load on each time
if (noffH.code.size > 0) {
DEBUG(dbgAddr, "Initializing code segment.");
DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size);
sz = noffH.code.size;
vaddr = noffH.code.virtualAddr;
fpos = noffH.code.inFileAddr;
for (uint offset = 0; offset < sz; offset += PageSize) {
ex = Translate(vaddr + offset, &paddr, 1);
if (ex != NoException) {
kernel->interrupt->setStatus(SystemMode);
ExceptionHandler(ex);
kernel->interrupt->setStatus(UserMode);
}
to_load = offset + PageSize < sz ? PageSize : sz - offset;
executable->ReadAt(
&(kernel->machine->mainMemory[paddr]),
to_load, fpos + offset);
}
}
if (noffH.initData.size > 0) {
DEBUG(dbgAddr, "Initializing data segment.");
DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size);
sz = noffH.initData.size;
vaddr = noffH.initData.virtualAddr;
fpos = noffH.initData.inFileAddr;
for (uint offset = 0; offset < sz; offset += PageSize) {
ex = Translate(vaddr + offset, &paddr, 1);
if (ex != NoException) {
kernel->interrupt->setStatus(SystemMode);
ExceptionHandler(ex);
kernel->interrupt->setStatus(UserMode);
}
to_load = offset + PageSize < sz ? PageSize : sz - offset;
executable->ReadAt(
&(kernel->machine->mainMemory[paddr]),
to_load, fpos + offset);
}
}
}
#ifdef RDATA
if (noffH.readonlyData.size > 0) {
DEBUG(dbgAddr, "Initializing read only data segment.");
DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size);
if (noffH.readonlyData.size > 0) {
DEBUG(dbgAddr, "Initializing read only data segment.");
DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size);
for (size_t cur = 0; cur < (size_t)noffH.readonlyData.size; cur += PageSize) {
size_t physAddr, size = min((size_t)PageSize, noffH.readonlyData.size - cur);
Translate(noffH.readonlyData.virtualAddr + cur, &physAddr, 1);
sz = noffH.readonlyData.size;
vaddr = noffH.readonlyData.virtualAddr;
fpos = noffH.readonlyData.inFileAddr;
executable->ReadAt(
&(kernel->machine->mainMemory[physAddr]),
size, noffH.readonlyData.inFileAddr + cur);
// read only flag for page table
for (int i = 0, lim = divRoundUp(sz, PageSize),
from = vaddr / PageSize; i < lim; ++i)
pageTable[from + i].readOnly = TRUE;
for (uint offset = 0; offset < sz; offset += PageSize) {
ex = Translate(vaddr + offset, &paddr, 0); // read only
if (ex != NoException) {
kernel->interrupt->setStatus(SystemMode);
ExceptionHandler(ex);
kernel->interrupt->setStatus(UserMode);
}
to_load = offset + PageSize < sz ? PageSize : sz - offset;
executable->ReadAt(
&(kernel->machine->mainMemory[paddr]),
to_load, fpos + offset);
}
}
}
#endif
delete executable; // close file
return TRUE; // success
delete executable; // close file
return TRUE; // success
}
//----------------------------------------------------------------------
@@ -274,21 +248,20 @@ AddrSpace::Load(char *fileName)
// the address space
//
//----------------------------------------------------------------------
void
AddrSpace::Execute(char* fileName)
void
AddrSpace::Execute(char* fileName)
{
//cerr << "AddrSpace::Execute" << endl;
kernel->currentThread->space = this;
this->InitRegisters(); // set the initial register values
this->RestoreState(); // load page table register
kernel->currentThread->space = this;
kernel->machine->Run(); // jump to the user progam
this->InitRegisters(); // set the initial register values
this->RestoreState(); // load page table register
ASSERTNOTREACHED(); // machine->Run never returns;
// the address space exits
// by doing the syscall "exit"
kernel->machine->Run(); // jump to the user program
ASSERTNOTREACHED(); // machine->Run never returns;
// the address space exits
// by doing the syscall "exit"
}
@@ -301,31 +274,30 @@ AddrSpace::Execute(char* fileName)
// will be saved/restored into the currentThread->userRegisters
// when this thread is context switched out.
//----------------------------------------------------------------------
void
AddrSpace::InitRegisters()
{
Machine *machine = kernel->machine;
int i;
Machine* machine = kernel->machine;
int i;
for (i = 0; i < NumTotalRegs; i++)
machine->WriteRegister(i, 0);
for (i = 0; i < NumTotalRegs; i++)
machine->WriteRegister(i, 0);
// Initial program counter -- must be location of "Start", which
// is assumed to be virtual address zero
machine->WriteRegister(PCReg, 0);
// Initial program counter -- must be location of "Start", which
// is assumed to be virtual address zero
machine->WriteRegister(PCReg, 0);
// Need to also tell MIPS where next instruction is, because
// of branch delay possibility
// Since instructions occupy four bytes each, the next instruction
// after start will be at virtual address four.
machine->WriteRegister(NextPCReg, 4);
// Need to also tell MIPS where next instruction is, because
// of branch delay possibility
// Since instructions occupy four bytes each, the next instruction
// after start will be at virtual address four.
machine->WriteRegister(NextPCReg, 4);
// Set the stack register to the end of the address space, where we
// allocated the stack; but subtract off a bit, to make sure we don't
// accidentally reference off the end!
machine->WriteRegister(StackReg, numPages * PageSize - 16);
DEBUG(dbgAddr, "Initializing stack pointer: " << numPages * PageSize - 16);
// Set the stack register to the end of the address space, where we
// allocated the stack; but subtract off a bit, to make sure we don't
// accidentally reference off the end!
machine->WriteRegister(StackReg, numPages * PageSize - 16);
DEBUG(dbgAddr, "Initializing stack pointer: " << numPages * PageSize - 16);
}
//----------------------------------------------------------------------
@@ -335,9 +307,9 @@ AddrSpace::InitRegisters()
//
// For now, don't need to save anything!
//----------------------------------------------------------------------
void AddrSpace::SaveState()
{}
void AddrSpace::SaveState()
{
}
//----------------------------------------------------------------------
// AddrSpace::RestoreState
@@ -346,11 +318,10 @@ void AddrSpace::SaveState()
//
// For now, tell the machine where to find the page table.
//----------------------------------------------------------------------
void AddrSpace::RestoreState()
void AddrSpace::RestoreState()
{
kernel->machine->pageTable = pageTable;
kernel->machine->pageTableSize = numPages;
kernel->machine->pageTable = pageTable;
kernel->machine->pageTableSize = numPages;
}
@@ -363,50 +334,84 @@ void AddrSpace::RestoreState()
// Return any exceptions caused by the address translation.
//----------------------------------------------------------------------
ExceptionType
AddrSpace::Translate(unsigned int vaddr, unsigned int *paddr, int isReadWrite)
AddrSpace::Translate(unsigned int vaddr, unsigned int* paddr, int isReadWrite)
{
TranslationEntry *pte;
int pfn;
unsigned int vpn = vaddr / PageSize;
unsigned int offset = vaddr % PageSize;
TranslationEntry* pte;
int pfn;
unsigned int vpn = vaddr / PageSize;
unsigned int offset = vaddr % PageSize;
if(vpn >= numPages) {
return AddressErrorException;
}
pte = &pageTable[vpn];
if(isReadWrite && pte->readOnly) {
return ReadOnlyException;
}
pfn = pte->physicalPage;
if (pfn == -1) {
pfn = pte->physicalPage = kernel->frameTable->Allocate();
if (pfn == -1) {
DEBUG(dbgAddr, "Memory Limit exceeded");
return MemoryLimitException;
if (vpn >= numPages) {
return AddressErrorException;
}
}
// 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;
}
pte = &pageTable[vpn];
pte->use = TRUE; // set the use, dirty bits
if (isReadWrite && pte->readOnly) {
return ReadOnlyException;
}
if(isReadWrite)
pte->dirty = TRUE;
pfn = pte->physicalPage;
*paddr = pfn * PageSize + offset;
// if the pageFrame is too big, there is something really wrong!
// An invalid translation was loaded into the page table or TLB.
if (pfn >= NumPhysPages) {
DEBUG(dbgAddr, "Illegal physical page " << pfn);
return BusErrorException;
}
ASSERT((*paddr < MemorySize));
pte->use = TRUE; // set the use, dirty bits
//cerr << " -- AddrSpace::Translate(): vaddr: " << vaddr <<
// ", paddr: " << *paddr << "\n";
if (isReadWrite)
pte->dirty = TRUE;
return NoException;
*paddr = pfn * PageSize + offset;
ASSERT((*paddr < MemorySize));
//cerr << " -- AddrSpace::Translate(): vaddr: " << vaddr <<
// ", paddr: " << *paddr << "\n";
return NoException;
}
FrameTable::FrameTable() {
for (int i = 0; i < NumPhysPages; ++i)
available.Append(i);
}
FrameTable::~FrameTable() {}
uint FrameTable::RemainSize() { return available.NumInList(); }
PageTable FrameTable::Allocate(uint pageNum) {
// if not enough memory
if (RemainSize() < pageNum)
return NULL;
PageTable ptb = new TranslationEntry[pageNum];
for (int i = 0; i < pageNum; ++i) {
ptb[i].virtualPage = i;
int f = available.RemoveFront(); // frame number
ptb[i].physicalPage = f;
// initialize flags
ptb[i].valid = TRUE;
ptb[i].use = FALSE;
ptb[i].dirty = FALSE;
ptb[i].readOnly = FALSE;
// zero out the entire address space
bzero(kernel->machine->mainMemory + f * PageSize, PageSize);
}
return ptb;
}
void FrameTable::Release(PageTable ptb, int pageNum) {
if (!ptb)
return; // nothing to release
for (int i = 0; i < pageNum; ++i)
available.Append(ptb[i].physicalPage);
delete[] ptb;
}

View File

@@ -18,57 +18,84 @@
#define UserStackSize 1024 // increase this as necessary!
class FrameTable {
public:
FrameTable();
~FrameTable();
int Allocate();
void Release(int phyPageNum);
size_t RemainSize();
private:
struct Node {
Node *next;
int idx;
Node(int idx = -1);
};
Node *begin, *end;
size_t available;
int *useCount;
};
class AddrSpace {
public:
AddrSpace(); // Create an address space.
~AddrSpace(); // De-allocate an address space
public:
AddrSpace(); // Create an address space.
~AddrSpace(); // De-allocate an address space
bool Load(char *fileName); // Load a program into addr space from
// a file
// return false if not found
bool Load(char* fileName); // Load a program into addr space from
// a file
// return false if not found
void Execute(char *fileName); // Run a program
// assumes the program has already
// been loaded
void Execute(char* fileName); // Run a program
// assumes the program has already
// been loaded
void SaveState(); // Save/restore address space-specific
void RestoreState(); // info on a context switch
void SaveState(); // Save/restore address space-specific
void RestoreState(); // info on a context switch
// Translate virtual address _vaddr_
// to physical address _paddr_. _mode_
// is 0 for Read, 1 for Write.
ExceptionType Translate(unsigned int vaddr, unsigned int *paddr, int mode);
// Translate virtual address _vaddr_
// to physical address _paddr_. _mode_
// is 0 for Read, 1 for Write.
ExceptionType Translate(unsigned int vaddr, unsigned int* paddr, int mode);
private:
TranslationEntry *pageTable;
unsigned int numPages; // Number of pages in the virtual
// address space
private:
TranslationEntry* pageTable; // Assume linear page table translation
// for now!
unsigned int numPages; // Number of pages in the virtual
// address space
void InitRegisters(); // Initialize user-level CPU registers,
// before jumping to user code
void InitRegisters(); // Initialize user-level CPU registers,
// before jumping to user code
};
#endif // ADDRSPACE_H
#ifndef FRAME_TABLE_H
#define FRAME_TABLE_H
#include "machine.h"
#include "list.h"
/**
* Data structure of Virtual Memory
*/
typedef TranslationEntry* PageTable;
/**
* Data structure of Physical Memory
*/
class FrameTable {
public:
/**
* Initialize a frame table
*/
FrameTable();
~FrameTable();
/**
* Allocate pageNum of frames (pages) and collect
* corresponding translation information into a page table.
*
* @param pageNum numbers of pages
* @return a new Page table, NULL if not enough memory space
*/
PageTable Allocate(uint pageNum);
/**
* Release the physical memory frame
* which the info stored in PageTable
*/
void Release(PageTable ptb, int pageNum);
/**
* @return the remaining numbers of entry of the frame table
*/
uint RemainSize();
private:
List<int> available;
};
#endif /* FRAME_TABLE_H */

View File

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

View File

@@ -0,0 +1,11 @@
#include "syscall.h"
int
main()
{
int n;
for (n = 0; n < 4; n++) {
PrintInt(1);
}
return 0;
}

View File

@@ -0,0 +1,11 @@
#include "syscall.h"
int
main()
{
int n;
for (n = 0; n < 5; n++) {
PrintInt(2);
}
return 0;
}

View File

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

View File

@@ -0,0 +1,12 @@
#include "syscall.h"
int
main()
{
int n;
for (n = 0; n < 11; n++) {
PrintInt(4);
}
return 0;
}

View File

@@ -1,78 +1,71 @@
/**************************************************************
*
* userprog/ksyscall.h
*
* Kernel interface for systemcalls
*
* by Marcus Voelp (c) Universitaet Karlsruhe
*
**************************************************************/
#ifndef __USERPROG_KSYSCALL_H__
#define __USERPROG_KSYSCALL_H__
#define INT_BUF_LENGTH 13
#include "kernel.h"
#include "synchconsole.h"
void SysHalt()
{
kernel->interrupt->Halt();
}
int SysAdd(int op1, int op2)
{
return op1 + op2;
}
int SysCreate(char *filename)
{
// return value
// 1: success
// 0: failed
return kernel->interrupt->CreateFile(filename);
}
void SysPrintInt(int value) {
kernel->interrupt->PrintInt(value);
}
OpenFileId SysOpen(char *name) {
OpenFileId id = -1;
for (int i = 0; i < 20; i++)
if (kernel->fileSystem->fileDescriptorTable[i] == NULL) {
id = i;
kernel->fileSystem->fileDescriptorTable[i]
= kernel->fileSystem->Open(name);
if (kernel->fileSystem->fileDescriptorTable[i] == NULL)
return -1;
break;
}
return id;
}
int SysWrite(char *buffer, int size, OpenFileId id) {
if (id < 0 || id >= 20 || kernel->fileSystem->fileDescriptorTable[id] == NULL)
return -1;
return kernel->fileSystem->fileDescriptorTable[id]->Write(buffer, size);
}
int SysRead(char *buffer, int size, OpenFileId id) {
if (id < 0 || id >= 20 || kernel->fileSystem->fileDescriptorTable[id] == NULL)
return -1;
return kernel->fileSystem->fileDescriptorTable[id]->Read(buffer, size);
}
int SysClose(OpenFileId id) {
if (id < 0 || id >= 20 || kernel->fileSystem->fileDescriptorTable[id] == NULL)
return 0;
delete kernel->fileSystem->fileDescriptorTable[id];
kernel->fileSystem->fileDescriptorTable[id] = NULL;
return 1;
}
#endif /* ! __USERPROG_KSYSCALL_H__ */
/**************************************************************
*
* userprog/ksyscall.h
*
* Kernel interface for systemcalls
*
* by Marcus Voelp (c) Universitaet Karlsruhe
*
**************************************************************/
#ifndef __USERPROG_KSYSCALL_H__
#define __USERPROG_KSYSCALL_H__
#include "kernel.h"
#include "synchconsole.h"
typedef int OpenFileId;
void SysHalt()
{
kernel->interrupt->Halt();
}
int SysAdd(int op1, int op2)
{
return op1 + op2;
}
int SysCreate(char* filename)
{
// return value
// 1: success
// 0: failed
return kernel->interrupt->CreateFile(filename);
}
void SysPrintInt(int value)
{
kernel->interrupt->PrintInt(value);
}
// -1: open fail
// fd
OpenFileId SysOpen(char* filename)
{
return kernel->interrupt->OpenFile(filename);
}
// -1: write fail
// size
int SysWrite(char* buffer, int size, OpenFileId fd)
{
return kernel->interrupt->WriteFile(buffer, size, fd);
}
// 1: close success
// 0: close fail
int SysClose(OpenFileId fd)
{
return kernel->interrupt->CloseFile(fd);
}
// -1: read fail
// size
int SysRead(char* buffer, int size, OpenFileId fd)
{
return kernel->interrupt->ReadFile(buffer, size, fd);
}
#endif /* ! __USERPROG_KSYSCALL_H__ */

View File

@@ -1,4 +1,4 @@
/* noff.h
/* noff.h
* Data structures defining the Nachos Object Code Format
*
* Basically, we only know about three types of segments:
@@ -6,23 +6,22 @@
*/
#define NOFFMAGIC 0xbadfad /* magic number denoting Nachos
* object code file
*/
/* object code file*/
typedef struct segment {
int virtualAddr; /* location of segment in virt addr space */
int inFileAddr; /* location of segment in this file */
int size; /* size of segment */
int virtualAddr; /* location of segment in virt addr space */
int inFileAddr; /* location of segment in this file */
int size; /* size of segment */
} Segment;
typedef struct noffHeader {
int noffMagic; /* should be NOFFMAGIC */
Segment code; /* executable code segment */
Segment code; /* executable code segment */
Segment initData; /* initialized data segment */
#ifdef RDATA
Segment readonlyData; /* read only data */
#endif
Segment uninitData; /* uninitialized data segment --
* should be zero'ed before use
*/
* should be zero'ed before use
*/
} NoffHeader;

View File

@@ -17,7 +17,7 @@
// otherwise, read from this file
//----------------------------------------------------------------------
SynchConsoleInput::SynchConsoleInput(char *inputFile)
SynchConsoleInput::SynchConsoleInput(char* inputFile)
{
consoleInput = new ConsoleInput(inputFile, this);
lock = new Lock("console in");
@@ -30,9 +30,9 @@ SynchConsoleInput::SynchConsoleInput(char *inputFile)
//----------------------------------------------------------------------
SynchConsoleInput::~SynchConsoleInput()
{
delete consoleInput;
delete lock;
{
delete consoleInput;
delete lock;
delete waitFor;
}
@@ -73,7 +73,7 @@ SynchConsoleInput::CallBack()
// otherwise, read from this file
//----------------------------------------------------------------------
SynchConsoleOutput::SynchConsoleOutput(char *outputFile)
SynchConsoleOutput::SynchConsoleOutput(char* outputFile)
{
consoleOutput = new ConsoleOutput(outputFile, this);
lock = new Lock("console out");
@@ -86,9 +86,9 @@ SynchConsoleOutput::SynchConsoleOutput(char *outputFile)
//----------------------------------------------------------------------
SynchConsoleOutput::~SynchConsoleOutput()
{
delete consoleOutput;
delete lock;
{
delete consoleOutput;
delete lock;
delete waitFor;
}
@@ -106,13 +106,18 @@ SynchConsoleOutput::PutChar(char ch)
lock->Release();
}
//----------------------------------------------------------------------
// SynchConsoleOutput::PutInt
// Write a int to the console display, waiting if necessary.
//----------------------------------------------------------------------
void
SynchConsoleOutput::PutInt(int value)
{
lock->Acquire();
consoleOutput->PutInt(value);
waitFor->P();
lock->Release();
lock->Acquire();
consoleOutput->PutInt(value);
waitFor->P();
lock->Release();
}
//----------------------------------------------------------------------

View File

@@ -21,34 +21,34 @@
// a console device
class SynchConsoleInput : public CallBackObj {
public:
SynchConsoleInput(char *inputFile); // Initialize the console device
~SynchConsoleInput(); // Deallocate console device
public:
SynchConsoleInput(char* inputFile); // Initialize the console device
~SynchConsoleInput(); // Deallocate console device
char GetChar(); // Read a character, waiting if necessary
private:
ConsoleInput *consoleInput; // the hardware keyboard
Lock *lock; // only one reader at a time
Semaphore *waitFor; // wait for callBack
char GetChar(); // Read a character, waiting if necessary
void CallBack(); // called when a keystroke is available
private:
ConsoleInput* consoleInput; // the hardware keyboard
Lock* lock; // only one reader at a time
Semaphore* waitFor; // wait for callBack
void CallBack(); // called when a keystroke is available
};
class SynchConsoleOutput : public CallBackObj {
public:
SynchConsoleOutput(char *outputFile); // Initialize the console device
~SynchConsoleOutput();
public:
SynchConsoleOutput(char* outputFile); // Initialize the console device
~SynchConsoleOutput();
void PutChar(char ch); // Write a character, waiting if necessary
void PutInt(int value);
private:
ConsoleOutput *consoleOutput;// the hardware display
Lock *lock; // only one writer at a time
Semaphore *waitFor; // wait for callBack
void PutChar(char ch); // Write a character, waiting if necessary
void PutInt(int value);
void CallBack(); // called when more data can be written
private:
ConsoleOutput* consoleOutput;// the hardware display
Lock* lock; // only one writer at a time
Semaphore* waitFor; // wait for callBack
void CallBack(); // called when more data can be written
};
#endif // SYNCHCONSOLE_H

View File

@@ -1,12 +1,12 @@
/* syscalls.h
/* syscalls.h
* Nachos system call interface. These are Nachos kernel operations
* that can be invoked from user programs, by trapping to the kernel
* via the "syscall" instruction.
*
* This file is included by user programs and by the Nachos kernel.
* This file is included by user programs and by the Nachos kernel.
*
* Copyright (c) 1992-1993 The Regents of the University of California.
* All rights reserved. See copyright.h for copyright notice and limitation
* All rights reserved. See copyright.h for copyright notice and limitation
* of liability and disclaimer of warranty provisions.
*/
@@ -15,83 +15,86 @@
#include "copyright.h"
#include "errno.h"
/* system call codes -- used by the stubs to tell the kernel which system call
* is being asked for
*/
/* system call codes -- used by the stubs to tell the kernel which system call
* is being asked for
*/
#define SC_Halt 0
#define SC_Exit 1
#define SC_Exec 2
#define SC_Join 3
#define SC_Create 4
#define SC_Remove 5
#define SC_Remove 5
#define SC_Open 6
#define SC_Read 7
#define SC_Write 8
#define SC_Seek 9
#define SC_Close 10
#define SC_ThreadFork 11
#define SC_Seek 9
#define SC_Close 10
#define SC_ThreadFork 11
#define SC_ThreadYield 12
#define SC_ExecV 13
#define SC_ExecV 13
#define SC_ThreadExit 14
#define SC_ThreadJoin 15
#define SC_PrintInt 16
#define SC_Add 42
#define SC_MSG 100
#define SC_Add 42
#define SC_MSG 100
#define SC_PrintInt 16
#ifndef IN_ASM
/* The system call interface. These are the operations the Nachos
* kernel needs to support, to be able to run user programs.
*
* Each of these is invoked by a user program by simply calling the
* procedure; an assembly language stub stuffs the system call code
* into a register, and traps to the kernel. The kernel procedures
* are then invoked in the Nachos kernel, after appropriate error checking,
* from the system call entry point in exception.cc.
*/
/* The system call interface. These are the operations the Nachos
* kernel needs to support, to be able to run user programs.
*
* Each of these is invoked by a user program by simply calling the
* procedure; an assembly language stub stuffs the system call code
* into a register, and traps to the kernel. The kernel procedures
* are then invoked in the Nachos kernel, after appropriate error checking,
* from the system call entry point in exception.cc.
*/
/* Stop Nachos, and print out performance stats */
void Halt();
/*
* Show the int value on console
*/
void PrintInt(int value);
/* Stop Nachos, and print out performance stats */
void Halt();
/*
* Add the two operants and return the result
*/
*/
int Add(int op1, int op2);
/*
* Just for simply showing message, not a safe way for console IO
*/
void MSG(char *msg);
void MSG(char* msg);
/* Address space control operations: Exit, Exec, Execv, and Join */
/* This user program is done (status = 0 means exited normally). */
void Exit(int status);
void Exit(int status);
/* A unique identifier for an executing user program (address space) */
typedef int SpaceId;
typedef int SpaceId;
/* A unique identifier for a thread within a task */
typedef int ThreadId;
/* Run the specified executable, with no args */
/* This can be implemented as a call to ExecV.
*/
*/
SpaceId Exec(char* exec_name);
/* Run the executable, stored in the Nachos file "argv[0]", with
* parameters stored in argv[1..argc-1] and return the
* parameters stored in argv[1..argc-1] and return the
* address space identifier
*/
SpaceId ExecV(int argc, char* argv[]);
/* Only return once the user program "id" has finished.
/* Only return once the user program "id" has finished.
* Return the exit status.
*/
int Join(SpaceId id);
int Join(SpaceId id);
/* File system operations: Create, Remove, Open, Read, Write, Close
* These functions are patterned after UNIX -- files represent
@@ -101,45 +104,45 @@ int Join(SpaceId id);
* can be used to support these system calls if the regular Nachos
* file system has not been implemented.
*/
/* A unique identifier for an open Nachos file. */
typedef int OpenFileId;
/* when an address space starts up, it has two open files, representing
/* A unique identifier for an open Nachos file. */
typedef int OpenFileId;
/* when an address space starts up, it has two open files, representing
* keyboard input and display output (in UNIX terms, stdin and stdout).
* Read and Write can be used directly on these, without first opening
* the console device.
*/
#define SysConsoleInput 0
#define SysConsoleOutput 1
/* Create a Nachos file, with name "name" */
/* Note: Create does not open the file. */
/* Return 1 on success, negative error code on failure */
int Create(char *name);
#define SysConsoleOutput 1
/* Create a Nachos file, with name "name" */
/* Note: Create does not open the file. */
/* Return 1 on success, negative error code on failure */
int Create(char* name);
/* Remove a Nachos file, with name "name" */
int Remove(char *name);
int Remove(char* name);
/* Open the Nachos file "name", and return an "OpenFileId" that can
/* Open the Nachos file "name", and return an "OpenFileId" that can
* be used to read and write to the file.
*/
OpenFileId Open(char *name);
OpenFileId Open(char* name);
/* Write "size" bytes from "buffer" to the open file.
/* Write "size" bytes from "buffer" to the open file.
* Return the number of bytes actually read on success.
* On failure, a negative error code is returned.
*/
int Write(char *buffer, int size, OpenFileId id);
int Write(char* buffer, int size, OpenFileId id);
/* Read "size" bytes from the open file into "buffer".
/* Read "size" bytes from the open file into "buffer".
* Return the number of bytes actually read -- if the open file isn't
* long enough, or if it is an I/O device, and there aren't enough
* characters to read, return whatever is available (for I/O devices,
* long enough, or if it is an I/O device, and there aren't enough
* characters to read, return whatever is available (for I/O devices,
* you should always wait until you can return at least one character).
*/
int Read(char *buffer, int size, OpenFileId id);
int Read(char* buffer, int size, OpenFileId id);
/* Set the seek position of the open file "id"
* to the byte "position".
@@ -153,21 +156,21 @@ int Close(OpenFileId id);
/* User-level thread operations: Fork and Yield. To allow multiple
* threads to run within a user program.
* threads to run within a user program.
*
* Could define other operations, such as LockAcquire, LockRelease, etc.
*/
/* Fork a thread to run a procedure ("func") in the *same* address space
* as the current thread.
* Return a positive ThreadId on success, negative error code on failure
*/
/* Fork a thread to run a procedure ("func") in the *same* address space
* as the current thread.
* Return a positive ThreadId on success, negative error code on failure
*/
ThreadId ThreadFork(void (*func)());
/* Yield the CPU to another runnable thread, whether in this address space
* or not.
/* Yield the CPU to another runnable thread, whether in this address space
* or not.
*/
void ThreadYield();
void ThreadYield();
/*
* Blocks current thread until lokal thread ThreadID exits with ThreadExit.
@@ -180,8 +183,6 @@ int ThreadJoin(ThreadId id);
*/
void ThreadExit(int ExitCode);
void PrintInt(int number);
#endif /* IN_ASM */
#endif /* SYSCALL_H */