Tutorial 2
Some of the slides were borrowed from csc369 course, U of T, St George
• Use sftp to upload your file to your account
• % mkdir ~/cscc69
• You should copy your source directory (a1) cscc69
– % cd cscc69
– % cp –r [a1 path] .
• % cd a1/src
• % ./configure
– Check that you have defs.mk in your src
• Configure kernel ASST1
– % cd kern/conf
– % ./config ASST1
• Build kernel ASST1
– % cd ../compile/ASST1
– % bmake depend
– % bmake
• Install kernel ASST1
– % bmake install
• Build user level utilities
– % cd ../../..
– % bmake
– % bmake install
• Now you have kernel and user utilities.
• NOTE: you might get this error while making or installing the kernel: “warnings are treated as errors”
– In order to solve this problem: open
~/cscc69/a1/src/mk/os161.config.mk then comment out “WERROR=-Werror” and add “WERROR=“
• NOTE: you might also get an error regarding man pages
– In that case, open ~/cscc69/a1/src/man/dev/Makefile and make the changes such that you have
“MANFILES=“
• Copy a1/src/sys161.conf file to ~/cscc69/root
• Change directory to ~/cscc69/root
• Run sys161 on your OS
– % sys161 kernel
• The system boots, and you see command prompt
• Type ? To see the menu
• Type ?o for operation menu
• Type p /bin/poweroff <return> to shut down
• Debugging OS161 requires two terminals
– Run OS161 in one terminal with the debug flag
• Sys161 –w kernel
– Connect the debugger to it from another terminal
• cd ~/cscc69/root
• Os161-gdb kernel
• >target remote unix:.sockets/gdb
• Use .gdbinit files to make debugging easier
– GDB executes the files in the .gdbinit files upon startup
– You can even define blocks of statements to be executed when called at the command line in GDB
# Start example .gdbinit file.
dir /<path to A1 tree>/src/kern/arch/mips/mips
# Above line tells the debugger to parse the assembly files located in that directory. Remember to edit the path to match your source location!
define db target remote unix:.sockets/gdb
# Above line connects debugger to the waiting kernelend define syscall_time
# Defines a macro for GDB to use called "syscall_time"break syscall
# Sets a breakpoint on a function called "syscall” break sys___time
End
# End macro definition define interrupt_b break common_exception break mips_trap break mips_interrupt break exception_return
End
# End .gdbinit
• User level applications are isolated from the OS in a different protection domain
• System calls are a way of requesting the services of the
OS
– Method calls defined in user-level libraries “trap” from user-space to the OS in kernel-space
• Once control traps to the kernel, a kernel-level system call handler is invoked to service the system call and return the appropriate results to user-space
• Once the system call is complete, control is given back to the user-level application
• The trap frame is used to pass information about the exception, storing the current processor state for later execution
• The trap handler determines which syscall is being requested by looking at the corresponding code in the trap frame struct (tf->tf_a0)
• Once the syscall finishes executing, the return value or error code is put back into the trap frame (tf->tf_v0)
• Read the code: take a look at the whole call stack to get a better idea
• The MIPS syscall instruction will cause a software interruption.
• After this instruction, the hardware will automatically turn off interrupts, then jump to the code located at 0x80000080.
– From kern/arch/mips/locore/exception-mips1.S, we can see that mips_general_handler is the code that defined at 0x80000080. The assembly code here do a lot of stuff that we don’t need to care. All we need to know that they will save a trapframe on current thread’s kernel stack and call mips_trap in kern/arch/mips/locore/trap.c.
• Then if this trap (or interruption) is caused by syscall instruction, mips_trap will call syscall in kern/arch/mips/syscall/syscall.c to handle.
• Then we go to syscall function, we dispatch the syscall according to the call number, then collect the results and return.
• If every thing is OK, we go back to mips_trap, then to the assembly code common_exception and then go back to user mode.
• http://www.cdf.utoronto.ca/~csc369h/fall/docs/understanding.shtml
• Define the new system call code in src/kern/include/kern/syscall.h
• Define the prototypes for the new syscall
– Kernel space: src/kern/include/syscall.h
– User space: src/user/include
• Write the source code for it in src/kern/syscall/new_syscall.c
– Be sure to include this new file in src/kern/conf/conf.kern! (so it’s included in the build path)
• If necessary, define any new error codes in src/kern/include/kern/errno.h
• Add a case in the handler switch statement in src/kern/arch/mips/syscall/syscall.c
• Create a test program in user/testbin
• Rebuild both kernel and user level programs
• Hint: take a look at what has been done for sys___time system call. You can follow the same pattern.
• Go to this website for the description of
OS161 system calls
– http://cgi.cse.unsw.edu.au/~cs3231/10s1/os161/ man/syscall/
Name
_exit - terminate process
Library
Standard C Library (libc, -lc)
Synopsis
#include <unistd.h>
Void
_exit(int exitcode);
Description
Cause the current process to exit. The exit code exitcode is reported back to other process(es) via the waitpid() call. The process id of the exiting process should not be reused until all processes interested in collecting the exit code with waitpid have done so. (What "interested" means is intentionally left vague; you should design this.)
Return Values
_exit does not return.
• exit only take on integer argument.
• All we need to do is find our struct process entry using curthread->t_pid.
• Then indicate that “I’ve exited” and fill the exitcode. The only thing to note that the exitcode must be made using the MACROs in
/kern/include/kern/wait.h.