init: init nachos hw01, should pass jenkins os_group_20_hw job but fail on os_group_20_ta job
This commit is contained in:
316
code/userprog/addrspace.cc
Normal file
316
code/userprog/addrspace.cc
Normal file
@@ -0,0 +1,316 @@
|
||||
// addrspace.cc
|
||||
// Routines to manage address spaces (executing user programs).
|
||||
//
|
||||
// In order to run a user program, you must:
|
||||
//
|
||||
// 1. link with the -n -T 0 option
|
||||
// 2. run coff2noff to convert the object file to Nachos format
|
||||
// (Nachos object code format is essentially just a simpler
|
||||
// version of the UNIX executable object code format)
|
||||
// 3. load the NOFF file into the Nachos file system
|
||||
// (if you are using the "stub" file system, you
|
||||
// don't need to do this last step)
|
||||
//
|
||||
// Copyright (c) 1992-1996 The Regents of the University of California.
|
||||
// All rights reserved. See copyright.h for copyright notice and limitation
|
||||
// of liability and disclaimer of warranty provisions.
|
||||
|
||||
#include "copyright.h"
|
||||
#include "main.h"
|
||||
#include "addrspace.h"
|
||||
#include "machine.h"
|
||||
#include "noff.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SwapHeader
|
||||
// Do little endian to big endian conversion on the bytes in the
|
||||
// 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)
|
||||
{
|
||||
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);
|
||||
#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);
|
||||
|
||||
#ifdef RDATA
|
||||
DEBUG(dbgAddr, "code = " << noffH->code.size <<
|
||||
" readonly = " << noffH->readonlyData.size <<
|
||||
" init = " << noffH->initData.size <<
|
||||
" uninit = " << noffH->uninitData.size << "\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// AddrSpace::AddrSpace
|
||||
// Create an address space to run a user program.
|
||||
// Set up the translation from program memory to physical
|
||||
// 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 = 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
|
||||
// Dealloate an address space.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
AddrSpace::~AddrSpace()
|
||||
{
|
||||
delete pageTable;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// AddrSpace::Load
|
||||
// Load a user program into memory from a file.
|
||||
//
|
||||
// Assumes that the page table has been initialized, and that
|
||||
// the object code file is in NOFF format.
|
||||
//
|
||||
// "fileName" is the file containing the object code to load into memory
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
bool
|
||||
AddrSpace::Load(char *fileName)
|
||||
{
|
||||
OpenFile *executable = kernel->fileSystem->Open(fileName);
|
||||
NoffHeader noffH;
|
||||
unsigned int size;
|
||||
|
||||
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);
|
||||
|
||||
#ifdef RDATA
|
||||
// how big is address space?
|
||||
size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size +
|
||||
noffH.uninitData.size + UserStackSize;
|
||||
// we need to increase the size
|
||||
// to leave room for the stack
|
||||
#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
|
||||
#endif
|
||||
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
|
||||
|
||||
DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size);
|
||||
|
||||
// then, copy in the code and data segments into memory
|
||||
// Note: this code assumes that virtual address = physical address
|
||||
if (noffH.code.size > 0) {
|
||||
DEBUG(dbgAddr, "Initializing code segment.");
|
||||
DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size);
|
||||
executable->ReadAt(
|
||||
&(kernel->machine->mainMemory[noffH.code.virtualAddr]),
|
||||
noffH.code.size, noffH.code.inFileAddr);
|
||||
}
|
||||
if (noffH.initData.size > 0) {
|
||||
DEBUG(dbgAddr, "Initializing data segment.");
|
||||
DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size);
|
||||
executable->ReadAt(
|
||||
&(kernel->machine->mainMemory[noffH.initData.virtualAddr]),
|
||||
noffH.initData.size, noffH.initData.inFileAddr);
|
||||
}
|
||||
|
||||
#ifdef RDATA
|
||||
if (noffH.readonlyData.size > 0) {
|
||||
DEBUG(dbgAddr, "Initializing read only data segment.");
|
||||
DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size);
|
||||
executable->ReadAt(
|
||||
&(kernel->machine->mainMemory[noffH.readonlyData.virtualAddr]),
|
||||
noffH.readonlyData.size, noffH.readonlyData.inFileAddr);
|
||||
}
|
||||
#endif
|
||||
|
||||
delete executable; // close file
|
||||
return TRUE; // success
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// AddrSpace::Execute
|
||||
// Run a user program using the current thread
|
||||
//
|
||||
// The program is assumed to have already been loaded into
|
||||
// the address space
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
AddrSpace::Execute(char* fileName)
|
||||
{
|
||||
|
||||
kernel->currentThread->space = this;
|
||||
|
||||
this->InitRegisters(); // set the initial register values
|
||||
this->RestoreState(); // load page table register
|
||||
|
||||
kernel->machine->Run(); // jump to the user progam
|
||||
|
||||
ASSERTNOTREACHED(); // machine->Run never returns;
|
||||
// the address space exits
|
||||
// by doing the syscall "exit"
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// AddrSpace::InitRegisters
|
||||
// Set the initial values for the user-level register set.
|
||||
//
|
||||
// We write these directly into the "machine" registers, so
|
||||
// that we can immediately jump to user code. Note that these
|
||||
// will be saved/restored into the currentThread->userRegisters
|
||||
// when this thread is context switched out.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
AddrSpace::InitRegisters()
|
||||
{
|
||||
Machine *machine = kernel->machine;
|
||||
int i;
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// AddrSpace::SaveState
|
||||
// On a context switch, save any machine state, specific
|
||||
// to this address space, that needs saving.
|
||||
//
|
||||
// For now, don't need to save anything!
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void AddrSpace::SaveState()
|
||||
{}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// AddrSpace::RestoreState
|
||||
// On a context switch, restore the machine state so that
|
||||
// this address space can run.
|
||||
//
|
||||
// For now, tell the machine where to find the page table.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void AddrSpace::RestoreState()
|
||||
{
|
||||
kernel->machine->pageTable = pageTable;
|
||||
kernel->machine->pageTableSize = numPages;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// AddrSpace::Translate
|
||||
// Translate the virtual address in _vaddr_ to a physical address
|
||||
// and store the physical address in _paddr_.
|
||||
// The flag _isReadWrite_ is false (0) for read-only access; true (1)
|
||||
// for read-write access.
|
||||
// Return any exceptions caused by the address translation.
|
||||
//----------------------------------------------------------------------
|
||||
ExceptionType
|
||||
AddrSpace::Translate(unsigned int vaddr, unsigned int *paddr, int isReadWrite)
|
||||
{
|
||||
TranslationEntry *pte;
|
||||
int pfn;
|
||||
unsigned int vpn = vaddr / PageSize;
|
||||
unsigned int offset = vaddr % PageSize;
|
||||
|
||||
if(vpn >= numPages) {
|
||||
return AddressErrorException;
|
||||
}
|
||||
|
||||
pte = &pageTable[vpn];
|
||||
|
||||
if(isReadWrite && pte->readOnly) {
|
||||
return ReadOnlyException;
|
||||
}
|
||||
|
||||
pfn = pte->physicalPage;
|
||||
|
||||
// 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->use = TRUE; // set the use, dirty bits
|
||||
|
||||
if(isReadWrite)
|
||||
pte->dirty = TRUE;
|
||||
|
||||
*paddr = pfn*PageSize + offset;
|
||||
|
||||
ASSERT((*paddr < MemorySize));
|
||||
|
||||
//cerr << " -- AddrSpace::Translate(): vaddr: " << vaddr <<
|
||||
// ", paddr: " << *paddr << "\n";
|
||||
|
||||
return NoException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
53
code/userprog/addrspace.h
Normal file
53
code/userprog/addrspace.h
Normal file
@@ -0,0 +1,53 @@
|
||||
// addrspace.h
|
||||
// Data structures to keep track of executing user programs
|
||||
// (address spaces).
|
||||
//
|
||||
// For now, we don't keep any information about address spaces.
|
||||
// The user level CPU state is saved and restored in the thread
|
||||
// executing the user program (see thread.h).
|
||||
//
|
||||
// Copyright (c) 1992-1996 The Regents of the University of California.
|
||||
// All rights reserved. See copyright.h for copyright notice and limitation
|
||||
// of liability and disclaimer of warranty provisions.
|
||||
|
||||
#ifndef ADDRSPACE_H
|
||||
#define ADDRSPACE_H
|
||||
|
||||
#include "copyright.h"
|
||||
#include "filesys.h"
|
||||
|
||||
#define UserStackSize 1024 // increase this as necessary!
|
||||
|
||||
class AddrSpace {
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
// 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; // 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
|
||||
|
||||
};
|
||||
|
||||
#endif // ADDRSPACE_H
|
||||
84
code/userprog/errno.h
Normal file
84
code/userprog/errno.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/* errno.h
|
||||
* Error codes for system calls.
|
||||
*
|
||||
* Do not modify the contents of this file.
|
||||
*
|
||||
* Try to use the most descriptive error number for the error.
|
||||
* You may find it helpful to see what errors equivalent UNIX
|
||||
* system calls return under various error conditions.
|
||||
* For example the man page for the write system call "man 2 write"
|
||||
* provides a list of different error number values for different
|
||||
* conditions.
|
||||
* NOTE: there are way more errors here than you should be supporting
|
||||
* and many more error conditions listed in man pages than
|
||||
* Nachos can possibly generate. The list here is to give you
|
||||
* some ideas and to hopefully standardize on some error numbers.
|
||||
*
|
||||
* ALSO NOTE: These definitions may not correspond to Solaris definitions
|
||||
* (for copyright reasons these are taken from Linux).
|
||||
*/
|
||||
|
||||
#ifndef ERRNO_H
|
||||
#define ERRNO_H
|
||||
|
||||
#include "copyright.h"
|
||||
|
||||
#define EPERM -1 /* Operation not permitted */
|
||||
#define ENOENT -2 /* No such file or directory */
|
||||
#define ESRCH -3 /* No such process */
|
||||
#define EINTR -4 /* Interrupted system call */
|
||||
#define EIO -5 /* I/O error */
|
||||
#define ENXIO -6 /* No such device or address */
|
||||
#define E2BIG -7 /* Arg list too long */
|
||||
#define ENOEXEC -8 /* Exec format error */
|
||||
#define EBADF -9 /* Bad file number */
|
||||
#define ECHILD -10 /* No child processes */
|
||||
#define EAGAIN -11 /* Try again */
|
||||
#define ENOMEM -12 /* Out of memory */
|
||||
#define EACCES -13 /* Permission denied */
|
||||
#define EFAULT -14 /* Bad address */
|
||||
#define ENOTBLK -15 /* Block device required */
|
||||
#define EBUSY -16 /* Device or resource busy */
|
||||
#define EEXIST -17 /* File exists */
|
||||
#define EXDEV -18 /* Cross-device link */
|
||||
#define ENODEV -19 /* No such device */
|
||||
#define ENOTDIR -20 /* Not a directory */
|
||||
#define EISDIR -21 /* Is a directory */
|
||||
#define EINVAL -22 /* Invalid argument */
|
||||
#define ENFILE -23 /* File table overflow */
|
||||
#define EMFILE -24 /* Too many open files */
|
||||
#define ENOTTY -25 /* Not a typewriter */
|
||||
#define ETXTBSY -26 /* Text file busy */
|
||||
#define EFBIG -27 /* File too large */
|
||||
#define ENOSPC -28 /* No space left on device */
|
||||
#define ESPIPE -29 /* Illegal seek */
|
||||
#define EROFS -30 /* Read-only file system */
|
||||
#define EMLINK -31 /* Too many links */
|
||||
#define EPIPE -32 /* Broken pipe */
|
||||
#define EDOM -33 /* Math argument out of domain of func */
|
||||
#define ERANGE -34 /* Math result not representable */
|
||||
#define EDEADLK -35 /* Resource deadlock would occur */
|
||||
#define ENAMETOOLONG -36 /* File name too long */
|
||||
#define ENOLCK -37 /* No record locks available */
|
||||
#define ENOSYS -38 /* Function not implemented */
|
||||
#define ENOTEMPTY -39 /* Directory not empty */
|
||||
#define ELOOP -40 /* Too many symbolic links encountered */
|
||||
#define EWOULDBLOCK EAGAIN /* Operation would block */
|
||||
#define ENOMSG -42 /* No message of desired type */
|
||||
#define EIDRM -43 /* Identifier removed */
|
||||
#define ECHRNG -44 /* Channel number out of range */
|
||||
#define EL2NSYNC -45 /* Level 2 not synchronized */
|
||||
#define EL3HLT -46 /* Level 3 halted */
|
||||
#define EL3RST -47 /* Level 3 reset */
|
||||
#define ELNRNG -48 /* Link number out of range */
|
||||
#define EUNATCH -49 /* Protocol driver not attached */
|
||||
#define ENOCSI -50 /* No CSI structure available */
|
||||
#define EL2HLT -51 /* Level 2 halted */
|
||||
#define EBADE -52 /* Invalid exchange */
|
||||
#define EBADR -53 /* Invalid request descriptor */
|
||||
#define EXFULL -54 /* Exchange full */
|
||||
#define ENOANO -55 /* No anode */
|
||||
#define EBADRQC -56 /* Invalid request code */
|
||||
#define EBADSLT -57 /* Invalid slot */
|
||||
|
||||
#endif // ERRNO_H
|
||||
132
code/userprog/exception.cc
Normal file
132
code/userprog/exception.cc
Normal file
@@ -0,0 +1,132 @@
|
||||
// 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:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Copyright (c) 1992-1996 The Regents of the University of California.
|
||||
// All rights reserved. See copyright.h for copyright notice and limitation
|
||||
// of liability and disclaimer of warranty provisions.
|
||||
|
||||
#include "copyright.h"
|
||||
#include "main.h"
|
||||
#include "syscall.h"
|
||||
#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.
|
||||
//
|
||||
// For system calls, the following is the calling convention:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// 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.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
default:
|
||||
cerr << "Unexpected system call " << type << "\n";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cerr << "Unexpected user mode exception " << (int)which << "\n";
|
||||
break;
|
||||
}
|
||||
ASSERTNOTREACHED();
|
||||
}
|
||||
|
||||
38
code/userprog/ksyscall.h
Normal file
38
code/userprog/ksyscall.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/**************************************************************
|
||||
*
|
||||
* userprog/ksyscall.h
|
||||
*
|
||||
* Kernel interface for systemcalls
|
||||
*
|
||||
* by Marcus Voelp (c) Universitaet Karlsruhe
|
||||
*
|
||||
**************************************************************/
|
||||
|
||||
#ifndef __USERPROG_KSYSCALL_H__
|
||||
#define __USERPROG_KSYSCALL_H__
|
||||
|
||||
#include "kernel.h"
|
||||
|
||||
#include "synchconsole.h"
|
||||
|
||||
|
||||
void SysHalt()
|
||||
{
|
||||
kernel->interrupt->Halt();
|
||||
}
|
||||
|
||||
int SysAdd(int op1, int op2)
|
||||
{
|
||||
return op1 + op2;
|
||||
}
|
||||
|
||||
int SysCreate(char *filename)
|
||||
{
|
||||
// return value
|
||||
// 1: success
|
||||
// 0: failed
|
||||
return kernel->interrupt->CreateFile(filename);
|
||||
}
|
||||
|
||||
|
||||
#endif /* ! __USERPROG_KSYSCALL_H__ */
|
||||
28
code/userprog/noff.h
Normal file
28
code/userprog/noff.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/* noff.h
|
||||
* Data structures defining the Nachos Object Code Format
|
||||
*
|
||||
* Basically, we only know about three types of segments:
|
||||
* code (read-only), initialized data, and unitialized data
|
||||
*/
|
||||
|
||||
#define NOFFMAGIC 0xbadfad /* magic number denoting Nachos
|
||||
* 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 */
|
||||
} Segment;
|
||||
|
||||
typedef struct noffHeader {
|
||||
int noffMagic; /* should be NOFFMAGIC */
|
||||
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
|
||||
*/
|
||||
} NoffHeader;
|
||||
119
code/userprog/synchconsole.cc
Normal file
119
code/userprog/synchconsole.cc
Normal file
@@ -0,0 +1,119 @@
|
||||
// synchconsole.cc
|
||||
// Routines providing synchronized access to the keyboard
|
||||
// and console display hardware devices.
|
||||
//
|
||||
// Copyright (c) 1992-1996 The Regents of the University of California.
|
||||
// All rights reserved. See copyright.h for copyright notice and limitation
|
||||
// of liability and disclaimer of warranty provisions.
|
||||
|
||||
#include "copyright.h"
|
||||
#include "synchconsole.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SynchConsoleInput::SynchConsoleInput
|
||||
// Initialize synchronized access to the keyboard
|
||||
//
|
||||
// "inputFile" -- if NULL, use stdin as console device
|
||||
// otherwise, read from this file
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
SynchConsoleInput::SynchConsoleInput(char *inputFile)
|
||||
{
|
||||
consoleInput = new ConsoleInput(inputFile, this);
|
||||
lock = new Lock("console in");
|
||||
waitFor = new Semaphore("console in", 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SynchConsoleInput::~SynchConsoleInput
|
||||
// Deallocate data structures for synchronized access to the keyboard
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
SynchConsoleInput::~SynchConsoleInput()
|
||||
{
|
||||
delete consoleInput;
|
||||
delete lock;
|
||||
delete waitFor;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SynchConsoleInput::GetChar
|
||||
// Read a character typed at the keyboard, waiting if necessary.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
char
|
||||
SynchConsoleInput::GetChar()
|
||||
{
|
||||
char ch;
|
||||
|
||||
lock->Acquire();
|
||||
waitFor->P(); // wait for EOF or a char to be available.
|
||||
ch = consoleInput->GetChar();
|
||||
lock->Release();
|
||||
return ch;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SynchConsoleInput::CallBack
|
||||
// Interrupt handler called when keystroke is hit; wake up
|
||||
// anyone waiting.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
SynchConsoleInput::CallBack()
|
||||
{
|
||||
waitFor->V();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SynchConsoleOutput::SynchConsoleOutput
|
||||
// Initialize synchronized access to the console display
|
||||
//
|
||||
// "outputFile" -- if NULL, use stdout as console device
|
||||
// otherwise, read from this file
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
SynchConsoleOutput::SynchConsoleOutput(char *outputFile)
|
||||
{
|
||||
consoleOutput = new ConsoleOutput(outputFile, this);
|
||||
lock = new Lock("console out");
|
||||
waitFor = new Semaphore("console out", 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SynchConsoleOutput::~SynchConsoleOutput
|
||||
// Deallocate data structures for synchronized access to the keyboard
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
SynchConsoleOutput::~SynchConsoleOutput()
|
||||
{
|
||||
delete consoleOutput;
|
||||
delete lock;
|
||||
delete waitFor;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SynchConsoleOutput::PutChar
|
||||
// Write a character to the console display, waiting if necessary.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
SynchConsoleOutput::PutChar(char ch)
|
||||
{
|
||||
lock->Acquire();
|
||||
consoleOutput->PutChar(ch);
|
||||
waitFor->P();
|
||||
lock->Release();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SynchConsoleOutput::CallBack
|
||||
// Interrupt handler called when it's safe to send the next
|
||||
// character can be sent to the display.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
SynchConsoleOutput::CallBack()
|
||||
{
|
||||
waitFor->V();
|
||||
}
|
||||
53
code/userprog/synchconsole.h
Normal file
53
code/userprog/synchconsole.h
Normal file
@@ -0,0 +1,53 @@
|
||||
// synchconsole.h
|
||||
// Data structures for synchronized access to the keyboard
|
||||
// and console display devices.
|
||||
//
|
||||
// NOTE: this abstraction is not completely implemented.
|
||||
//
|
||||
// Copyright (c) 1992-1996 The Regents of the University of California.
|
||||
// All rights reserved. See copyright.h for copyright notice and limitation
|
||||
// of liability and disclaimer of warranty provisions.
|
||||
|
||||
#ifndef SYNCHCONSOLE_H
|
||||
#define SYNCHCONSOLE_H
|
||||
|
||||
#include "copyright.h"
|
||||
#include "utility.h"
|
||||
#include "callback.h"
|
||||
#include "console.h"
|
||||
#include "synch.h"
|
||||
|
||||
// The following two classes define synchronized input and output to
|
||||
// a console device
|
||||
|
||||
class SynchConsoleInput : public CallBackObj {
|
||||
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
|
||||
|
||||
void CallBack(); // called when a keystroke is available
|
||||
};
|
||||
|
||||
class SynchConsoleOutput : public CallBackObj {
|
||||
public:
|
||||
SynchConsoleOutput(char *outputFile); // Initialize the console device
|
||||
~SynchConsoleOutput();
|
||||
|
||||
void PutChar(char ch); // Write a character, waiting if necessary
|
||||
|
||||
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
|
||||
183
code/userprog/syscall.h
Normal file
183
code/userprog/syscall.h
Normal file
@@ -0,0 +1,183 @@
|
||||
/* 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.
|
||||
*
|
||||
* Copyright (c) 1992-1993 The Regents of the University of California.
|
||||
* All rights reserved. See copyright.h for copyright notice and limitation
|
||||
* of liability and disclaimer of warranty provisions.
|
||||
*/
|
||||
|
||||
#ifndef SYSCALLS_H
|
||||
#define SYSCALLS_H
|
||||
|
||||
#include "copyright.h"
|
||||
#include "errno.h"
|
||||
/* 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_Open 6
|
||||
#define SC_Read 7
|
||||
#define SC_Write 8
|
||||
#define SC_Seek 9
|
||||
#define SC_Close 10
|
||||
#define SC_ThreadFork 11
|
||||
#define SC_ThreadYield 12
|
||||
#define SC_ExecV 13
|
||||
#define SC_ThreadExit 14
|
||||
#define SC_ThreadJoin 15
|
||||
#define SC_Add 42
|
||||
#define SC_MSG 100
|
||||
|
||||
#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.
|
||||
*/
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Address space control operations: Exit, Exec, Execv, and Join */
|
||||
|
||||
/* This user program is done (status = 0 means exited normally). */
|
||||
void Exit(int status);
|
||||
|
||||
/* A unique identifier for an executing user program (address space) */
|
||||
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
|
||||
* address space identifier
|
||||
*/
|
||||
SpaceId ExecV(int argc, char* argv[]);
|
||||
|
||||
/* Only return once the user program "id" has finished.
|
||||
* Return the exit status.
|
||||
*/
|
||||
int Join(SpaceId id);
|
||||
|
||||
|
||||
/* File system operations: Create, Remove, Open, Read, Write, Close
|
||||
* These functions are patterned after UNIX -- files represent
|
||||
* both files *and* hardware I/O devices.
|
||||
*
|
||||
* Note that the Nachos file system has a stub implementation, which
|
||||
* 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
|
||||
* 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);
|
||||
|
||||
/* Remove a Nachos file, with name "name" */
|
||||
int Remove(char *name);
|
||||
|
||||
/* Open the Nachos file "name", and return an "OpenFileId" that can
|
||||
* be used to read and write to the file.
|
||||
*/
|
||||
OpenFileId Open(char *name);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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,
|
||||
* you should always wait until you can return at least one character).
|
||||
*/
|
||||
int Read(char *buffer, int size, OpenFileId id);
|
||||
|
||||
/* Set the seek position of the open file "id"
|
||||
* to the byte "position".
|
||||
*/
|
||||
int Seek(int position, OpenFileId id);
|
||||
|
||||
/* Close the file, we're done reading and writing to it.
|
||||
* Return 1 on success, negative error code on failure
|
||||
*/
|
||||
int Close(OpenFileId id);
|
||||
|
||||
|
||||
/* User-level thread operations: Fork and Yield. To allow multiple
|
||||
* 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
|
||||
*/
|
||||
ThreadId ThreadFork(void (*func)());
|
||||
|
||||
/* Yield the CPU to another runnable thread, whether in this address space
|
||||
* or not.
|
||||
*/
|
||||
void ThreadYield();
|
||||
|
||||
/*
|
||||
* Blocks current thread until lokal thread ThreadID exits with ThreadExit.
|
||||
* Function returns the ExitCode of ThreadExit() of the exiting thread.
|
||||
*/
|
||||
int ThreadJoin(ThreadId id);
|
||||
|
||||
/*
|
||||
* Deletes current thread and returns ExitCode to every waiting lokal thread.
|
||||
*/
|
||||
void ThreadExit(int ExitCode);
|
||||
|
||||
#endif /* IN_ASM */
|
||||
|
||||
#endif /* SYSCALL_H */
|
||||
|
||||
Reference in New Issue
Block a user