Sorin Manolache Nachos – System Calls and Multiprogramming Sorin Manolache sorma@ida.liu.se 1 September 14, 2004 Sorin Manolache System Calls (1) • in exception.cc, ExceptionHandler • Create, Open, Close, Read, Write • Exec, Exit, Join • syscall signatures found in syscall.h • syscall.h exists in order to be included in your “user”-level applications (those that will be cross-compiled to MIPS code) • unfortunately, Close and Exit exist as functions in Nachos (sysdep.cc), doing something else 2 September 14, 2004 Sorin Manolache Syscall (2) kernel (inside Nachos) user (progs to be cross-compiled) void ExceptionHandler(ExceptionType which) { if (which == SyscallException) if (type == SC_OPEN) { /* your code here */ /* the name of the function that implements the system call does not necessarily need to be ‘Open’ */ /* let’s say it’s _My_Open and we call it from here */ } else if (type == SC_READ) { /* etc. */ ... } else { /* only assignment 3 */ /* treat here PageFaultExceptions */ /* they may happen if the page is not in the TLB or it is not in memory */ } } #include “syscall.h” int main(void) { /* some code */ Open(“foo”); /* system call */ } • if Open was an ordinary function, it would be like a call of a function that is found in some library (like printf, for example) • then we had to have a function called Open somewhere and to link with it • in test/start.s, Open is translated to syscall, not to call • when the MIPS emulator inside Nachos emulates the syscall MIPS instruction it will give control to ExceptionHandler. void _My_Open(...) { ... } September 14, 2004 3 Sorin Manolache User Space vs. Kernel Space (1) virtual machine->mainMemory int main(void) { 10 char *s = “foo”; Open(s); { char *b = “badluck”; 1997 } { char *n = “foobar”; 2050 } } physical physical memory 0 foo 10 1997 3000 bad 2000 bar 2100 int main(void) { char *f = “bar”; Create(f); } 3000 100 3050 luck foobar 4 September 14, 2004 Sorin Manolache User Space vs. Kernel Space (2) • Translate will do the virtual → physical address translation. You’ll never have to call it directly. ReadMem and WriteMem use it • it is not enough to translate the start address and continue reading directly from the physical memory, because of fragmentation (think of the “badluck” string) • therefore, before using some data, copy it to the kernel space (any variable in the nachos program is in the kernel space, only those in the test programs are in the user space) 5 September 14, 2004 Sorin Manolache User Space vs. Kernel Space (2) • Open, Create and Exec will transfer strings (char arrays terminated by ‘\0’ (unbounded)) from the user space to kernel space • Read will transfer byte buffers of fixed size from kernel space to user space • Write will transfer byte buffers of fixed size from user space to kernel space Hint: Create a function for each of those 3 cases September 14, 2004 6 Sorin Manolache Nachos Device Oriented System Calls (1) • OpenFileId is the handle to the files • after opening, all operations are performed by means of the handle user program: in kernel: #include “syscall.h” case SC_OPEN: ... OpenFile *ptr = filesys->Open(kFilename); /* what should we do with ptr? */ ... case SC_READ: ... ptr->Read(kBuf, size); /* where do we get the ptr from? */ ... int main(void) { char buf[20]; OpenFileId fd; /* int actually */ Create(“foo”); fd = Open(“foo”); Read(buf, sizeof(buf), fd); Close(fd); } 7 September 14, 2004 Sorin Manolache Nachos Device Oriented System Calls (2) we keep per process file descriptor tables (sound design) 0 1 2 3 0x800b0100 0xffffffff 0x800b0300 0x800b0400 we keep per OS file de- we return (int)ptr (very scriptor tables (no se- dangerous) curity) no table, the OS is un0 0x800b0100 able to perform ANY 1 0xa0100300 checks. It’s very dan2 0x800b0300 gerous a user to have 3 0x800b0400 4 0xa0100400 pointers in the kernel 5 0xffffffff space 6 0xffffffff 7 0xffffffff 0 1 2 3 0xa0100300 0xa0100400 0xffffffff 0xffffffff the user deals only with the table indexes but what if a process sends to the OS the file descriptor of a file opened by some other process? If the sent ptr is not a valid pointer to an OpenFile and we call (OpenFile*)ptr-> Read... disaster 8 September 14, 2004 Sorin Manolache Nachos Process Oriented System Calls (1) SpaceId child; /* int */ child = Exec(“foo”); create a new Thread object create an address space for it (allocate physical memory for it) load the process image (from the executable file) in the address space keep a handle to the thread or addr. space (it doesn’t matter to which of them as they are bound together) again, process table vs. pointer cast approach fork the new thread decide which should be the function to be passed to Fork (what should the new thread execute?) return the handle Exit(code); code = Join(child); September 14, 2004 destroy its addr. space (de-allocate the occupied phys. memory) let other processes know about its death if you have a global process table, store the exit code there and finish the thread, else store the exit code in the thread object and set the thread to sleep if the child has not died already register in the child’s queue of processes that wait its death and go to sleep take the exit code from where it is stored and return it 9 Sorin Manolache Nachos Process Oriented System Calls (2) • think of a mechanism of who is allowed to Wait/Join another process • proposals: – anybody, but only one or several? (Unix new solution, waitpid system call) – only the parent, if the parent dies before the child: – a grand-parent, or – the root of all processes (Unix solution) • if not anybody, then you need some additional data structures for the process genealogic tree 10 September 14, 2004 Sorin Manolache Advanced Issues – Re-entrant System Calls (not really a problem in Nachos) • what if we get an interrupt from the hardware when running in kernel mode, as a result the threads are switched, and the new thread will call the same system call as the one in service just before the switching? • make the syscalls atomic (non-pre-emptable)? but what if the syscall is extremely slow (read from a CD-ROM)? • the elegant solution is to have re-entrant system calls • as the same code may run “at the same time”, they are not allowed to share data (global or static data break re-entrance) (think at the 3 translation functions, what if the kernel buffer is unique and we get interrupted in the middle of a translation?) • make non-re-entrant code (but protect it with mutexes) only where you cannot otherwise (and make sure that those regions execute fast) 11 September 14, 2004 Sorin Manolache Multiprogramming (1) • where does the MIPS know from how to translate between virtual and physical addresses (ReadMem and WriteMem)? • each process translates its addresses according to its own translation scheme • each AddrSpace object contains its own pageTable that specifies the mapping virtual ↔ physical page • at any moment in time, machine->pageTable points to the page table of the currently running thread. The switching is already implemented (space->RestoreState called from Scheduler::Run) September 14, 2004 12 Sorin Manolache Multiprogramming (2) • allocation should be done in AddrSpace constructor • de-allocation in AddrSpace deconstructor • this time blank only your portion of memory before loading the process image (right now, the whole memory is blanked) • use a bitmap (helper class Bitmap) • each bit corresponds to a page in physical memory • Bitmap::Find will find you the first unset bit (the first free page) and it will set the bit (mark the page as taken) • Bitmap::Clear is handy when de-allocating memory 13 September 14, 2004 Sorin Manolache Virtual Memory – Assignment 3 • create a file that acts as the swap space on the disk • use another bitmap to mark free/taken pages on the swap space • use OpenFile::ReadTo and OpenFile::WriteTo for transferring pages between the physical memory (machine->mainMemory + physicalAddressOfPage) and the address on the disk • upon Exec, load as much as you can into the physical memory, mark the pages as valid, but also as dirty (trick). What does not fit in, load into the swap space, and set the page as invalid. The physicalPage field in the pageTable has different meanings depending where the page is (valid or not) 14 September 14, 2004 Sorin Manolache Virtual Memory • page fault exception: either it is not referred in the TLB but it is in the physical memory, or it is not in the physical memory • first check, may be it is only not referred in the TLB. If yes, try to refer it in the TLB, if there is no space anymore in the TLB decide which reference to remove from the TLB • if it is not at all in memory, bring it from the disk, try to load it in the physical memory, if there is no space, replace one page from the physical memory, refer it in the TLB, remove the reference to the replaced page from the TLB, update the valid bits • who to replace? – clean pages (not dirty) (they do not have to be written on disk, because the copies are identical) – pages not referred for a long time • invalidate all references in the TLB upon a switch September 14, 2004 15