Assignment 2. Multiprogramming
Introduction
The second phase of Nachos is to support multiprogramming.
As in the first assignment, we give you some of the code
you need; your job is to complete the system and enhance it.
The first step is to read and understand the part of the system
we have written for you. Our code can run a single user-level `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 -d
'
(here the `-d
' option is for printing debugging
messages). As before, trace what happens as the user program
gets loaded, runs, and invokes a system call.
The files for this assignment are:
In addition, many files in the threads and
machine directories (used in Assignment 1)
are now compiled with the USER_PROGRAM
flag turned on
so all code enclosed by the #ifdef USER_PROGRAM
statements now does matter. You should read these files again.
So far, all the code you have written for Nachos has been part of the
operating system kernel. In a real operating system, the kernel not only
uses its procedures internally, but allows user-level programs to access
some of its routines via ``system calls''.
In this assignment we are giving you a simulated CPU that models a real CPU.
In fact, the simulated
CPU is the same as the real CPU (a MIPS chip), but we cannot just run
user programs as regular UNIX processes, 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.
Our simulator can run normal programs compiled from C -- see
the Makefile in the `test' subdirectory for an example. The compiled
programs must be linked with some special flags, then converted into
Nachos format, using the program ``coff2noff'' (which we supply).
The only caveat is that floating point operations are not supported.
Problem 1
Implement system call and exception handling. You must
support all of the system calls defined in syscall.h, except
for thread fork and yield, which can be implemented for extra credit.
We have provided you an assembly-language routine, ``syscall'', to
provide a way of invoking a system call from a C routine (UNIX has
something similar -- try `man syscall'). You'll need to do part 2 of
this assignment in order to test out the `exec' and `join' system calls;
the routine `StartProcess' in progtest.cc may be of use to you in
implementing the `exec' system call.
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). Also, to support the system calls that access
the console device, you will probably find it helpful to implement
a ``SynchConsole'' class, that provides the abstraction of
synchronous access to the console. ``progtest.cc'' has the beginnings
of a SynchConsole implementation; look ahead to the file system assignment for
the similar example for the SynchDisk class.
Problem 2
Implement multiprogramming with time-slicing. The code we have given
you is restricted to running one user program at a time.
You will need to: (a) come up with a way of allocating physical memory
frames so that multiple programs can be loaded into memory at once
(cf. bitmap.h), (b) provide a way of copying data to/from the kernel
from/to the user's
virtual address space (now that the addresses the user program sees
are not the same as the ones the kernel sees), and (c) use timer interrupts
to force threads to yield after a certain number of ticks.
Note that scheduler.cc now saves and restores user machine state
on context switches.
You will probably want to write some utilities like UNIX "cp" and
"cat", and use the "shell" provided in the test subdirectory to
verify that system call handling and multiprogramming are working
properly.
Problem 3
The `exec' system call does not provide any way for the
user program to pass parameters or arguments to the newly created
address space. UNIX does allow this, for instance, to pass in command
line arguments to the new address space. Implement this feature.