Lab 3: System Calls and Exception Handling
Computer Science 377
Due: Monday, April 5, 1:00 PM


Please start immediately on this assignment. You will not be able to complete it in a single day.

The second phase of Nachos is to implement system calls. As in the first assignment, we give you some of the code you need; your job is to complete the system and enhance it. This document first describes the features and files in Nachos that you need to focus on for this assignment.

This lab is very much linked to the next one (multiprogramming support in Nachos). Both of these labs are very challenging and we strongly encourage you to form teams of two.

Understanding the Nachos Software, Part II

Before attempting to understand this assignment, you must first understand the parts of Nachos that you will need to work with. Read the following material before attempting to understand the assignment:

Once you understand the relevant portions of Nachos, read the remainder of this handout in its entirety before beginning your project.

In this assignment, you will implement system calls and exception handling for Nachos. You will be working with the simulated CPU that is provided by Nachos. We use a simulated CPU, because we want complete control over how many instructions are executed at a time, how the address spaces work, and how interrupts and exceptions (including system calls) are handled. The Nachos CPU simulates a MIPS chip. The simulator can run normal C programs (except that floating point operations are not supported and the only system calls supported are the ones that you implement). At present, Nachos is a uniprogramming operating system; it can run a single C program at a time. As a test case, we've provided you with a trivial user program, halt; all halt does is to turn around and ask the operating system to shut the machine down. Run the program

nachos -x ../test/halt
from the userprog directory. As before, trace what happens as the user program gets loaded, runs, and invokes a system call.

See the Makefile in the `test' subdirectory for an example of how to generate an executable program for Nachos. Among other things, this Makefile can generate the executable for halt. Briefly, C programs are compiled and linked using gcc and gld (with special flags) and are then converted to Nachos object file format (noff) using coff2noff, a utility provided by Nachos. Since Nachos runs ordinary C programs, you can make your own test programs that make the system calls you are implementing. Remember that you cannot use system calls or library routines that use system calls in your test programs. This means you cannot put printf statements in your test programs, for example.

You will be working mostly in the userprog directory. You must become familiar with the following Nachos files:

addrspace.h, (found in the userprog directory)
create and destroy address spaces for user programs.

syscall.h (found in the userprog directory)
the system call interface. This file contains the signatures of the system calls you must implement and the codes that represent each system call when ExceptionHandler is called.

exception.cc (found in the userprog directory)
The handler for system calls and other user-level exceptions, such as page faults. In the code we supply, only the `halt' system call is supported. This file explains how parameters are passed to system calls, where return results should be placed, and other useful hints on implementing the system calls.

filesys.h, openfile.h (found in the filesys directory)
a stub defining the Nachos file system routines. For this assignment, we have implemented the Nachos file system by directly making the corresponding calls to the UNIX file system. This mechanism prevents you from needing to write the file system as well.

machine.h (found in the machine directory)
Emulates the part of the machine that executes user programs: main memory, processor registers, etc. You need to be able to read and write registers to retrieve the parameters from system calls and return values from system calls.

console.h (found in the machine directory)
emulates a terminal device using UNIX files. A terminal is (i) byte oriented, (ii) incoming bytes can be read and written at the same time, and (iii) bytes arrive asynchronously (as a result of user keystrokes), without being explicitly requested. You will call the methods provided here from your SynchConsole class.

system.cc (found in the threads directory)
The file that initializes global variables when Nachos starts and cleans up before Nachos halts. If you add any new global variables, they should be initialized in the Initialize method in system.cc.

The Assignment

