Tips for NACHOS Assignment 2
NEW:
Stuff that was going to be done in the lab Thursday, Oct. 2.
A rudimentary set of
man pages
has been made available for
the set of system calls to be implemented in Assignment 2.
Thanks to John Campbell and Peter Reissner (from the Winter 1995 class)
for the intial draft of these man pages.
All of Assignment 2 can be done inside of the directories code/userprog
and code/test.
Unlike Asssignment 1 the the clock is simulated in a much
cleaner fashion. Because user code will be executed, the clock will
advance one tick for each user instruction executed.
You probably won't be needing the Alarm for future assignments, however,
you should be able to reuse either some of what you've done or learned
in implementing the Alarm to implement multiprogramming in this assignment.
You can also get rid of the modifications I made available
(the ones in new-code) if you like.
This really is one of those assignments where you are better off
implementing little pieces at a time. In previous years too many groups
have tried to do roughly everthing at once. The result is very hard to
debug. I suggest at the very least you leave multiprogramming (time slicing)
until the very end. This way you'll be able to trace through and debug
any problems you have with your system calls without having to worry about
the kernel switching Nachos processes on you.
Also the rest of the assigments will go much more smoothly if
you have a correct implementation of the system calls - without
being able to time-slice than if you do a half debugged version
of time-slicing.
A Possible Strategy
Before you Start
-
Have a look at the
the Nachos
Roadmap document.
In particular the sections titled:
-
Look at and understand the
BitMap class
(threads/utility.h).
You may find it useful for things for this and future assignments.
-
Figure out what a Nachos address space looks like
class AddrSpace.
-
Figure out what the file format is of the Nachos executable (noff file).
Two good places to look are the source file code/bin/coff2noff.c
(which reads a COFF file and writes a NOFF file) and in the file
code/userprog/addrspace.cc (which currently reads in the different
segments of the specified program from disk, loads it into memory
starting at virtual address 0, and sets up the initial state for
it to begin execution.
A Special Tip on Improving the File System Simulation
You are not required to do this but it may help to ensure that
you don't encounter any nasty bugs in your implementation
when moving to assignment 4.
Getting Started
Implement the System Calls
The system calls to be implemented are
specified in code/userprog/syscall.h
(Fork and Yield are optional and shouldn't be attempted until everything
else is working).
NOTE: I recommend that you save time-slicing for last.
It will make debugging your code much easier.
-
Start by looking the code for and understanding how the SynchDisk
class works. Based on how access to the disk is synchronized, build
the SynchConsole class.
This will soon enable you to put debugging statements inside of your
user program (after you implement the system call Write).
Later when trying to debug other system calls you may find
it useful to periodically disable or not use the SynchConsole.
-
Look at code/test/start.s to see how the Halt function call in a user
program results in a system call.
Look at code/userprog/exceptions to see how the kernel implements
the Halt system call.
-
Implement Create, Open, Close, Write, Read.
You should probably create a file error.h that includes
error codes (that are used to specify why a system call failed).
You can even write your own version of perror if you like.
-
While implementing any of the system calls think about what
kinds of test programs to write and run to demonstrate
that they are working properly.
-
The main points/difficulties here are:
Moving parameters and data between user programs and the kernel.
Some of this can be accomplished by using
ReadRegister, WriteRegister, ReadMem, and WriteMem.
(Remember that the MIPS (target) and SUN (host) use
different byte ordering but the ReadMem and WriteMem routines
take care of that for you.)
-
A note about ReadMem and WriteMem and the next assignment.
ReadMem and WriteMem can fail for various reasons.
One of which is because the address of the user data space has
not been paged into memory or it's not part of the address space
or ...
-
In general remember that in the next assignment you will be
implementing demand paging and that user data may have to
be paged into memory before it can be used.
This may slightly affect your design for this assignment as
you should try to remember to make it relatively easy to change
portions of your implementation.
-
Implement Exec, Join, Exit.
Try to protect pages of segments to the extent possible.
However, it might be the case that a read-only segment and
a read-write segment share the same page. In this case
you obviously can't write protect the page.
(In a real system the hardware might implement a combination
of segments and paging or each segment might be page aligned.)
-
One way to test if memory is being allocated and your page tables
set up properly is to try allocating memory in reverse order.
That is, from the highest (last) page to the lowest (first) page.
(Remember Nachos currently assumes that the program is loaded into
memory at location 0.)
Test the System Calls
Implement the other Exception Handlers
-
Note that one program crashing should not affect the others
nor should it affect the execution of the operating system.
-
Note that for this assignment a page fault should never be generated
but you will be implementing a page fault handler for Assignment 3.
So you can add a stub for the the page fault exception but just
add an assertion that would cause a crash if a page fault were to be
generated.
Add Time-Slicing
-
Use a timer to generate a hardware interrupt periodically.
You should remember that the resolution of the timer is 100
clock ticks - and think about how big the quantum should be
based on this and the size of your programs, etc.
-
In your documentation you should justify your choice
of the quantum.
Retest the System Calls
-
When printing and handing in the code for the assignment
please show the .h file first followed immediately by
the corresponding .cc file.
( PLEASE: Do not list all of the .h
files followed by all of the .cc files.)
-
Try to demonstrate that two programs can clearly be
executing simulaneously and that the kernel handles
system calls properly under these circumstances.
-
The proper design of good test programs is critical here.
Things to Remember (Gotcha's)
-
Don't be afraid to modify (increase) the number of physical pages in the
the system for the purposes of running test programs,
especially when doing multiprogramming.
This is defined in code/machine.h:
#define NumPhysPages 32
-
Learn how to disassemble your code using objdump-mips or gcc-mips -S.
-
Learn to use the step function and debugging options in Nachos to step
through the execution of the user program one instruction at a time.
-
Add more debugging statements and options for different parts of the
program.
-
Some of you will notice and have trouble with
C++ syntax errors when including synch.h in addrspace.h.
It is unfortunately a problem cyclic includes/definitions in C++.
How to fix this problem
-
Remember that the addresses you get from a system call are
addresses in the user's address space. E.g., in
Write(char *buffer, int size, OpenFileId id)
buffer is an address in the user's address space.
-
Before returning from a syscall exception you must increment the
registers PCReg and NextPCReg
(see the comment in code/userprog/exception.cc).
-
See the notes on
Assignment One
for other "Things to Remember" and
for how to hand in the assignment.
Modified: Oct 11, 1995
Created: Oct 4, 1995