1 / 60

Nachos Instructional OS: Part 2

Nachos Instructional OS: Part 2. CS 170, Tao Yang, Fall 2012. What to learn?. How to execute a program in Nachos Produce binary MIPS code from a C program Execute this MIPS code in a tiny space Make a simple Nachos system call in a C program Project 2.

liseli
Download Presentation

Nachos Instructional OS: Part 2

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Nachos Instructional OS: Part 2 CS 170, Tao Yang, Fall 2012

  2. What to learn? • How to execute a program in Nachos • Produce binary MIPS code from a C program • Execute this MIPS code in a tiny space • Make a simple Nachos system call in a C program • Project 2. • Support the execution of multiple processes • Support multiprogramming. • System calls for process execution. • System calls for a simple file system interface.

  3. System Layers User process: Binary code User process: Binary code Nachos kernel threads Thread 1 Thread 2 Thread N Nachos OS modules (Threads mgm, File System, Code execution/memory mapping, System calls/Interrupt) MIPS Virtual Machine (Memory, Disk, Console) Base Operating System (Linux for our class)

  4. Virtual Machine Layer • under machine subdirectory. • Approximates the MIPS architecture • Can execute a sequence of MIPS instructions. registers Timer Rn page table Machine object SP PC memory

  5. Two modes of executions • User mode: execute instructions which only access the user space. • Kernel mode • kernel executes when Nachos first starts up • or when an instruction causes a trap • illegal instruction, • page fault • system call Nachos layer

  6. Code execution steps in Nachos User binary code • Load instructions into the machine's memory. • Initialize registers (program counter, etc). • Tell the machine to start executing instructions. • The machine fetches the instruction, decodes it, and executes it. • Repeat until all instructions are executed. Handle interrupt/page fault when needed Nachos Nachos execution layer MIPS Machine

  7. Machine Object: Implement a MIPS machine • an instance created when Nachos starts up. • Supported public variables: • Registers: 40 registers. • 4KB Memory: Byte-addressable. 32 pages (128Bytes) • Virtual memory: use a single linear page table or a software-managed TLB. Rn page table Machine object SP PC memory

  8. Code/machine/machine.h class Machine { char *mainMemory; // physical memory to store user program, // code and data, while executing int registers[NumTotalRegs]; // CPU registers, for executing user programs TranslationEntry *pageTable; unsigned int pageTableSize;

  9. Machine Object: Supported operations • Machine(bool debug);//allocate memory of 32 pages (128bytes per page). Initialize memory/register/ page table • Translate(int virtAddr, int* physAddr, int size, bool writing); • OneInstruction(); // Run one instruction of a user program. • Run(); // Run a user program • ReadRegister(int num); • WriteRegister(int num, int value); • ReadMem(int addr, int size, int* value); • WriteMem(int addr, int size, int value);

  10. Code/machine/ipssim.cc void Machine::Run(){ Instruction *instr = new Instruction; // storage for decoded instruction interrupt->setStatus(UserMode); for (;;) { OneInstruction(instr); //fetch and execute one instruction interrupt->OneTick(); //advance clock } }

  11. Code/machine/machine.h class Instruction { public: void Decode(); // decode binary representation of instruction unsigned int value; // binary representation of the instruction unsigned char opCode; // Type of instruction unsigned char rs, rt, rd; // Three registers from instruction. int extra; // offset or other purpose. Treat as 0 };

  12. Code/machine/ipssim.cc Void Machine::OneInstruction(Instruction *instr) { //Fetch an instruction and then decode if (!machine->ReadMem(registers[PCReg], 4, &raw)) return; //if error, return instr->value = raw; instr->Decode(); // Execute the instruction switch (instr->opCode) { … case OP_ADDU: registers[instr->rd] = registers[instr->rs] + registers[instr->rt];break; case OP_SW: machine->WriteMem(registers[instr->rs], 4, registers[instr->rt]); break; … case OP_SYSCALL: RaiseException(SyscallException, 0); return; … } // Advance program counters. registers[PCReg] = registers[NextPCReg]; registers[NextPCReg] = pcAfter; //which is registers[NextPCReg] + 4; }

  13. Code/machine/translate.cc bool Machine::WriteMem(int addr, int size, int value) { ExceptionType exception; int physicalAddress; exception = Translate(addr, &physicalAddress, size, TRUE);//address translation if (exception != NoException) { machine->RaiseException(exception, addr); return FALSE; } switch (size) { //Copy value to the target physical memory address properly case 1: machine->mainMemory[physicalAddress] = (unsigned char) (value & 0xff); break; case 2: *(unsigned short *) &machine->mainMemory[physicalAddress] = ShortToMachine((unsigned short) (value & 0xffff)); break; case 4: …. } } bool Machine::ReadMem(int addr, int size, int *value) { … }

  14. A Simple Page Table process page table PFN 0 PFN 1 Each process has its own page table. Virtual addresses are translated relative to the current page table. PFN i PFN i + offset page #i offset user virtual address physical memory page frames

  15. Code/machine/translate.cc Physical page use bit | dirty bit ExceptionType Machine::Translate(int virtAddr, * physAddr, size, writing) { unsigned int vpn, offset; TranslationEntry *entry; unsigned int pageFrame; // calculate virtual page number, and offset within the page vpn = (unsigned) virtAddr / PageSize; offset = (unsigned) virtAddr % PageSize; entry = &pageTable[vpn]; pageFrame = entry->physicalPage; entry->use = TRUE; // set the use, dirty bits if (writing) entry->dirty = TRUE; *physAddr = pageFrame * PageSize + offset; // compute physical address return NoException; }

  16. Virtual Machine Layer registers Timer Rn page table Machine object SP PC memory Interrupt

  17. Interrupt Object • Maintain an event queue with a simulated clock. • Supported operations: • Schedule(VoidFunctionPtr handler, int arg, int when, IntType type) Schedule a future event to take place at time ``when''. • Usage: schedule a yield at random interval. • SetLevel(IntStatus level). Used to temporarily disable and re-enable interrupts. Two levels are supported: IntOn and IntOff. • OneTick()—advance 1 clock tick • CheckIfDue(bool advanceClock). Examines if some event should be serviced. • Idle(). ``advances'' to the clock to the time of the next scheduled event

  18. Interrupt::OneTick() • Software managed clock. • The clock advances 1 tick for user mode, 10 for system mode • after every restored interrupt (disable/enable Interrupt) • or after the MIPS simulator executes one instruction. • When the ready list is empty, fast-advance ticks until the next scheduled event happens.

  19. Timer object • Generate interrupts at regular or random intervals • Then Nachos invokes the predefined clock event handling procedure. • Supported operation: • Timer(VoidFunctionPtr timerHandler, int callArg, bool doRandom). • Create a real-time clock that interrupts • every TimerTicks (100) time units • Or set this a random number for random mode

  20. Console Object • Simulates the behavior of a character-oriented CRT device • Data can be written to the device one character at a time through the PutChar() routine. • Input characters arrive one-at-a-time. They can be retrieved by GetChar(). • Supported operations: • Console(char *readFile, char *writeFile, VoidFunctionPtr readAvail,VoidFunctionPtr writeDone, int callArg). Create a console instance.``readFile'' is the Unix file of where the data is to be read from; if NULL, standard input is assumed. • PutChar(char ch) • GetChar()

  21. Disk Object • Simulates the behavior of a real disk. • The disk has only a single platter, with multiple tracks (32). • Each track contains the same number of sectors (32). • Allow only one pending operation at a time. • Contain a ``track buffer'' cache. Immediately after seeking to a new track, the disk starts reading sectors, placing them in the track buffer. • Supported operations: • Disk(char *name, VoidFunctionPtr callWhenDone, int callArg) • ReadRequest(int sectorNumber, char *data) • WriteRequest(int sectorNumber, char *data) • ComputeLatency(int newSector, bool writing)

  22. data Executing a user program halt user space MIPS instructions executed by the emulator ExceptionHandler() Nachoskernel MIPS emulator Machine::Run() fetch/execute examine/deposit SaveState/RestoreState examine/deposit Rn page table process page tables Machine object SP PC memory registers

  23. data data data data data From C program to MIPS binary myprogram.c myprogram.o object file int j; char* s = “hello\n”; int p() { j = write(1, s, 6); return(j); } assembler libraries and other objects linker ….. p: store this store that push jsr _write ret etc. gcc compiler program myprogram.s myprogram (executable file)

  24. Binary code format (Noff) Source code: under userprog subdirectory. • Current Nachos can run a single MIPS binary (Noff format) • type ``nachos -x ../test/halt''. • A user program must be compiled using a cross-platform gcc compiler that generates MIPS code. • A Noff-format file contains (bin/noff.h) • the Noff header, describes the contents of the rest of the file • executable code segment (TEXT) • initialized data segment (DATA) • uninitialized data segment (BSS).

  25. STACK HEAP BSS DATA TEXT Space usage during execution of a C program Stack grows from top-down. Heap grows bottom-up Uninitialized data Initialized data Code

  26. TEXT, DATA, BSS, HEAP, STACK in C Int f3=3; /* DATA segment */ Int f1; /*BSS segment*/ def[] = "1"; /* DATA segment */ int main(void){static char abc[12], /* BSS segment */static float pi = 3.14159; /* DATA segment */int i = 3; /* Stack*/ char *cp; /*stack*/ cp= malloc(10); /*malloc allocates space from HEAP*/ f1= i+f3; /* code is in TEXT*/ strcpy(abc , "Test" ); /* “Test” is located in DATA segment */ }

  27. Noff format . Each segment has the following information: • virtualAddr: virtual address that segment begins at. • inFileAddr: Pointer within the Noff file where that section actually begins. • The size (in bytes) of that segment.

  28. User process for executing a program A Nachos thread is extended as a process • Each process has its own address space containing • Executable code (Code segment) • Initialized data (Data segment) • Uninitialized data (BSS) • Stack space for function calls/local variables • how big is address space? • A process owns some other objects, such as open file descriptors.

  29. Steps in User process creation Currently only execute a single user program. • Create an address space. • Zero out all of physical memory (machine->mainMemory) • Read the binary into physical memory and initialize data segment. • Initialize the translation tables to do a one-to-one mapping between virtual and physical addresses. • Zero all registers, setting PCReg and NextPCReg to 0 and 4 respectively. • Set the stackpointer to the largest virtual address of the process (stack grows downward).

  30. Key Calling graph when Nachos executes under userprog directory Executable file ReadAt() Space= New AddrSpace() in addrspace.cc Initialize() in system.cc Machine-> WriteRegister() Space-> InitRegisters() main() in main.cc StartProcess () in progtest.cc Space ->RestoreState() Machine-> OneInstruction() Machine->Run () in mipssim.cc Interupt-> OneTick() In Interupt.cc

  31. Creating a Nachos Process (code/userprog/progtest.cc) Create a handle for reading text and initial data out of the executable file. void StartProcess(char *filename) { OpenFile *executable; AddrSpace *space; executable = fileSystem->Open(filename); if (executable == NULL) { printf("Unable to open file %s\n", filename); return; } space = new AddrSpace(executable); currentThread->space = space; delete executable; // close file space->InitRegisters(); space->RestoreState(); machine->Run(); ASSERT(FALSE); } Create an AddrSpace object, allocating physical memory and setting up the process page table. Set address space of current thread/process. Initialize registers, load pagetable, and begin execution in user mode.

  32. Creating a Nachos Address Space (code/userprog/addrspace.cc) AddrSpace::AddrSpace(OpenFile *executable) { NoffHeader noffH; unsigned int i, size; executable->ReadAt((char *)&noffH, sizeof(noffH), 0); // how big is address space? size = noffH.code.size + noffH.initData.size + noffH.uninitData.size + UserStackSize; // we need to increase the size to leave room for the stack numPages = divRoundUp(size, PageSize); size = numPages * PageSize; pageTable = new TranslationEntry[numPages]; for (i = 0; i < numPages; i++) { pageTable[i].virtualPage = i; // for now, virtual page # = phys page # pageTable[i].physicalPage = i; pageTable[i].valid = TRUE; } .... Read the header of binary file Compute address space need Setup a page table for address translation

  33. Initializing a Nachos Address Space Zero out memory allocated bzero(machine->mainMemory, size); // copy in the code and data segments into memory if (noffH.code.size > 0) { executable->ReadAt(&(machine->mainMemory[noffH.code.virtualAddr]), noffH.code.size, noffH.code.inFileAddr); } if (noffH.initData.size > 0) { executable->ReadAt(&(machine->mainMemory[noffH.initData.virtualAddr]), noffH.initData.size, noffH.initData.inFileAddr); } Copy code segment to memory Copy initialized data segment to memory

  34. Compilation of halt.c halt.s: ssembly code of halt.c • Test/halt.c: #include "syscall.h" main() { Halt(); /* not reached */ } gcc -S main: …. jal Halt … Test/start.s … Halt: addiu $2,$0,SC_Halt syscall j $31 .end Halt start.s has system call entries. System call number is always in register 2

  35. Nachos –x halt using halt.c in test directory Machine-> RaiseException(SyscallException) Machine-> OneInstruction() Machine->Run () in mipssim.cc ExceptionHandler(SyscallException) Interrupt-> Halt() In Interupt.cc

  36. Code/userprog/exception.cc ExceptionType Machine::Translate(int virtAddr, * physAddr, size, writing) { void ExceptionHandler(ExceptionType which) { int type = machine->ReadRegister(2); if ((which == SyscallException) && (type == SC_Halt)) { DEBUG('a', "Shutdown, initiated by user program.\n"); interrupt->Halt(); } } // Code Convention: // system call code -- r2 // arg1 -- r4, arg2 -- r5, arg3 -- r6, arg4 -- r7

  37. Summary: actions of “nachos –x halt” • The main thread starts by running function StartProcess() in file progtest.cc. This thread is used to run halt binary. • StartProcess() allocates a new address space and loads the halt binary. It also initializes registers and sets up the page table. • Call Machine::Run() to execute the halt binary using the MIPS emulator. • The halt binary invokes the system call Halt(), which causes a trap back to the Nachos kernel via functions RaiseException() and ExceptionHandler(). • The exception handler determines that a Halt() system call was requested from user mode, and it halts Nachos.

  38. Assignment 2: Multiprogramming&System Calls • Modify source code under userprog subdirectory. • ~1200 lines of code. • The crossplatform compiler is under ~cs170/gcc/. • This compiler on x86 machines produces a.out with the coff format. • Use utility coff2noff (under nachos’ bin directory) to convert it as Noff. • Check the makefile under test subdirectory on how to use gcc and coff2noff. • System calls to be implemented: • Multiprogramming: Fork(), Yield(), Exit(), Exec() and Join(). • File and console I/O: Creat(), Open(), Read(), Write(), and Close(). • Test program: ~cs170/sample/PROJECT2/test

  39. 0 0 0 text text text data data data data data data BSS BSS BSS user stack user stack user stack Multi-Processes and the Kernel Fork or Exec 2n-1 0 Nachos kernel 2n-1

  40. To run multiple processes Nachos should • Provide the physical memory management; • Fill memory with proper data, instruction. • Set up an address translation table with linear page tables; • Save/restore address-space related state during process switching (AddrSpace::SaveUserState() and AddrSpace:RestoreUserState() are called).

  41. Assignment 2: Files involved • Key files. (Red for modification/extension) • progtest.cc -- test routines to run user code. • addrspace.h addrspace.cc -- create an address space and load the program from disk. • syscall.h -- the system call interface. • exception.cc -- the handler for system calls and other user-level exceptions such as page faults. • filesys.h, openfile.h console.h -- interface to the Nachos file system and console. • Other related files: • bitmap.h bitmap.cc -- manipulate bitmsps (useful for keeping track of physical page frames). • translate.h, translate.cc -- translation tables. • machine.h, machine.cc -- emulates main memory, processor, etc. • mipsim.cc -- emulates MPIS R2/3000 instructions. • console.cc -- emulates a terminal using UNIXfiles.

  42. Assignment 2: Implementation Notes Tao Yang

  43. Part I: Multiprogramming • Fork(func) creates a new user-level (child) process, whose address space starts out as an exact copy of that of the caller (the parent), • Yield(): temporarily relinquish the CPU to another process. • Exit(int) call takes a single argument, which is an integer status value as in Unix. The currently executing process is terminated. • Exec(filename) spawns a new user-level thread (process), but creates a new address space. It should return to the parent a SpaceId. • Join(ID) call waits and returns only after a process with the specified ID has finished.

  44. Getting Started • Review start.s (under test directory) which includes all system call stubs, following the style of Halt. • Modify ExceptionHandler() in exception.cc to include all system call entries. • After each system call, increment PC registers so that ExceptionHandler() execution flow returns back to next instruction after user’s system call place. • counter = machine->ReadRegister(PCReg); • machine->WriteRegister(PrevPCReg,counter); • counter = counter + 4; machine->WriteRegister(PCReg,counter); • counter = counter + 4; machine->WriteRegister(NextPCReg,counter); • Arguments of a system call are in Registers 4, 5, 6 etc. • how to verify? You may review MPIS assembly code produced for a test C program using gcc with -S. • If needed, return result is register 2 • machine->WriteRegister(2,result);

  45. PCB (Process Control Block) • Write the PCB and a process manager. Create a PCB class that will store the necessary information about a process. Don't worry about putting everything in it right now, you can always add more as you go along. To start, it should have a PID, parent PID, and Thread*. • The process manager- it can have getPID and clearPID methods, which return an unused process id and clear a process id respectively.

  46. Memory Manager • Write a Memory Manager that will be used to facilitate memory allocation: • Track memory page usage. • Allocate a page • Free a page • Modify AddrSpace:AddrSpace (addrspace.cc) to use the memory manager. • Modify the page table constructors to use pages allocated by your memory manager • Create a PCB (process control block) also for each process to include key control information.

  47. AddSpace.cc • Write a function (e.g. AddrSpace::Translate), which converts a virtual address to a physical address. It does so by breaking the virtual address into a page table index and an offset. • Write a function( e.g. AddrSpace::ReadFile), which loads the code and data segments into the translated memory, instead of at position 0. • Read data into a system buffer (diskBuffer). • Copy buffered data into proper memory locations (e.g. at machine->mainMemory[physAddr].)

  48. 0 0 0 text text text data data data data data data BSS BSS BSS user stack user stack user stack How to Run User Processes Concurrently? Forked process Forked process Main program 2n-1 … Machine->run() … … Machine->run() … … Machine->run() … 0 Nachos Kernel Threads 2n-1

  49. Compilation of a fork program Assembly code #include "syscall.h“ FunEntry(){} main() { Fork(FuncEntry); Fork(FuncEntry); } gcc -S FuncEntry: … main: ... la $4, FuncEntry jal Fork … la $4, FuncEntry jal Fork … Test/start.s … Fork: addiu $2,$0,SC_Fork syscall j $31 .end Fork … System call number is in register 2. Argument 1 is in register 4

  50. Questions on Forking a Process • When to spawn a new kernel thread? • Do we directly use thread fork function to execute the binary of a child? • Thread->Fork(FuncEntry, NULL)? • Thread->Fork(Machine->Run, NULL)? • Who needs to set the program counter for the new process? Parent thread vs child thread? Machine-> RaiseException(SyscallException) Machine-> OneInstruction() Machine->Run () in mipssim.cc ExceptionHandler(SyscallException)

More Related