The items of the assignment are listed in the order in which you should attempt them. Later ones are either more difficult or build upon earlier ones.

  1. (10 points each) Implement system calls that interface to the file system. The signatures of the system calls are defined in syscall.h. Your implementation goes in ExceptionHandler in exception.cc. (See how halt is defined in syscall.h and implemented in exception.cc.)

    Your system call implementations should check the parameters passed in to make sure they are legal and then call the equivalent kernel routines already implemented in filesys/filesys.h and filesys/openfile.h. Note that we are using the stub implementation of the file system for this assignment.

    Create
    Create a file. Remember to copy the filename from the user specified string to a kernel string. The file exception.cc contains the function UserToKernelString which can be used for this purpose.

    Open
    Open a file. Keep track of the ids of the opened files so that exit can close them. You should allow up to 16 files to be open at one time. Remember to copy the filename from the user specified string to a kernel string.

    Close
    Close a file. Remember to update the list of opened files.

    Read
    Read from a file. Remember to copy the contents from the kernel buffer to the user buffer after reading. The file exception.cc contains a function, KernelToUser, which can be used for this purpose.

    Write
    Write to a file. Remember to copy the contents from the user buffer to the kernel buffer before writing. The file exception.cc contains a function, UserToKernel, which can be used for this purpose.

    Length
    Return the length of a file.

  2. (10 points) Implement the Exit system call.

    Exit
    Exit the user's program. Look at StartProcess in progtest.cc in the userprog directory to understand how nachos starts up and executes user programs to help you understand what you need to do to exit one. Remember to close all the files that the process opened. (Since we are not implementing fork in this lab, it is safe for you to assume that a user's program only contains one thread.)

  3. (10 points) Implement exception handlers for all the exceptions defined in machine.h. For all exceptions except SyscallException, your exception handlers should print an error message and exit the user's program.

  4. (10 points) Implement a SynchConsole class. This provides synchronous access to the simulated hardware console. The hardware console (implemented in the Console class defined in machine/console.cc) provides non-blocking PutChar and GetChar operations. These send a command to the simulated I/O hardware and immediately return without waiting for the I/O to complete. Your SynchConsole class should provide PutChar and GetChar operations that only return after the I/O is complete. The ConsoleTest procedure in progtest.cc has the beginnings of a SynchConsole implementation.

  5. (10 points) Extend your implementations of the Read and Write system calls to allow reading from and writing to the console.

    (You should not implement thread fork, yield, exec, and join.)

Note that you will need to "bullet-proof" the Nachos kernel from user program errors -- there should be nothing a user program can do to crash the operating system (with the exception of explicitly asking the system to halt). Therefore, your system call implementations should do whatever error checking is necessary to ensure that they will succeed or will cause the user's program to fail, but not nachos.

How to Turn in Lab 3

All of the following files and hard copies must be turned in to get full credit for a question.

  1. Hand in a hard copy of all the files that you modified. Remember to mark your changes:
    // Start changes
       put your changes here
    // End changes
    
    You should put all your modified files in a lab3 subdirectory of your cs377 directory.

  2. Your nachos executable (from the userprog directory should also be in the cs377/lab3 directory.

  3. Hand in a hard copy of a README file that explains your implementation for each part of the assignment. README should contain:

    Your ~/cs377/lab3 directory should also contain the README file.

Tips

Testing System Calls: Running User Programs

Here is a sample user program. You should make up your own test programs to provide more complete testing.


/* Program to test I/O */
/* Reads, writes to stdin and stdout; opens a file and writes stuff to it. */

#include "syscall.h"
#define numloop 500

int
main()
{
  int i;
  char *ch = "A";
  OpenFileId fd;
  char buffer[24];

  i= Read(buffer,2,ConsoleInput);   /* read from console */

  Write(buffer,2,ConsoleOutput);    /* write the same thing to console */

  fd = Open("pa.c.bak"); /* open a file */
  i = Read(buffer,7,fd); /* Read from it */
  Write(buffer,i,ConsoleOutput);     // write chars just read from
				     // file on the screen 
  Close(fd);

  /* Write a bunch of A's on the screen */
  for (i=0;i<numloop;i++)
     Write(ch,1,ConsoleOutput);

   Exit(0);
}

Here are the changes made to the Makefile in the test directory in order to compile the user program printa.c:

all: halt shell matmult sort printa
printa.o: printa.c
        $(CC) $(CFLAGS) -c printa.c
printa: printa.o start.o
        $(LD) $(LDFLAGS) start.o printa.o -o printa.coff
        ../bin/coff2noff printa.coff printa

In order to compile your user programs, make appropriate changes to the Makefile in the test directory and type make all at the prompt while in the test directory.