User programs invoke system calls by executing the MIPS syscall instruction, which causes the Nachos kernel exception handler to be invoked (with the cause register set to Processor.exceptionSyscall). The kernel must first tell the processor where the exception handler is by calling Machine.processor().setExceptionHandler().
The default Kernel exception handler, UserKernel.exceptionHandler(), reads the value of the processor’s cause register, determines the current process, and invokes handleException on the current process, passing the cause of the exception as an argument. Again, for a syscall, this value will be Processor.exceptionSyscall.
The syscall instruction indicates a system call is requested, but doesn’t indicate which system call to perform. By convention, user programs place the value indicating the particular system call desired into MIPS register r2 (the first return register, v0) before executing the syscall instruction. Arguments to the system call, when necessary, are passed in MIPS registers r4 through r7 (i.e. the argument registers, a0 ... a3), following the standard C procedure call convention. Function return values, including system call return values, are expected to be in register r2 (v0) on return. Only the halt system call has been implemented, you will be asked to complete the implementation of the method UserProcess.handleSyscall for other system calls. Note that the registers do NOT store the values of the arguments, rather, the virtual memory locations of these arguments. For example, consider a method that handles open system call. From test/syscall.h, we have
Thus, there should only be one argument to the method, say, handleOpen(int name). To get the actual string that stores the file name to be opened, one can use the method UserProcess.readVirtualMemoryString(name, maxFileNameLength), where maxFileNameLength is the (programmer defined maximum length of file names).