intro what is an os processes and system calls
play

intro / what is an OS / processes and system calls 1 Changelog 14 - PowerPoint PPT Presentation

intro / what is an OS / processes and system calls 1 Changelog 14 January 2020: reorganize slides to move process defjnition earlier 14 January 2020: use 64 instead of 0x40 in write() fmow chart to be more consistent with code


  1. security and protection memory-mapped devices, I/O buses, … applications application 1 memory CPU hardware 28 interrupts, memory addresses, special registers, OS’s interface operating system processes, fjles, sockets, … hardware interface threads, address spaces, s e g m e n t a t i o n f a u l t keyboard/mouse monitor disks network …

  2. goal: protection run multiple applications, and … keep them from crashing the OS keep them from crashing each other (keep parts of OS from crashing other parts?) 29

  3. mechanism 1: dual-mode operation processor has two modes: kernel (privileged) and user OS controls what runs in kernel mode 30 some operations require kernel mode

  4. mechanism 2: address translation Program B code = kernel-mode only trigger error real memory … OS data Program B data Program A data Program A code Program A (set by OS) mapping (set by OS) mapping addresses Program B addresses 31

  5. aside: alternate mechanisms dual mode operation and address translation are common today not the only ways to implement operating system features (plausibly not even the most effjcient…) 32 …so we’ll talk about them a lot

  6. hardware support for running OS: exception problem: OS needs to respond to events keypress happens? program using CPU for too long? … need hardware support because CPU is running application instructions 33

  7. problem: OS needs to respond to events keypress happens? program using CPU for too long? … hardware support for running OS: exception need hardware support because CPU is running application instructions 33

  8. exceptions and dual-mode operation rule: user code always runs in user mode rule: only OS code ever runs in kernel mode on exception : changes from user mode to kernel mode …and is only mechanism for doing so how OS controls what runs in kernel mode 34

  9. exception terminology CS 3330 terms: interrupt: triggered by external event timer, keyboard, network, … fault: triggered by program doing something “bad” invalid memory access, divide-by-zero, … traps: triggered by explicit program action system calls aborts: something in the hardware broke 35

  10. xv6 exception terms everything is a called a trap or sometimes an interrupt no real distinction in name about kinds 36

  11. real world exception terms it’s all over the place… context clues 37

  12. kernel services allocating memory? (change address space) reading/writing to fjle? (communicate with hard drive) read input? (communicate with keyboard) all need privileged instructions! 38 need to run code in kernel mode

  13. hardware mechanism: deliberate exceptions some instructions exist to trigger exceptions still works like normal exception starts executing OS-chosen handler …in kernel mode allows program requests privilieged instructions OS handler decides what program can request OS handler decides format of requests 39

  14. system call timeline (x86-64 Linux) ‘priviliged’ operations because of pointer set during boot hardware knows to go here (the “kernel”) in kernel mode (the standard library) in user mode ... testq %rax, %rax // now use return value // special instruction iret actually do read and 40 syscall_handler: // special instruction syscall mov $BUFFER_LEN, %r8 mov $buffer, %rdi mov $FILENO_stdout, %rsi mov $SYS_write, %rax (change memory layout, I/O, exceptions) allowed ‘priviliged’ operations prohibited /* set arguments in registers */ /* trigger exception */ /* ... save registers and set return value ... */ /* go back to "user" code */

  15. system call timeline (x86-64 Linux) ‘priviliged’ operations because of pointer set during boot hardware knows to go here (the “kernel”) in kernel mode (the standard library) in user mode ... testq %rax, %rax // now use return value // special instruction iret actually do read and 40 syscall_handler: // special instruction syscall mov $BUFFER_LEN, %r8 mov $buffer, %rdi mov $FILENO_stdout, %rsi mov $SYS_write, %rax (change memory layout, I/O, exceptions) allowed ‘priviliged’ operations prohibited /* set arguments in registers */ /* trigger exception */ /* ... save registers and set return value ... */ /* go back to "user" code */

  16. system call timeline (x86-64 Linux) ‘priviliged’ operations because of pointer set during boot hardware knows to go here (the “kernel”) in kernel mode (the standard library) in user mode ... testq %rax, %rax // now use return value // special instruction iret actually do read and 40 syscall_handler: // special instruction syscall mov $BUFFER_LEN, %r8 mov $buffer, %rdi mov $FILENO_stdout, %rsi mov $SYS_write, %rax (change memory layout, I/O, exceptions) allowed ‘priviliged’ operations prohibited /* set arguments in registers */ /* trigger exception */ /* ... save registers and set return value ... */ /* go back to "user" code */

  17. system call timeline (x86-64 Linux) ‘priviliged’ operations because of pointer set during boot hardware knows to go here (the “kernel”) in kernel mode (the standard library) in user mode ... testq %rax, %rax // now use return value // special instruction iret actually do read and 40 syscall_handler: // special instruction syscall mov $BUFFER_LEN, %r8 mov $buffer, %rdi mov $FILENO_stdout, %rsi mov $SYS_write, %rax (change memory layout, I/O, exceptions) allowed ‘priviliged’ operations prohibited /* set arguments in registers */ /* trigger exception */ /* ... save registers and set return value ... */ /* go back to "user" code */

  18. the classic Unix design pipes the OS? the OS? … device controllers memory management unit login… login the shell libc (C standard library) … swapping signals applications device drivers virtual memory networking fjlesystems CPU scheduler hardware hardware interface kernel system call interface utility programs standard libraries and standard library functions / shell commands 41

  19. the classic Unix design pipes the OS? the OS? … device controllers memory management unit login… login the shell libc (C standard library) … swapping signals applications device drivers virtual memory networking fjlesystems CPU scheduler hardware hardware interface kernel system call interface utility programs standard libraries and standard library functions / shell commands 41

  20. the classic Unix design pipes the OS? the OS? … device controllers memory management unit login… login the shell libc (C standard library) … swapping signals applications device drivers virtual memory networking fjlesystems CPU scheduler hardware hardware interface kernel system call interface utility programs standard libraries and standard library functions / shell commands 41

  21. aside: is the OS the kernel? OS = stufg that runs in kernel mode? OS = stufg that runs in kernel mode + libraries to use it? OS = stufg that runs in kernel mode + libraries + utility programs (e.g. shell, fjnder)? OS = everything that comes with machine? no consensus on where the line is each piece can be replaced separately… 42

  22. xv6 we will be using an teaching OS called “xv6” based on Sixth Edition Unix 43 modifjed to be multicore and use 32-bit x86 (not PDP-11)

  23. xv6 setup/assignment fjrst assignment — adding two simple xv6 system calls includes xv6 download instructions and link to xv6 book 44

  24. xv6 technical requirements you will need a Linux environment we will supply one (VM on website), or get your own (it’s probably possible to use OS X, but you need a cross-compiler and we don’t have instructions) …with qemu installed qemu (for us) = emulator for 32-bit x86 system Ubuntu/Debian package qemu-system-i386 45

  25. fjrst assignment get compiled and xv6 working …toolkit uses an emulator could run on real hardware or a standard VM, but a lot of details also, emulator lets you use GDB 46

  26. xv6: what’s included Unix-like kernel very small set of syscalls some less featureful (e.g. exit without exit status) userspace library very limited userspace programs command line, ls, mkdir, echo, cat, etc. some self-testing programs 47

  27. xv6: echo.c #include "types.h" #include "stat.h" #include "user.h" int { int i; for (i = 1; i < argc; i++) exit(); } 48 main( int argc, char *argv[]) printf(1, "%s%s", argv[i], i+1 < argc ? " " : "\n");

  28. xv6: echo.c #include "types.h" #include "stat.h" #include "user.h" int { int i; for (i = 1; i < argc; i++) printf(1, "%s%s", argv[i], i+1 < argc ? " " : "\n"); exit(); } 48 main( int argc, char *argv[])

  29. xv6: echo.c #include "types.h" #include "stat.h" #include "user.h" int { int i; for (i = 1; i < argc; i++) exit(); } 48 main( int argc, char *argv[]) printf(1, "%s%s", argv[i], i+1 < argc ? " " : "\n");

  30. xv6 demo 49

  31. xv6 demo 50

  32. + stack + stack write syscall in xv6 asm saves regs return via trap() HW switches stacks return from interrupt using syscall # from eax read args from user stack C function: sys_write() C function: syscall() ( struct trapframe ) HW switches stacks + calls C function: trap() user mode assembly func: vector64() trigger exception HW does lookup interrupt table function call: write() syscall wrapper ( int $64 ) user program kernel mode 53

  33. write syscall in xv6 C function: trap() return via trap() HW switches stacks return from interrupt using syscall # from eax read args from user stack C function: sys_write() C function: syscall() ( struct trapframe ) asm saves regs HW switches stacks + calls user mode assembly func: vector64() trigger exception HW does lookup interrupt table function call: write() syscall wrapper ( int $64 ) user program kernel mode 53 + stack + stack

  34. write syscall in xv6: user mode (partial, after macro replacement) otherwise: same as 32-bit x86 calling convention (arguments on stack ) eax = syscall number xv6 syscall calling convention: parameter ( 64 in this case) — type of exception int errupt — trigger an exception similar to a keypress usys.S ret int $T_SYSCALL movl $SYS_write, %eax write: .globl write syscall.h / traps.h ... ... 64 #define T_SYSCALL ... 16 #define SYS_write ... main.c ... 14); "Hello, World!\n", write(1, 55

  35. write syscall in xv6: user mode (partial, after macro replacement) otherwise: same as 32-bit x86 calling convention (arguments on stack ) eax = syscall number xv6 syscall calling convention: parameter ( 64 in this case) — type of exception int errupt — trigger an exception similar to a keypress usys.S ret int $T_SYSCALL movl $SYS_write, %eax write: .globl write syscall.h / traps.h ... ... 64 #define T_SYSCALL ... 16 #define SYS_write ... main.c ... 14); "Hello, World!\n", write(1, 55

  36. write syscall in xv6: user mode (partial, after macro replacement) otherwise: same as 32-bit x86 calling convention (arguments on stack ) eax = syscall number xv6 syscall calling convention: parameter ( 64 in this case) — type of exception int errupt — trigger an exception similar to a keypress usys.S ret int $T_SYSCALL movl $SYS_write, %eax write: .globl write syscall.h / traps.h ... ... 64 #define T_SYSCALL ... 16 #define SYS_write ... main.c ... 14); "Hello, World!\n", write(1, 55

  37. trap( struct trapframe *tf) write syscall in xv6: interrupt table setup ... 1: do not disable interrupts during syscalls e.g. keypress/timer handling can interrupt slow syscall vectors[T_SYSCALL] — OS function for processor to run set to pointer to assembly function vector64 eventually calls C function trap trap returns to alltraps alltraps restores registers from tf , then returns to user-mode vector64: pushl $0 pushl $64 jmp alltraps vectors.S meaning: run in kernel mode hardware jumps here alltraps: ... call trap ... iret trapasm.S void { ... trap.c (yes, code segments specifjes more than that — nothing we care about) set it to use the kernel “code segment” ... // - istrap: 1 for a trap gate, 0 for an interrupt gate. ... SETGATE(idt[T_SYSCALL], 1, SEG_KCODE<<3, vectors[T_SYSCALL], DPL_USER); ... trap.c (run on boot) lidt — function (in x86.h) wrapping lidt instruction sets the interrupt descriptor table to idt idt = array of pointers to handler functions for each exception type (plus a few bits of information about those handler functions) (from mmu.h): // Set up a normal interrupt/trap gate descriptor. // (otherwise: triggers fault like privileged instruction) 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) \ set the T_SYSCALL interrupt to be callable from user mode via int instruction 56 lidt(idt, sizeof (idt));

  38. trap( struct trapframe *tf) write syscall in xv6: interrupt table setup ... 1: do not disable interrupts during syscalls e.g. keypress/timer handling can interrupt slow syscall vectors[T_SYSCALL] — OS function for processor to run set to pointer to assembly function vector64 eventually calls C function trap trap returns to alltraps alltraps restores registers from tf , then returns to user-mode vector64: pushl $0 pushl $64 jmp alltraps vectors.S meaning: run in kernel mode hardware jumps here alltraps: ... call trap ... iret trapasm.S void { ... trap.c (yes, code segments specifjes more than that — nothing we care about) set it to use the kernel “code segment” ... // - istrap: 1 for a trap gate, 0 for an interrupt gate. lidt(idt, sizeof (idt)); ... SETGATE(idt[T_SYSCALL], 1, SEG_KCODE<<3, vectors[T_SYSCALL], DPL_USER); ... trap.c (run on boot) lidt — function (in x86.h) wrapping lidt instruction sets the interrupt descriptor table to idt idt = array of pointers to handler functions for each exception type (plus a few bits of information about those handler functions) (from mmu.h): // Set up a normal interrupt/trap gate descriptor. // (otherwise: triggers fault like privileged instruction) 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) \ set the T_SYSCALL interrupt to be callable from user mode via int instruction 56

  39. trap( struct trapframe *tf) write syscall in xv6: interrupt table setup ... 1: do not disable interrupts during syscalls e.g. keypress/timer handling can interrupt slow syscall vectors[T_SYSCALL] — OS function for processor to run set to pointer to assembly function vector64 eventually calls C function trap trap returns to alltraps alltraps restores registers from tf , then returns to user-mode vector64: pushl $0 pushl $64 jmp alltraps vectors.S meaning: run in kernel mode hardware jumps here alltraps: ... call trap ... iret trapasm.S void { ... trap.c (yes, code segments specifjes more than that — nothing we care about) set it to use the kernel “code segment” ... // - istrap: 1 for a trap gate, 0 for an interrupt gate. ... SETGATE(idt[T_SYSCALL], 1, SEG_KCODE<<3, vectors[T_SYSCALL], DPL_USER); ... trap.c (run on boot) lidt — function (in x86.h) wrapping lidt instruction sets the interrupt descriptor table to idt idt = array of pointers to handler functions for each exception type (plus a few bits of information about those handler functions) (from mmu.h): // Set up a normal interrupt/trap gate descriptor. // (otherwise: triggers fault like privileged instruction) 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) \ set the T_SYSCALL interrupt to be callable from user mode via int instruction 56 lidt(idt, sizeof (idt));

  40. trap( struct trapframe *tf) write syscall in xv6: interrupt table setup ... 1: do not disable interrupts during syscalls e.g. keypress/timer handling can interrupt slow syscall vectors[T_SYSCALL] — OS function for processor to run set to pointer to assembly function vector64 eventually calls C function trap trap returns to alltraps alltraps restores registers from tf , then returns to user-mode vector64: pushl $0 pushl $64 jmp alltraps vectors.S meaning: run in kernel mode hardware jumps here alltraps: ... call trap ... iret trapasm.S void { ... trap.c (yes, code segments specifjes more than that — nothing we care about) set it to use the kernel “code segment” ... // - istrap: 1 for a trap gate, 0 for an interrupt gate. ... SETGATE(idt[T_SYSCALL], 1, SEG_KCODE<<3, vectors[T_SYSCALL], DPL_USER); ... trap.c (run on boot) lidt — function (in x86.h) wrapping lidt instruction sets the interrupt descriptor table to idt idt = array of pointers to handler functions for each exception type (plus a few bits of information about those handler functions) (from mmu.h): // Set up a normal interrupt/trap gate descriptor. // (otherwise: triggers fault like privileged instruction) 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) \ set the T_SYSCALL interrupt to be callable from user mode via int instruction 56 lidt(idt, sizeof (idt));

  41. trap( struct trapframe *tf) write syscall in xv6: interrupt table setup ... 1: do not disable interrupts during syscalls e.g. keypress/timer handling can interrupt slow syscall vectors[T_SYSCALL] — OS function for processor to run set to pointer to assembly function vector64 eventually calls C function trap trap returns to alltraps alltraps restores registers from tf , then returns to user-mode vector64: pushl $0 pushl $64 jmp alltraps vectors.S meaning: run in kernel mode hardware jumps here alltraps: ... call trap ... iret trapasm.S void { ... trap.c (yes, code segments specifjes more than that — nothing we care about) set it to use the kernel “code segment” ... // - istrap: 1 for a trap gate, 0 for an interrupt gate. ... SETGATE(idt[T_SYSCALL], 1, SEG_KCODE<<3, vectors[T_SYSCALL], DPL_USER); ... trap.c (run on boot) lidt — function (in x86.h) wrapping lidt instruction sets the interrupt descriptor table to idt idt = array of pointers to handler functions for each exception type (plus a few bits of information about those handler functions) (from mmu.h): // Set up a normal interrupt/trap gate descriptor. // (otherwise: triggers fault like privileged instruction) 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) \ set the T_SYSCALL interrupt to be callable from user mode via int instruction 56 lidt(idt, sizeof (idt));

  42. trap( struct trapframe *tf) write syscall in xv6: interrupt table setup ... 1: do not disable interrupts during syscalls e.g. keypress/timer handling can interrupt slow syscall vectors[T_SYSCALL] — OS function for processor to run set to pointer to assembly function vector64 eventually calls C function trap trap returns to alltraps alltraps restores registers from tf , then returns to user-mode vector64: pushl $0 pushl $64 jmp alltraps vectors.S meaning: run in kernel mode hardware jumps here alltraps: ... call trap ... iret trapasm.S void { ... trap.c (yes, code segments specifjes more than that — nothing we care about) set it to use the kernel “code segment” ... // - istrap: 1 for a trap gate, 0 for an interrupt gate. ... SETGATE(idt[T_SYSCALL], 1, SEG_KCODE<<3, vectors[T_SYSCALL], DPL_USER); ... trap.c (run on boot) lidt — function (in x86.h) wrapping lidt instruction sets the interrupt descriptor table to idt idt = array of pointers to handler functions for each exception type (plus a few bits of information about those handler functions) (from mmu.h): // Set up a normal interrupt/trap gate descriptor. // (otherwise: triggers fault like privileged instruction) 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) \ set the T_SYSCALL interrupt to be callable from user mode via int instruction 56 lidt(idt, sizeof (idt));

  43. trap( struct trapframe *tf) write syscall in xv6: interrupt table setup ... 1: do not disable interrupts during syscalls e.g. keypress/timer handling can interrupt slow syscall vectors[T_SYSCALL] — OS function for processor to run set to pointer to assembly function vector64 eventually calls C function trap trap returns to alltraps alltraps restores registers from tf , then returns to user-mode vector64: pushl $0 pushl $64 jmp alltraps vectors.S meaning: run in kernel mode hardware jumps here alltraps: ... call trap ... iret trapasm.S void { ... trap.c (yes, code segments specifjes more than that — nothing we care about) set it to use the kernel “code segment” ... // - istrap: 1 for a trap gate, 0 for an interrupt gate. ... SETGATE(idt[T_SYSCALL], 1, SEG_KCODE<<3, vectors[T_SYSCALL], DPL_USER); ... trap.c (run on boot) lidt — function (in x86.h) wrapping lidt instruction sets the interrupt descriptor table to idt idt = array of pointers to handler functions for each exception type (plus a few bits of information about those handler functions) (from mmu.h): // Set up a normal interrupt/trap gate descriptor. // (otherwise: triggers fault like privileged instruction) 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) \ set the T_SYSCALL interrupt to be callable from user mode via int instruction 56 lidt(idt, sizeof (idt));

  44. trap( struct trapframe *tf) write syscall in xv6: interrupt table setup jmp alltraps con: makes writing system calls safely more complicated (what if keypress handler runs during system call?) pro: slow system calls don’t stop timers, keypresses, etc. from working non-system call exceptions: interrupts disabled vectors[T_SYSCALL] — OS function for processor to run set to pointer to assembly function vector64 eventually calls C function trap trap returns to alltraps alltraps restores registers from tf , then returns to user-mode vector64: pushl $0 pushl $64 ... 1: do not disable interrupts during syscalls vectors.S hardware jumps here alltraps: ... call trap ... iret trapasm.S void { ... trap.c e.g. keypress/timer handling can interrupt slow syscall (yes, code segments specifjes more than that — nothing we care about) ... // ... SETGATE(idt[T_SYSCALL], 1, SEG_KCODE<<3, vectors[T_SYSCALL], DPL_USER); ... trap.c (run on boot) lidt — function (in x86.h) wrapping lidt instruction sets the interrupt descriptor table to idt idt = array of pointers to handler functions for each exception type (plus a few bits of information about those handler functions) (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 meaning: run in kernel mode // - 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) \ set the T_SYSCALL interrupt to be callable from user mode via int instruction (otherwise: triggers fault like privileged instruction) set it to use the kernel “code segment” 57 lidt(idt, sizeof (idt));

  45. write syscall in xv6: interrupt table setup jmp alltraps (yes, code segments specifjes more than that — nothing we care about) 1: do not disable interrupts during syscalls e.g. keypress/timer handling can interrupt slow syscall vectors[T_SYSCALL] — OS function for processor to run set to pointer to assembly function vector64 eventually calls C function trap trap returns to alltraps alltraps restores registers from tf , then returns to user-mode vector64: pushl $0 pushl $64 ... ... vectors.S hardware jumps here alltraps: ... call trap ... iret trapasm.S void { ... trap.c meaning: run in kernel mode set it to use the kernel “code segment” (otherwise: triggers fault like privileged instruction) be callable from user mode via int instruction ... SETGATE(idt[T_SYSCALL], 1, SEG_KCODE<<3, vectors[T_SYSCALL], DPL_USER); ... trap.c (run on boot) lidt — function (in x86.h) wrapping lidt instruction sets the interrupt descriptor table to idt idt = array of pointers to handler functions for each exception type (plus a few bits of information about those handler functions) (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) \ set the T_SYSCALL interrupt to 58 lidt(idt, sizeof (idt)); trap( struct trapframe *tf)

  46. interrupt type, application registers, … write syscall in xv6: the trap function } what operation to do for program uses myproc()->tf to determine syscall() — actual implementations much more on this later in semester represents currently running process myproc() — pseudo-global variable example: tf >eax = old value of eax struct trapframe — set by assembly trap.c ... void } return ; exit(); syscall(); exit(); { 59 trap( struct trapframe *tf) if (tf − >trapno == T_SYSCALL){ if (myproc() − >killed) myproc() − >tf = tf; if (myproc() − >killed)

  47. write syscall in xv6: the trap function void what operation to do for program uses myproc()->tf to determine syscall() — actual implementations much more on this later in semester represents currently running process myproc() — pseudo-global variable struct trapframe — set by assembly trap.c } ... } return ; exit(); syscall(); exit(); { 59 trap( struct trapframe *tf) interrupt type, application registers, … if (tf − >trapno == T_SYSCALL){ example: tf − >eax = old value of eax if (myproc() − >killed) myproc() − >tf = tf; if (myproc() − >killed)

  48. interrupt type, application registers, … write syscall in xv6: the trap function } what operation to do for program uses myproc()->tf to determine syscall() — actual implementations much more on this later in semester represents currently running process myproc() — pseudo-global variable example: tf >eax = old value of eax struct trapframe — set by assembly trap.c ... void } return ; exit(); syscall(); exit(); { 59 trap( struct trapframe *tf) if (tf − >trapno == T_SYSCALL){ if (myproc() − >killed) myproc() − >tf = tf; if (myproc() − >killed)

  49. interrupt type, application registers, … write syscall in xv6: the trap function } what operation to do for program uses myproc()->tf to determine syscall() — actual implementations much more on this later in semester represents currently running process myproc() — pseudo-global variable example: tf >eax = old value of eax struct trapframe — set by assembly trap.c ... void } return ; exit(); syscall(); exit(); { 59 trap( struct trapframe *tf) if (tf − >trapno == T_SYSCALL){ if (myproc() − >killed) myproc() − >tf = tf; if (myproc() − >killed)

  50. write syscall in xv6: the syscall function } else { copies tf >eax into %eax ) (assembly code this returns to result assigned to eax store result in user’s eax register call sys_…function from table (if system call number in range) ‘ [number] value ’: syscalls[number] = value array of functions — one for syscall syscall.c ... if (num > 0 && num < NELEM(syscalls) && syscalls[num]) { static int (*syscalls[])( void ) = { ... { syscall( void ) void ... }; ... sys_write, [SYS_write] ... 60 num = curproc − >tf − >eax; curproc − >tf − >eax = syscalls[num]();

  51. write syscall in xv6: the syscall function } else { copies tf >eax into %eax ) (assembly code this returns to result assigned to eax store result in user’s eax register call sys_…function from table (if system call number in range) ‘ [number] value ’: syscalls[number] = value array of functions — one for syscall syscall.c ... if (num > 0 && num < NELEM(syscalls) && syscalls[num]) { static int (*syscalls[])( void ) = { ... { syscall( void ) void ... }; ... sys_write, [SYS_write] ... 60 num = curproc − >tf − >eax; curproc − >tf − >eax = syscalls[num]();

  52. write syscall in xv6: the syscall function } else { copies tf >eax into %eax ) (assembly code this returns to result assigned to eax store result in user’s eax register call sys_…function from table (if system call number in range) ‘ [number] value ’: syscalls[number] = value array of functions — one for syscall syscall.c ... if (num > 0 && num < NELEM(syscalls) && syscalls[num]) { static int (*syscalls[])( void ) = { ... { syscall( void ) void ... }; ... sys_write, [SYS_write] ... 60 num = curproc − >tf − >eax; curproc − >tf − >eax = syscalls[num]();

  53. write syscall in xv6: the syscall function static int (*syscalls[])( void ) = { (assembly code this returns to result assigned to eax store result in user’s eax register call sys_…function from table (if system call number in range) ‘ [number] value ’: syscalls[number] = value array of functions — one for syscall syscall.c ... } else { if (num > 0 && num < NELEM(syscalls) && syscalls[num]) { ... { syscall( void ) void ... }; ... sys_write, [SYS_write] ... 60 copies tf − >eax into %eax ) num = curproc − >tf − >eax; curproc − >tf − >eax = syscalls[num]();

  54. write syscall in xv6: sys_write } (the terminal counts as a fjle) actual internal function that implements writing to a fjle (note: 32-bit x86 calling convention puts all args on stack) (more on this later) returns -1 on error (e.g. stack pointer invalid) utility functions that read arguments from user’s stack sysfjle.c return filewrite(f, p, n); int if (argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0) int n; { sys_write( void ) 61 struct file *f; char *p; return − 1;

  55. write syscall in xv6: sys_write } (the terminal counts as a fjle) actual internal function that implements writing to a fjle (note: 32-bit x86 calling convention puts all args on stack) (more on this later) returns -1 on error (e.g. stack pointer invalid) utility functions that read arguments from user’s stack sysfjle.c return filewrite(f, p, n); int if (argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0) int n; { sys_write( void ) 61 struct file *f; char *p; return − 1;

  56. write syscall in xv6: sys_write } (the terminal counts as a fjle) actual internal function that implements writing to a fjle (note: 32-bit x86 calling convention puts all args on stack) (more on this later) returns -1 on error (e.g. stack pointer invalid) utility functions that read arguments from user’s stack sysfjle.c return filewrite(f, p, n); int if (argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0) int n; { sys_write( void ) 61 struct file *f; char *p; return − 1;

  57. write syscall in xv6: interrupt table setup jmp alltraps (yes, code segments specifjes more than that — nothing we care about) 1: do not disable interrupts during syscalls e.g. keypress/timer handling can interrupt slow syscall vectors[T_SYSCALL] — OS function for processor to run set to pointer to assembly function vector64 eventually calls C function trap trap returns to alltraps alltraps restores registers from tf , then returns to user-mode vector64: pushl $0 pushl $64 ... ... vectors.S hardware jumps here alltraps: ... call trap ... iret trapasm.S void { ... trap.c meaning: run in kernel mode set it to use the kernel “code segment” (otherwise: triggers fault like privileged instruction) be callable from user mode via int instruction ... SETGATE(idt[T_SYSCALL], 1, SEG_KCODE<<3, vectors[T_SYSCALL], DPL_USER); ... trap.c (run on boot) lidt — function (in x86.h) wrapping lidt instruction sets the interrupt descriptor table to idt idt = array of pointers to handler functions for each exception type (plus a few bits of information about those handler functions) (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) \ set the T_SYSCALL interrupt to 62 lidt(idt, sizeof (idt)); trap( struct trapframe *tf)

  58. write syscall in xv6 C function: trap() return via trap() HW switches stacks return from interrupt using syscall # from eax read args from user stack C function: sys_write() C function: syscall() ( struct trapframe ) asm saves regs HW switches stacks + calls user mode assembly func: vector64() trigger exception HW does lookup interrupt table function call: write() syscall wrapper ( int $64 ) user program kernel mode 63 + stack + stack

  59. + stack + stack write syscall in xv6 C function: trap() return via trap() HW switches stacks return from interrupt using syscall # from eax C function: sys_write() C function: syscall() ( struct trapframe ) asm saves regs HW switches stacks + calls user mode assembly func: vector64() trigger exception HW does lookup interrupt table function call: write() syscall wrapper ( int $64 ) user program kernel mode 64 read args from user stack

  60. xv6intro homework get familiar with xv6 OS add a new system call: writecount() returns total number of times write call happened 65

  61. 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 repeat, adding setwritecount 66

  62. note on locks some existing code uses acquire/release you do not have to do this only for multiprocessor support 67

  63. 68

  64. backup slides 69

  65. time multiplexing really loop.exe ssh.exe firefox.exe loop.exe ssh.exe = operating system exception happens return from exception 70

  66. time multiplexing really loop.exe ssh.exe firefox.exe loop.exe ssh.exe = operating system exception happens return from exception 70

Recommend


More recommend