Monolithic Kernels and the Unix API 1
homework xv6 introduction: due Friday 2
anonymous feedback “It would be really helpful if homework directions were less vague. Things don’t have to be hard and confusing just for the sake of it. it probably is, but I can only make (probably bad) guesses about how it’s vague trying to maintain balance: giving complete homework requirements not having walls of text that no one reads not copying all the lecture material, etc. into homework writeup 3 (without saying “modify line X of fjle Y ”)
homework steps system call implementation: sys_writecount hint in writeup: imitate sys_uptime need a counter for number of writes add writecount to several tables/lists (list of handlers, list of library functions to create, etc.) recommendation: imitate how other system calls are listed create a userspace program that calls writecount recommendation: copy from given programs 4
note on locks some existing code uses acquire/release you do not have to do this only for multiprocessor support …but, copying what’s done for ticks would be correct 5
xv6 context switch and saving user mode kernel mode start trap handler save A’s user regs to kernel stack swtch() — switch kernel stacks/kernel registers exit trap handler restore B’s user regs from kernel stack 6 running A running B
where things go in context switch ‘to’ kernel stack caller-saved registers swtch arguments swtch return addr. saved ebp saved ebx saved esi saved edi fjrst %esp value trap return addr. for ‘to’ process (argument to swtch ) main ’s return addr. main ’s vars … ‘to’ user stack %esp value after return-from-exception … saved user registers saved user registers saved edi trap return addr. … caller-saved registers swtch arguments swtch return addr. saved ebp saved ebx saved esi ‘from’ kernel stack just before exception last %esp value for ‘from’ process (saved by swtch ) main ’s return addr. main ’s vars … ‘from’ user stack %esp value 7
where things go in context switch ‘to’ kernel stack caller-saved registers swtch arguments swtch return addr. saved ebp saved ebx saved esi saved edi fjrst %esp value trap return addr. for ‘to’ process (argument to swtch ) main ’s return addr. main ’s vars … ‘to’ user stack %esp value after return-from-exception … saved user registers saved user registers saved edi trap return addr. … caller-saved registers swtch arguments swtch return addr. saved ebp saved ebx saved esi ‘from’ kernel stack just before exception last %esp value for ‘from’ process (saved by swtch ) main ’s return addr. main ’s vars … ‘from’ user stack %esp value 7
trap( struct trapframe *tf) write syscall in xv6: interrupt table setup ... meaning: run in kernel mode (yes, code segments specifjes more than that — nothing we care about) vectors[T_SYSCALL] — OS function for processor to run set to pointer to assembly function vector64 trap returns to alltraps alltraps restores registers from tf , then returns to user-mode vector64: pushl $0 pushl $64 jmp alltraps vectors.S (otherwise: triggers fault like privileged instruction) alltraps: ... call trap ... iret trapasm.S void { ... trap.c set it to use the kernel “code segment” be callable from user mode via int instruction ... set the T_SYSCALL (= 0x40 ) interrupt to lidt(idt, sizeof (idt)); ... ... trap.c (run on boot) lidt — function (in x86.h) wrapping lidt instruction sets the interrupt descriptor table table of handler functions for each interrupt type (from mmu.h): // Set up a normal interrupt/trap gate descriptor. // - istrap: 1 for a trap gate, 0 for an interrupt gate. // interrupt gate clears FL_IF, trap gate leaves FL_IF alone // - sel: Code segment selector for interrupt/trap handler // - off: Offset in code segment for interrupt/trap handler // - dpl: Descriptor Privilege Level - // the privilege level required for software to invoke // this interrupt/trap gate explicitly using an int instruction. #define SETGATE(gate, istrap, sel, off, d) \ 8 SETGATE(idt[T_SYSCALL], 1, SEG_KCODE<<3, vectors[T_SYSCALL], DPL_USER);
interrupt descriptor table x86’s interrupt descriptor table has an entry for each kind of exception segmentation fault timer expired (“your program ran too long”) divide-by-zero system calls … …and they always call the trap() function 9 xv6 sets all the table entries
process control block some data structure needed to represent a process called Process Control Block xv6: struct proc 10
process control block some data structure needed to represent a process called Process Control Block xv6: struct proc 10
xv6: struct proc if waiting, }; current registers/PC of process (user and kernel) stored on (pointer to) its kernel stack (if not currently running) thread’s state the kernel stack for this process every process has one kernel stack is process running? or waiting? or fjnished? waiting for what ( chan )? char name[16]; enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; process ID to identify process in systemn calls information about address space pgdir — used by processor sz — used by OS only information about open fjles, etc. // Process name (debugging) // Current directory struct proc { // Process ID uint sz; // Size of process memory (bytes) // Page table // Bottom of kernel stack for this process enum procstate state; // Process state int pid; // Parent process // Trap frame for current syscall // swtch() here to run process // If non-zero, sleeping on chan int killed; // If non-zero, have been killed // Open files 11 pde_t* pgdir; char *kstack; struct proc *parent; struct trapframe *tf; struct context *context; void *chan; struct file *ofile[NOFILE]; struct inode *cwd;
xv6: struct proc if waiting, }; current registers/PC of process (user and kernel) stored on (pointer to) its kernel stack (if not currently running) the kernel stack for this process every process has one kernel stack is process running? or waiting? or fjnished? waiting for what ( chan )? char name[16]; enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; process ID to identify process in systemn calls information about address space pgdir — used by processor sz — used by OS only information about open fjles, etc. // Process name (debugging) // Current directory struct proc { // Trap frame for current syscall uint sz; // Size of process memory (bytes) // Page table // Bottom of kernel stack for this process enum procstate state; // Process state int pid; // Process ID // Parent process // swtch() here to run process // If non-zero, sleeping on chan int killed; // If non-zero, have been killed // Open files 11 pde_t* pgdir; char *kstack; ≈ thread’s state struct proc *parent; struct trapframe *tf; struct context *context; void *chan; struct file *ofile[NOFILE]; struct inode *cwd;
xv6: struct proc if waiting, }; current registers/PC of process (user and kernel) stored on (pointer to) its kernel stack (if not currently running) thread’s state the kernel stack for this process every process has one kernel stack is process running? or waiting? or fjnished? waiting for what ( chan )? char name[16]; enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; process ID to identify process in systemn calls information about address space pgdir — used by processor sz — used by OS only information about open fjles, etc. // Process name (debugging) // Current directory struct proc { // Process ID uint sz; // Size of process memory (bytes) // Page table // Bottom of kernel stack for this process enum procstate state; // Process state int pid; // Parent process // Trap frame for current syscall // swtch() here to run process // If non-zero, sleeping on chan int killed; // If non-zero, have been killed // Open files 11 pde_t* pgdir; char *kstack; struct proc *parent; struct trapframe *tf; struct context *context; void *chan; struct file *ofile[NOFILE]; struct inode *cwd;
xv6: struct proc if waiting, }; current registers/PC of process (user and kernel) stored on (pointer to) its kernel stack (if not currently running) thread’s state the kernel stack for this process every process has one kernel stack is process running? or waiting? or fjnished? waiting for what ( chan )? char name[16]; enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; process ID to identify process in systemn calls information about address space pgdir — used by processor sz — used by OS only information about open fjles, etc. // Process name (debugging) // Current directory struct proc { // Process ID uint sz; // Size of process memory (bytes) // Page table // Bottom of kernel stack for this process enum procstate state; // Process state int pid; // Parent process // Trap frame for current syscall // swtch() here to run process // If non-zero, sleeping on chan int killed; // If non-zero, have been killed // Open files 11 pde_t* pgdir; char *kstack; struct proc *parent; struct trapframe *tf; struct context *context; void *chan; struct file *ofile[NOFILE]; struct inode *cwd;
Recommend
More recommend