Initial version

This commit is contained in:
Yorick Barbanneau 2021-10-11 22:27:00 +02:00
commit 6f405265a5
102 changed files with 14486 additions and 0 deletions

24
code/userprog/Makefile Normal file
View file

@ -0,0 +1,24 @@
# NOTE: this is a GNU Makefile. You must use "gmake" rather than "make".
#
# Makefile for the multiprogramming assignment
# Defines set up assuming multiprogramming is done before the file system.
# If not, use the "filesys first" defines below.
#
#
# Copyright (c) 1992 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.
DEFINES = -DUSER_PROGRAM -DFILESYS_NEEDED -DFILESYS_STUB
INCPATH = -I../bin -I../filesys -I../userprog -I../threads -I../machine
C_OFILES = $(THREAD_O) $(USERPROG_O)
# if file system done first!
# DEFINES = -DUSER_PROGRAM -DFILESYS_NEEDED -DFILESYS
# INCPATH = -I../bin -I../filesys -I../userprog -I../threads -I../machine
# C_OFILES = $(THREAD_O) $(USERPROG_O) $(FILESYS_O)
include ../Makefile.common
include ../Makefile.dep

294
code/userprog/addrspace.cc Normal file
View file

@ -0,0 +1,294 @@
// 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 haven't implemented the file system yet, you
// don't need to do this last step)
//
// 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.
#include "copyright.h"
#include "system.h"
#include "addrspace.h"
#include "noff.h"
#include "syscall.h"
#include "new"
//----------------------------------------------------------------------
// 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);
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);
}
//----------------------------------------------------------------------
// AddrSpaceList
// List of all address spaces, for debugging
//----------------------------------------------------------------------
List AddrSpaceList;
//----------------------------------------------------------------------
// AddrSpace::AddrSpace
// Create an address space to run a user program.
// Load the program from a file "executable", and set everything
// up so that we can start executing user instructions.
//
// Assumes that the object code file is in NOFF format.
//
// First, 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
//
// "executable" is the file containing the object code to load into memory
//----------------------------------------------------------------------
AddrSpace::AddrSpace (OpenFile * executable)
{
unsigned int i, size;
executable->ReadAt (&noffH, sizeof (noffH), 0);
if ((noffH.noffMagic != NOFFMAGIC) &&
(WordToHost (noffH.noffMagic) == NOFFMAGIC))
SwapHeader (&noffH);
/* Check that this is really a MIPS program */
ASSERT (noffH.noffMagic == NOFFMAGIC);
// how big is address space?
size = noffH.code.size + noffH.initData.size + noffH.uninitData.size + UserStacksAreaSize; // we need to increase the size
// to leave room for the stack
numPages = divRoundUp (size, PageSize);
size = numPages * PageSize;
// check we're not trying
// to run anything too big --
// at least until we have
// virtual memory
if (numPages > NumPhysPages)
throw std::bad_alloc();
DEBUG ('a', "Initializing address space, num pages %d, total size 0x%x\n",
numPages, size);
// first, set up the translation
pageTable = new TranslationEntry[numPages];
for (i = 0; i < numPages; i++)
{
pageTable[i].physicalPage = i; // for now, phys page # = virtual page #
pageTable[i].valid = TRUE;
pageTable[i].use = FALSE;
pageTable[i].dirty = FALSE;
pageTable[i].readOnly = FALSE; // if the code segment was entirely on
// a separate page, we could set its
// pages to be read-only
}
// then, copy in the code and data segments into memory
if (noffH.code.size > 0)
{
DEBUG ('a', "Initializing code segment, at 0x%x, size 0x%x\n",
noffH.code.virtualAddr, noffH.code.size);
executable->ReadAt (&(machine->mainMemory[noffH.code.virtualAddr]),
noffH.code.size, noffH.code.inFileAddr);
}
if (noffH.initData.size > 0)
{
DEBUG ('a', "Initializing data segment, at 0x%x, size 0x%x\n",
noffH.initData.virtualAddr, noffH.initData.size);
executable->ReadAt (&
(machine->mainMemory
[noffH.initData.virtualAddr]),
noffH.initData.size, noffH.initData.inFileAddr);
}
DEBUG ('a', "Area for stacks at 0x%x, size 0x%x\n",
size - UserStacksAreaSize, UserStacksAreaSize);
pageTable[0].valid = FALSE; // Catch NULL dereference
AddrSpaceList.Append(this);
}
//----------------------------------------------------------------------
// AddrSpace::~AddrSpace
// Dealloate an address space. Nothing for now!
//----------------------------------------------------------------------
AddrSpace::~AddrSpace ()
{
delete [] pageTable;
pageTable = NULL;
AddrSpaceList.Remove(this);
}
//----------------------------------------------------------------------
// 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 ()
{
int i;
for (i = 0; i < NumTotalRegs; i++)
machine->WriteRegister (i, 0);
// Initial program counter -- must be location of "Start"
machine->WriteRegister (PCReg, USER_START_ADDRESS);
// Need to also tell MIPS where next instruction is, because
// of branch delay possibility
machine->WriteRegister (NextPCReg, machine->ReadRegister(PCReg) + 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 ('a', "Initializing stack register to 0x%x\n",
numPages * PageSize - 16);
}
//----------------------------------------------------------------------
// AddrSpace::Dump
// Dump program layout as SVG
//----------------------------------------------------------------------
static void
DrawArea(FILE *output, unsigned sections_x, unsigned virtual_x,
unsigned y, unsigned blocksize,
struct segment *segment, const char *name)
{
if (segment->size == 0)
return;
ASSERT((segment->virtualAddr % PageSize == 0));
ASSERT((segment->size % PageSize == 0));
unsigned page = segment->virtualAddr / PageSize;
unsigned end = (segment->virtualAddr + segment->size) / PageSize;
fprintf(output, "<rect x=\"%u\" y=\"%u\" width=\"%u\" height=\"%u\" "
"fill=\"#ffffff\" "
"stroke=\"#000000\" stroke-width=\"1\"/>\n",
sections_x, y - end * blocksize,
virtual_x - sections_x, (end - page) * blocksize);
fprintf(output, "<text x=\"%u\" y=\"%u\" fill=\"#000000\" font-size=\"%u\">%s</text>\n",
sections_x, y - page * blocksize, blocksize, name);
}
unsigned
AddrSpace::Dump(FILE *output, unsigned addr_x, unsigned sections_x, unsigned virtual_x, unsigned virtual_width,
unsigned physical_x, unsigned virtual_y, unsigned y,
unsigned blocksize)
{
unsigned ret = machine->DumpPageTable(output, pageTable, numPages,
addr_x, virtual_x, virtual_width, physical_x, virtual_y, y, blocksize);
DrawArea(output, sections_x, virtual_x, virtual_y, blocksize, &noffH.code, "code");
DrawArea(output, sections_x, virtual_x, virtual_y, blocksize, &noffH.initData, "data");
DrawArea(output, sections_x, virtual_x, virtual_y, blocksize, &noffH.uninitData, "bss");
DumpThreadsState(output, this, sections_x, virtual_x, virtual_y, blocksize);
return ret;
}
//----------------------------------------------------------------------
// AddrSpace::AddrSpacesRoom
// Return how much room is needed for showing address spaces
//----------------------------------------------------------------------
unsigned
AddrSpacesRoom(unsigned blocksize)
{
ListElement *element;
unsigned room = 0;
for (element = AddrSpaceList.FirstElement ();
element;
element = element->next) {
AddrSpace *space = (AddrSpace*) element->item;
room += machine->PageTableRoom(space->NumPages(), blocksize);
}
return room;
}
//----------------------------------------------------------------------
// AddrSpace::DumpAddrSpaces
// Dump all address spaces
//----------------------------------------------------------------------
void
DumpAddrSpaces(FILE *output,
unsigned addr_x, unsigned sections_x, unsigned virtual_x, unsigned virtual_width,
unsigned physical_x, unsigned y, unsigned blocksize)
{
ListElement *element;
unsigned virtual_y = y;
/* TODO: sort by physical page addresses to avoid too much mess */
for (element = AddrSpaceList.FirstElement ();
element;
element = element->next) {
AddrSpace *space = (AddrSpace*) element->item;
virtual_y -= space->Dump(output, addr_x, sections_x, virtual_x, virtual_width, physical_x, virtual_y, y, blocksize);
}
}
//----------------------------------------------------------------------
// AddrSpace::SaveState
// On a context switch, save any machine state, specific
// to this address space, that needs saving.
//
// For now, nothing!
//----------------------------------------------------------------------
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 ()
{
machine->currentPageTable = pageTable;
machine->currentPageTableSize = numPages;
}

53
code/userprog/addrspace.h Normal file
View 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-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 ADDRSPACE_H
#define ADDRSPACE_H
#include "copyright.h"
#include "filesys.h"
#include "translate.h"
#include "noff.h"
#include "list.h"
#define UserStacksAreaSize 1024 // increase this as necessary!
class AddrSpace:public dontcopythis
{
public:
AddrSpace (OpenFile * executable); // Create an address space,
// initializing it with the program
// stored in the file "executable"
~AddrSpace (); // De-allocate an address space
void InitRegisters (); // Initialize user-level CPU registers,
// before jumping to user code
void SaveState (); // Save/restore address space-specific
void RestoreState (); // info on a context switch
unsigned Dump(FILE *output, unsigned addr_s, unsigned sections_x, unsigned virtual_x, unsigned virtual_width,
unsigned physical_x, unsigned virtual_y, unsigned y,
unsigned blocksize);
// Dump program layout as SVG
unsigned NumPages() { return numPages; }
private:
NoffHeader noffH; // Program layout
TranslationEntry * pageTable; // Page table
unsigned int numPages; // Number of pages in the page table
};
extern List AddrspaceList;
#endif // ADDRSPACE_H

172
code/userprog/bitmap.cc Normal file
View file

@ -0,0 +1,172 @@
// bitmap.c
// Routines to manage a bitmap -- an array of bits each of which
// can be either on or off. Represented as an array of integers.
//
// 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.
#include "copyright.h"
#include "bitmap.h"
// Definitions helpful for representing a bitmap as an array of integers
#define BitsInByte 8
#define BitsInWord 32
//----------------------------------------------------------------------
// BitMap::BitMap
// Initialize a bitmap with "nitems" bits, so that every bit is clear.
// it can be added somewhere on a list.
//
// "nitems" is the number of bits in the bitmap.
//----------------------------------------------------------------------
BitMap::BitMap (int nitems)
{
numBits = nitems;
numWords = divRoundUp (numBits, BitsInWord);
map = new unsigned int[numWords];
for (int i = 0; i < numBits; i++)
Clear (i);
}
//----------------------------------------------------------------------
// BitMap::~BitMap
// De-allocate a bitmap.
//----------------------------------------------------------------------
BitMap::~BitMap ()
{
delete [] map;
map = NULL;
}
//----------------------------------------------------------------------
// BitMap::Mark
// Set the "nth" bit in a bitmap.
//
// "which" is the number of the bit to be set.
//----------------------------------------------------------------------
void
BitMap::Mark (int which)
{
ASSERT (which >= 0 && which < numBits);
map[which / BitsInWord] |= 1 << (which % BitsInWord);
}
//----------------------------------------------------------------------
// BitMap::Clear
// Clear the "nth" bit in a bitmap.
//
// "which" is the number of the bit to be cleared.
//----------------------------------------------------------------------
void
BitMap::Clear (int which)
{
ASSERT (which >= 0 && which < numBits);
map[which / BitsInWord] &= ~(1 << (which % BitsInWord));
}
//----------------------------------------------------------------------
// BitMap::Test
// Return TRUE if the "nth" bit is set.
//
// "which" is the number of the bit to be tested.
//----------------------------------------------------------------------
bool
BitMap::Test (int which)
{
ASSERT (which >= 0 && which < numBits);
if (map[which / BitsInWord] & (1 << (which % BitsInWord)))
return TRUE;
else
return FALSE;
}
//----------------------------------------------------------------------
// BitMap::Find
// Return the number of the first bit which is clear.
// As a side effect, set the bit (mark it as in use).
// (In other words, find and allocate a bit.)
//
// If no bits are clear, return -1.
//----------------------------------------------------------------------
int
BitMap::Find ()
{
for (int i = 0; i < numBits; i++)
if (!Test (i))
{
Mark (i);
return i;
}
return -1;
}
//----------------------------------------------------------------------
// BitMap::NumClear
// Return the number of clear bits in the bitmap.
// (In other words, how many bits are unallocated?)
//----------------------------------------------------------------------
int
BitMap::NumClear ()
{
int count = 0;
for (int i = 0; i < numBits; i++)
if (!Test (i))
count++;
return count;
}
//----------------------------------------------------------------------
// BitMap::Print
// Print the contents of the bitmap, for debugging.
//
// Could be done in a number of ways, but we just print the #'s of
// all the bits that are set in the bitmap.
//----------------------------------------------------------------------
void
BitMap::Print ()
{
printf ("Bitmap set:\n");
for (int i = 0; i < numBits; i++)
if (Test (i))
printf ("%d, ", i);
printf ("\n");
}
// These aren't needed until the FILESYS assignment
//----------------------------------------------------------------------
// BitMap::FetchFromFile
// Initialize the contents of a bitmap from a Nachos file.
//
// "file" is the place to read the bitmap from
//----------------------------------------------------------------------
void
BitMap::FetchFrom (OpenFile * file)
{
file->ReadAt (map, numWords * sizeof (unsigned), 0);
}
//----------------------------------------------------------------------
// BitMap::WriteBack
// Store the contents of a bitmap to a Nachos file.
//
// "file" is the place to write the bitmap to
//----------------------------------------------------------------------
void
BitMap::WriteBack (OpenFile * file)
{
file->WriteAt (map, numWords * sizeof (unsigned), 0);
}

61
code/userprog/bitmap.h Normal file
View file

@ -0,0 +1,61 @@
// bitmap.h
// Data structures defining a bitmap -- an array of bits each of which
// can be either on or off.
//
// Represented as an array of unsigned integers, on which we do
// modulo arithmetic to find the bit we are interested in.
//
// The bitmap can be parameterized with with the number of bits being
// managed.
//
// 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 BITMAP_H
#define BITMAP_H
#include "copyright.h"
#include "utility.h"
#include "openfile.h"
// The following class defines a "bitmap" -- an array of bits,
// each of which can be independently set, cleared, and tested.
//
// Most useful for managing the allocation of the elements of an array --
// for instance, disk sectors, or main memory pages.
// Each bit represents whether the corresponding sector or page is
// in use or free.
class BitMap:public dontcopythis
{
public:
BitMap (int nitems); // Initialize a bitmap, with "nitems" bits
// initially, all bits are cleared.
~BitMap (); // De-allocate bitmap
void Mark (int which); // Set the "nth" bit
void Clear (int which); // Clear the "nth" bit
bool Test (int which); // Is the "nth" bit set?
int Find (); // Return the # of a clear bit, and as a side
// effect, set the bit.
// If no bits are clear, return -1.
int NumClear (); // Return the number of clear bits
void Print (); // Print contents of bitmap
// These aren't needed until FILESYS, when we will need to read and
// write the bitmap to a file
void FetchFrom (OpenFile * file); // fetch contents from disk
void WriteBack (OpenFile * file); // write contents to disk
private:
int numBits; // number of bits in the bitmap
int numWords; // number of words of bitmap storage
// (rounded up if numBits is not a
// multiple of the number of bits in
// a word)
unsigned int *map; // bit storage
};
#endif // BITMAP_H

137
code/userprog/exception.cc Normal file
View file

@ -0,0 +1,137 @@
// 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-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.
#include "copyright.h"
#include "system.h"
#include "syscall.h"
//----------------------------------------------------------------------
// UpdatePC : Increments the Program Counter register in order to resume
// the user program immediately after the "syscall" instruction.
//----------------------------------------------------------------------
static void
UpdatePC ()
{
int pc = machine->ReadRegister (PCReg);
machine->WriteRegister (PrevPCReg, pc);
pc = machine->ReadRegister (NextPCReg);
machine->WriteRegister (PCReg, pc);
pc += 4;
machine->WriteRegister (NextPCReg, pc);
}
//----------------------------------------------------------------------
// 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.
//
// And 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
// are in machine.h.
//----------------------------------------------------------------------
void
ExceptionHandler (ExceptionType which)
{
int type = machine->ReadRegister (2);
int address = machine->registers[BadVAddrReg];
switch (which)
{
case SyscallException:
{
switch (type)
{
case SC_Halt:
{
DEBUG ('s', "Shutdown, initiated by user program.\n");
interrupt->Powerdown ();
break;
}
default:
{
printf("Unimplemented system call %d\n", type);
ASSERT(FALSE);
}
}
// Do not forget to increment the pc before returning!
UpdatePC ();
break;
}
case PageFaultException:
if (!address) {
printf("NULL dereference at PC %x!\n", machine->registers[PCReg]);
ASSERT (FALSE);
} else {
printf ("Page Fault at address %x at PC %x\n", address, machine->registers[PCReg]);
ASSERT (FALSE); // For now
}
break;
case ReadOnlyException:
printf ("Read-Only at address %x at PC %x\n", address, machine->registers[PCReg]);
ASSERT (FALSE); // For now
break;
case BusErrorException:
printf ("Invalid physical address at address %x at PC %x\n", address, machine->registers[PCReg]);
ASSERT (FALSE); // For now
break;
case AddressErrorException:
printf ("Invalid address %x at PC %x\n", address, machine->registers[PCReg]);
ASSERT (FALSE); // For now
break;
case OverflowException:
printf ("Overflow at PC %x\n", machine->registers[PCReg]);
ASSERT (FALSE); // For now
break;
case IllegalInstrException:
printf ("Illegal instruction at PC %x\n", machine->registers[PCReg]);
ASSERT (FALSE); // For now
break;
default:
printf ("Unexpected user mode exception %d %d %x at PC %x\n", which, type, address, machine->registers[PCReg]);
ASSERT (FALSE);
break;
}
}

106
code/userprog/progtest.cc Normal file
View file

@ -0,0 +1,106 @@
// progtest.cc
// Test routines for demonstrating that Nachos can load
// a user program and execute it.
//
// Also, routines for testing the Console hardware device.
//
// 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.
#include "copyright.h"
#include "system.h"
#include "console.h"
#include "addrspace.h"
#include "synch.h"
//----------------------------------------------------------------------
// StartProcess
// Run a user program. Open the executable, load it into
// memory, and jump to it.
//----------------------------------------------------------------------
void
StartProcess (char *filename)
{
OpenFile *executable = fileSystem->Open (filename);
AddrSpace *space;
if (executable == NULL)
{
SetColor (stdout, ColorRed);
SetBold (stdout);
printf ("Unable to open file %s\n", filename);
ClearColor (stdout);
return;
}
space = new AddrSpace (executable);
currentThread->space = space;
delete executable; // close file
space->InitRegisters (); // set the initial register values
space->RestoreState (); // load page table register
machine->DumpMem ("memory.svg");
machine->Run (); // jump to the user progam
ASSERT (FALSE); // machine->Run never returns;
// the address space exits
// by doing the syscall "exit"
}
// Data structures needed for the console test. Threads making
// I/O requests wait on a Semaphore to delay until the I/O completes.
static Console *console;
static Semaphore *readAvail;
static Semaphore *writeDone;
//----------------------------------------------------------------------
// ConsoleInterruptHandlers
// Wake up the thread that requested the I/O.
//----------------------------------------------------------------------
static void
ReadAvailHandler (void *arg)
{
(void) arg;
readAvail->V ();
}
static void
WriteDoneHandler (void *arg)
{
(void) arg;
writeDone->V ();
}
//----------------------------------------------------------------------
// ConsoleTest
// Test the console by echoing characters typed at the input onto
// the output. Stop when the user types a 'q'.
//----------------------------------------------------------------------
void
ConsoleTest (const char *in, const char *out)
{
char ch;
readAvail = new Semaphore ("read avail", 0);
writeDone = new Semaphore ("write done", 0);
console = new Console (in, out, ReadAvailHandler, WriteDoneHandler, NULL);
for (;;)
{
readAvail->P (); // wait for character to arrive
ch = console->RX ();
console->TX (ch); // echo it!
writeDone->P (); // wait for write to finish
if (ch == 'q') {
printf ("Nothing more, bye!\n");
break; // if q, quit
}
}
delete console;
delete readAvail;
delete writeDone;
}

18
code/userprog/progtest.h Normal file
View file

@ -0,0 +1,18 @@
// progtest.h
// Declarations for test routines for demonstrating that Nachos can load a
// user program and execute it.
//
// Also, routines for testing the Console hardware device.
//
// 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 PROGTEST_H
#define PROGTEST_H
extern void StartProcess (char *filename);
extern void ConsoleTest (const char *in, const char *out);
#endif // PROGTEST_H

135
code/userprog/syscall.h Normal file
View file

@ -0,0 +1,135 @@
/* 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"
#define USER_START_ADDRESS 0x80
/* 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_Open 5
#define SC_Read 6
#define SC_Write 7
#define SC_Close 8
#define SC_Fork 9
#define SC_Yield 10
#ifdef IN_USER_MODE
// LB: This part is read only on compiling the test/*.c files.
// It is *not* read on compiling test/start.S
/* 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 () __attribute__ ((__noreturn__));
/* Address space control operations: Exit, Exec, and Join */
/* This user program is done (status = 0 means exited normally). */
void Exit (int status) __attribute__ ((__noreturn__));
/* A unique identifier for an executing user program (address space) */
typedef int SpaceId;
/* Run the executable, stored in the Nachos file "name", and return the
* address space identifier
*/
SpaceId Exec (const char *name);
/* Only return once the the user program "id" has finished.
* Return the exit status.
*/
int Join (SpaceId id);
/* File system operations: Create, Open, Read, Write, Close
* These functions are patterned after UNIX -- files represent
* both files *and* hardware I/O devices.
*
* If this assignment is done before doing the file system assignment,
* note that the Nachos file system has a stub implementation, which
* will work for the purposes of testing out these routines.
*/
/* 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 ConsoleInput 0
#define ConsoleOutput 1
/* Create a Nachos file, with "name" */
void Create (const char *name);
/* Open the Nachos file "name", and return an "OpenFileId" that can
* be used to read and write to the file.
*/
OpenFileId Open (const char *name);
/* Write "size" bytes from "buffer" to the open file. */
void Write (const void *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 (void *buffer, int size, OpenFileId id);
/* Close the file, we're done reading and writing to it. */
void Close (OpenFileId id);
/* User-level thread operations: Fork and Yield. To allow multiple
* threads to run within a user program.
*/
/* Fork a thread to run a procedure ("func") in the *same* address space
* as the current thread.
*/
void Fork (void (*func) ());
/* Yield the CPU to another runnable thread, whether in this address space
* or not.
*/
void Yield ();
#endif // IN_USER_MODE
#endif /* SYSCALL_H */