Discussion
Section: Wednesday, March 24, 1999
Getting
Started with Lab 3
GENERAL TIPS:
Put checks everywhere! Just because a Syscall routine gets a file ID doesn't mean the file exists. Also use ASSERTs to verify that what you think must be true is. Both of these techniques help you narrow where problems exist.
Test your code as you go along. Make up your own test cases for debug. Put debug print statements in the nacho code (exception.cc mostly) to see intermediate values because the user code is highly restricted in what it can use for IO (which is basically the console, but you can't use the console for debug until you've debugged the code).
Code for any of these routines should not exceed 25 or so lines (except for ExceptionHandler()) and many routines can be done in a dozen lines. If you are greatly exceeding this metric then you are probably doing something wrong. However, if you put a lot of checks and printouts then you will may have more.
Get started SOON, or better yet,
NOW!
Too many people waited too long before they started lab 2. Do not
make that mistake here. There will be NO
extensions and late penalties will apply.
You need to Implement some of the System Calls
Getting
Started with the Syscall Implementations...
Tips
for Create()
Tips
for Close()
close() finds a file by ID and removes it from the list of files
Tips
for Read()
Tips
for Open()
opens a file if it exists, or, if it doesn't, creates it and then opens it
Tips
for Write()
Tips
for Length()
I think you can figure this one out
by yourselves.
Tips for SyscallHalt()
Tips
for SyscallExit()
PASSING
ARGUMENTS TO SYSCALLS IS TRICKY!
Values are passed to the ExceptionHandler via registers as integers. You must cast the register values to the appropriate types in your SyscallXXX invocations.
RETURNING A VALUE IS TRICKY!
The kernel is communicating with
the user process via machine registers. See the top comments in exception.cc
that states values are returned in reg 2. Read up in machine.cc on ReadRegister
and WriteRegister. Register read and write examples are in the shell code
of exception.cc.
void ExceptionHandler(ExceptionType which)
The system call exceptions are caught by ExceptionHandler which calls the proper syscall handlers
For more info on this read:Salsa: System Calls and Exception Handling
Roadmap: System Calls and ExceptionHandling
Global
variables in threads/system.h(.cc)
Console
Sample TestCases
Write VERY simple test codes to generate some of the exceptions: divide by zero (watch out, compiler tries to optimize constants), over/underflow, etc.
/* test_DivideByZero.c such that compiler does not detect the error
*/
int main() {
int a;
int b;
int c;
a = 7;
c = a*a;
b = (a*a)/(a*a - c);
/* not reached */
}
ISSUE: Nachos does not
support printf and many other standard C library functions in user programs
(e.g., test/halt.c, test/test_DivideByZero.c). The functions that
are supported are in machine/sysdep.h(.cc). This means you won't
have the full arsenal of
C routines to debug your user programs. On the other hand, the
programs should be very simple.
Additional info about running user programs can be found.
Errata in the Given Code
Use the following code for UserToKernel and KernelToUser. The distributed code uses ReadMem/WriteMem, but they appear to have problems. The other method (also given in the distribution but commented out) works. Comment/Uncomment appropriately.
//-----------------------------------------------------------
// UserToKernel
// Copies a buffer of length from user
virtual address to a kernel
// structure.
//-----------------------------------------------------------
char *UserToKernel(char *source, int length)
{
int current=0;
int phyAddr;
char *dest;
if(!source)
return (int)0;
dest=new char[length];
while(current<length){
phyAddr=GetPhysAddrInKernel((int)source++, FALSE);
if(!phyAddr)
return 0;
dest[current++]=machine->mainMemory[phyAddr];
}
return dest;
}
//-------------------------------------------------------
// KernelToUser
// Copies a buffer of length from kernel
space to user space
//-------------------------------------------------------
void KernelToUser(char *dest, char *source, int length)
{
int current=0;
int phyAddr;
while(current<length){
phyAddr=GetPhysAddrInKernel((int)dest++, TRUE);
// dest won't get deleted if address is invalid
machine->mainMemory[phyAddr]=source[current++];
}
}