changelog

Changelog Changes made in this version not seen in fjrst lecture: 3 - PowerPoint PPT Presentation

Changelog Changes made in this version not seen in fjrst lecture: 3 September 2019: xv6: where the context is: rename from/to into A/B to avoid overloading to and be consistent with the preceeding context switch picture 3 September 2019:


  1. xv6: timer interrupt void acquire/release — related to synchronization (later) (needed for all interrupts from ‘external’ devices) lapiceoi — tell hardware we have handled this interrupt ( sleep system call) certain amount of time wakeup — handle waiting processes on timer interrupt: yield = maybe switch to difgerent program if a process is running (trigger periodically by external timer): on timer interrupt } ... yield(); 19 ... ticks++; { case T_IRQ0 + IRQ_TIMER: if (cpuid() == 0){ acquire(&tickslock); wakeup(&ticks); release(&tickslock); } lapiceoi(); break ; ... // Force process to give up CPU on clock tick. trap( struct trapframe *tf) switch (tf − >trapno){ if (myproc() && myproc() − >state == RUNNING && tf − >trapno == T_IRQ0+IRQ_TIMER)

  2. xv6: timer interrupt void acquire/release — related to synchronization (later) (needed for all interrupts from ‘external’ devices) lapiceoi — tell hardware we have handled this interrupt ( sleep system call) certain amount of time wakeup — handle waiting processes on timer interrupt: yield = maybe switch to difgerent program if a process is running (trigger periodically by external timer): on timer interrupt } ... yield(); 19 ... ticks++; { case T_IRQ0 + IRQ_TIMER: if (cpuid() == 0){ acquire(&tickslock); wakeup(&ticks); release(&tickslock); } lapiceoi(); break ; ... // Force process to give up CPU on clock tick. trap( struct trapframe *tf) switch (tf − >trapno){ if (myproc() && myproc() − >state == RUNNING && tf − >trapno == T_IRQ0+IRQ_TIMER)

  3. xv6: timer interrupt void acquire/release — related to synchronization (later) (needed for all interrupts from ‘external’ devices) lapiceoi — tell hardware we have handled this interrupt ( sleep system call) certain amount of time wakeup — handle waiting processes on timer interrupt: yield = maybe switch to difgerent program if a process is running (trigger periodically by external timer): on timer interrupt } ... yield(); 19 ... ticks++; { case T_IRQ0 + IRQ_TIMER: if (cpuid() == 0){ acquire(&tickslock); wakeup(&ticks); release(&tickslock); } lapiceoi(); break ; ... // Force process to give up CPU on clock tick. trap( struct trapframe *tf) switch (tf − >trapno){ if (myproc() && myproc() − >state == RUNNING && tf − >trapno == T_IRQ0+IRQ_TIMER)

  4. xv6: timer interrupt void acquire/release — related to synchronization (later) (needed for all interrupts from ‘external’ devices) lapiceoi — tell hardware we have handled this interrupt ( sleep system call) certain amount of time wakeup — handle waiting processes on timer interrupt: yield = maybe switch to difgerent program if a process is running (trigger periodically by external timer): on timer interrupt } ... yield(); 19 ... ticks++; { case T_IRQ0 + IRQ_TIMER: if (cpuid() == 0){ acquire(&tickslock); wakeup(&ticks); release(&tickslock); } lapiceoi(); break ; ... // Force process to give up CPU on clock tick. trap( struct trapframe *tf) switch (tf − >trapno){ if (myproc() && myproc() − >state == RUNNING && tf − >trapno == T_IRQ0+IRQ_TIMER)

  5. non-system call exceptions xv6: there are traps other than system calls timer interrupt — ‘tick’ from constantly running timer make sure infjnite loop doesn’t hog CPU check for programs waiting for time to pass faults — e.g. access invalid memory xv6’s action : kill the program I/O — handle I/O 20

  6. xv6: faults void can lookup in traps.h prints out trap number assume it screwed up print message and kill running program unknown exception } } 21 "eip 0x%x addr 0x%x--kill proc\n", cprintf("pid %d %s: trap %d err %d on cpu %d " ... default : ... ... { trap( struct trapframe *tf) switch (tf − >trapno) { myproc() − >pid, myproc() − >name, tf − >trapno, tf − >err, cpuid(), tf − >eip, rcr2()); myproc() − >killed = 1;

  7. xv6: faults void can lookup in traps.h prints out trap number assume it screwed up print message and kill running program unknown exception } } 21 "eip 0x%x addr 0x%x--kill proc\n", cprintf("pid %d %s: trap %d err %d on cpu %d " ... default : ... ... { trap( struct trapframe *tf) switch (tf − >trapno) { myproc() − >pid, myproc() − >name, tf − >trapno, tf − >err, cpuid(), tf − >eip, rcr2()); myproc() − >killed = 1;

  8. non-system call exceptions xv6: there are traps other than system calls timer interrupt — ‘tick’ from constantly running timer make sure infjnite loop doesn’t hog CPU check for programs waiting for time to pass faults — e.g. access invalid memory xv6’s action : kill the program I/O — handle I/O 22

  9. xv6: I/O kbdintr(); uart = serial port (external terminal) kbd = keyboard ide = disk interface break ; lapiceoi(); uartintr(); case T_IRQ0 + IRQ_COM1: break ; lapiceoi(); case T_IRQ0 + IRQ_KBD: void ... break ; lapiceoi(); ideintr(); case T_IRQ0 + IRQ_IDE: ... ... { 23 trap( struct trapframe *tf) switch (tf − >trapno) {

  10. xv6: keyboard I/O ... (xv6 choice: usually not immediately) make it run soon fjnds process waiting on console } ... wakeup(&input.r); { void void consoleintr(...) ... } consoleintr(kbdgetc); { kbdintr( void ) 24

  11. xv6: keyboard I/O ... (xv6 choice: usually not immediately) make it run soon fjnds process waiting on console } ... wakeup(&input.r); { void void consoleintr(...) ... } consoleintr(kbdgetc); { kbdintr( void ) 24

  12. time multiplexing // whatever get_time does ... subq %rbp, %rax // whatever get_time does call get_time million cycle delay (from loop.exe’s view) movq %rax, %rbp call get_time loop.exe ... time CPU: ssh.exe loop.exe firefox.exe ssh.exe 25

  13. time multiplexing // whatever get_time does ... subq %rbp, %rax // whatever get_time does call get_time million cycle delay (from loop.exe’s view) movq %rax, %rbp call get_time loop.exe ... time CPU: ssh.exe loop.exe firefox.exe ssh.exe 25

  14. time multiplexing // whatever get_time does ... subq %rbp, %rax // whatever get_time does call get_time million cycle delay (from loop.exe’s view) movq %rax, %rbp call get_time loop.exe ... time CPU: ssh.exe loop.exe firefox.exe ssh.exe 25

  15. time multiplexing really loop.exe ssh.exe firefox.exe loop.exe ssh.exe = operating system exception happens return from exception 26

  16. time multiplexing really loop.exe ssh.exe firefox.exe loop.exe ssh.exe = operating system exception happens return from exception 26

  17. OS and time multiplexing starts running instead of normal program via exception saves old program counter, registers somewhere sets new registers, jumps to new program counter called context switch saved information called context 27

  18. context all registers values condition codes program counter address space = page table base pointer 28 %rax %rbx , …, %rsp , …

  19. contexts (A running) Process B memory: in Memory … … %rcxPC %rbxZF %raxSF OS memory: code, stack, etc. code, stack, etc. %rax Process A memory: in CPU PC ZF SF … %rsp %rcx %rbx 29

  20. contexts (B running) OS memory: on A’s kernel stack into “trapframe” exception handler xv6: A’s registers saved by in Memory … … %rcxPC %rbxZF %raxSF code, stack, etc. %rax Process B memory: code, stack, etc. Process A memory: in CPU PC ZF SF … %rsp %rcx %rbx 30

  21. contexts (B running) OS memory: on A’s kernel stack into “trapframe” exception handler xv6: A’s registers saved by in Memory … … %rcxPC %rbxZF %raxSF code, stack, etc. %rax Process B memory: code, stack, etc. Process A memory: in CPU PC ZF SF … %rsp %rcx %rbx 30

  22. exercise: counting context switches two active processes: A: running infjnite loop B: described below process B asks to read from from the keyboard after input is available, B reads from a fjle then, B does a computation and writes the result to the screen how many system calls do we expect? how many context switches do we expect? your answers can be ranges 31

  23. counting system calls (no system calls from A) B: read from keyboard maybe more than one — lots to read? B: read from fjle maybe more than one — opening fjle + lots to read? B: write to screen maybe more than one — lots to write? (3 or more from B) 32

  24. counting context switches B makes system call to read from keyboard (1) switch to A while B waits keyboard input: B can run (2) switch to B to handle input B makes system call to read from fjle (3?) switch to A while waiting for disk? if data from fjle not available right away (4) switch to B to do computation + write system call + maybe switch between A + B while both are computing? 33

  25. xv6 context switch and saving restore B’s user regs call swtch() in A; return from swtch() in B what if no space left? what if stack pointer invalid? use kernel stack to avoid disrupting user stack haven’t decided whether to context switch when saving user registers here… from kernel stack exit trap handler user mode swtch() — switch kernel stacks/kernel registers to kernel stack save A’s user regs start trap handler kernel mode 34 running A running B

  26. context switch in xv6 will mostly talk about kernel thread switch : xv6 function: swtch() save kernel registers for A, restore for B in xv6: separate from saving/restoring user registers one of many possible OS design choices additional process switch pieces: ( switchuvm() ) changing address space (page tables) telling processor new stack pointer for exceptions 35

  27. xv6: where the context is save/restore B kernel stack pointer … ‘B’ process control block save/restore on trap() entry/exit on swtch() B’s saved kernel registers args to swtch() memory used to run process A memory accessable when running process A (= address space) ‘B’ kernel stack … ‘A’ process A’s saved user registers address space ‘B’ process address space kernel-only memory … ‘A’ user stack … B’s saved user registers A’s saved kernel registers ‘A’ kernel stack A’s kernel stack pointer … ‘A’ process control block … ‘B’ user stack 37

  28. xv6: where the context is save/restore B kernel stack pointer … ‘B’ process control block save/restore on trap() entry/exit on swtch() B’s saved kernel registers args to swtch() memory used to run process A memory accessable when running process A (= address space) ‘B’ kernel stack … ‘A’ process A’s saved user registers address space ‘B’ process address space kernel-only memory … ‘A’ user stack … B’s saved user registers A’s saved kernel registers ‘A’ kernel stack A’s kernel stack pointer … ‘A’ process control block … ‘B’ user stack 37

  29. xv6: where the context is save/restore B kernel stack pointer … ‘B’ process control block save/restore on trap() entry/exit on swtch() B’s saved kernel registers args to swtch() memory used to run process A memory accessable when running process A (= address space) ‘B’ kernel stack … ‘A’ process A’s saved user registers address space ‘B’ process address space kernel-only memory … ‘A’ user stack … B’s saved user registers A’s saved kernel registers ‘A’ kernel stack A’s kernel stack pointer … ‘A’ process control block … ‘B’ user stack 37

  30. xv6: where the context is save/restore B kernel stack pointer … ‘B’ process control block save/restore on trap() entry/exit on swtch() B’s saved kernel registers args to swtch() memory used to run process A memory accessable when running process A (= address space) ‘B’ kernel stack … ‘A’ process A’s saved user registers address space ‘B’ process address space kernel-only memory … ‘A’ user stack … B’s saved user registers A’s saved kernel registers ‘A’ kernel stack A’s kernel stack pointer … ‘A’ process control block … ‘B’ user stack 37

  31. xv6: where the context is save/restore B kernel stack pointer … ‘B’ process control block save/restore on trap() entry/exit on swtch() B’s saved kernel registers args to swtch() memory used to run process A memory accessable when running process A (= address space) ‘B’ kernel stack … ‘A’ process A’s saved user registers address space ‘B’ process address space kernel-only memory … ‘A’ user stack … B’s saved user registers A’s saved kernel registers ‘A’ kernel stack A’s kernel stack pointer … ‘A’ process control block … ‘B’ user stack 38

  32. xv6: where the context is save/restore B kernel stack pointer … ‘B’ process control block save/restore on trap() entry/exit on swtch() B’s saved kernel registers args to swtch() memory used to run process A memory accessable when running process A (= address space) ‘B’ kernel stack … ‘A’ process A’s saved user registers address space ‘B’ process address space kernel-only memory … ‘A’ user stack … B’s saved user registers A’s saved kernel registers ‘A’ kernel stack A’s kernel stack pointer … ‘A’ process control block … ‘B’ user stack 38

  33. xv6: where the context is save/restore B kernel stack pointer … ‘B’ process control block save/restore on trap() entry/exit on swtch() B’s saved kernel registers args to swtch() memory used to run process A memory accessable when running process A (= address space) ‘B’ kernel stack … ‘A’ process A’s saved user registers address space ‘B’ process address space kernel-only memory … ‘A’ user stack … B’s saved user registers A’s saved kernel registers ‘A’ kernel stack A’s kernel stack pointer … ‘A’ process control block … ‘B’ user stack 38

  34. xv6: where the context is save/restore B kernel stack pointer … ‘B’ process control block save/restore on trap() entry/exit on swtch() B’s saved kernel registers args to swtch() memory used to run process A memory accessable when running process A (= address space) ‘B’ kernel stack … ‘A’ process A’s saved user registers address space ‘B’ process address space kernel-only memory … ‘A’ user stack … B’s saved user registers A’s saved kernel registers ‘A’ kernel stack A’s kernel stack pointer … ‘A’ process control block … ‘B’ user stack 38

  35. thread switching yes, it looks like we’re missing switch to context new set old to point to it allocate space for context on top of stack function to switch contexts eip = saved program counter some registers we need… structure to save context in struct context { } uint eip; uint ebp; uint ebx; uint esi; uint edi; 39 void swtch( struct context **old, struct context * new );

  36. thread switching yes, it looks like we’re missing switch to context new set old to point to it allocate space for context on top of stack function to switch contexts eip = saved program counter some registers we need… structure to save context in struct context { } uint eip; uint ebp; uint ebx; uint esi; uint edi; 39 void swtch( struct context **old, struct context * new );

  37. thread switching yes, it looks like we’re missing switch to context new set old to point to it allocate space for context on top of stack function to switch contexts eip = saved program counter some registers we need… structure to save context in struct context { } uint eip; uint ebp; uint ebx; uint esi; uint edi; 39 void swtch( struct context **old, struct context * new );

  38. thread switching yes, it looks like we’re missing switch to context new set old to point to it allocate space for context on top of stack function to switch contexts eip = saved program counter some registers we need… structure to save context in struct context { } uint eip; uint ebp; uint ebx; uint esi; uint edi; 39 void swtch( struct context **old, struct context * new );

  39. thread switching in xv6: C swtch(...); ... ... // (3) ... ... // (2) in thread A: // (0) -- called earlier in thread B: ... // (4) ... // (1) 40 /* switch from A to B */ swtch(&(a − >context), b − >context); /* returns to (2) */ /* later on switch back to A */ swtch(&(b − >context), a − >context) /* returns to (4) */

  40. thread switching in xv6: C swtch(...); ... ... // (3) ... ... // (2) in thread A: // (0) -- called earlier in thread B: ... // (4) ... // (1) 40 /* switch from A to B */ swtch(&(a − >context), b − >context); /* returns to (2) */ /* later on switch back to A */ swtch(&(b − >context), a − >context) /* returns to (4) */

  41. thread switching in xv6: C swtch(...); ... ... // (3) ... ... // (2) in thread A: // (0) -- called earlier in thread B: ... // (4) ... // (1) 40 /* switch from A to B */ swtch(&(a − >context), b − >context); /* returns to (2) */ /* later on switch back to A */ swtch(&(b − >context), a − >context) /* returns to (4) */

  42. thread switching in xv6: C swtch(...); ... ... // (3) ... ... // (2) in thread A: // (0) -- called earlier in thread B: ... // (4) ... // (1) 40 /* switch from A to B */ swtch(&(a − >context), b − >context); /* returns to (2) */ /* later on switch back to A */ swtch(&(b − >context), a − >context) /* returns to (4) */

  43. thread switching in xv6: C swtch(...); ... ... // (3) ... ... // (2) in thread A: // (0) -- called earlier in thread B: ... // (4) ... // (1) 40 /* switch from A to B */ swtch(&(a − >context), b − >context); /* returns to (2) */ /* later on switch back to A */ swtch(&(b − >context), a − >context) /* returns to (4) */

  44. thread switching in xv6: C swtch(...); ... ... // (3) ... ... // (2) in thread A: // (0) -- called earlier in thread B: ... // (4) ... // (1) 40 /* switch from A to B */ swtch(&(a − >context), b − >context); /* returns to (2) */ /* later on switch back to A */ swtch(&(b − >context), a − >context) /* returns to (4) */

  45. struct context **from_context struct context *to_context thread switching in xv6: assembly = where to fjnd new context context stored on thread’s stack context address = top of stack saved: ebp, ebx, esi, edi what about other parts of context? eax, ecx, …: saved by swtch’s caller esp: same as address of context program counter: set by call of swtch save stack pointer to fjrst argument (stack pointer now has all info) restore stack pointer from second argument restore program counter (and other saved registers) from new context = where to save current context two arguments: .globl swtch pushl %edi swtch: movl 4(%esp), %eax movl 8(%esp), %edx # Save old callee-save registers pushl %ebp pushl %ebx pushl %esi # Switch stacks ret movl %esp, (%eax) movl %edx, %esp # Load new callee-save registers popl %edi popl %esi popl %ebx popl %ebp 41

  46. thread switching in xv6: assembly esp: same as address of context = where to fjnd new context context stored on thread’s stack context address = top of stack saved: ebp, ebx, esi, edi what about other parts of context? eax, ecx, …: saved by swtch’s caller program counter: set by call of swtch .globl swtch save stack pointer to fjrst argument (stack pointer now has all info) restore stack pointer from second argument restore program counter (and other saved registers) from new context = where to save current context two arguments: ret pushl %edi swtch: movl 4(%esp), %eax movl 8(%esp), %edx # Save old callee-save registers pushl %ebp pushl %ebx pushl %esi # Switch stacks popl %ebp movl %esp, (%eax) movl %edx, %esp # Load new callee-save registers popl %edi popl %esi popl %ebx 41 struct context **from_context struct context *to_context

  47. struct context **from_context struct context *to_context thread switching in xv6: assembly = where to fjnd new context context stored on thread’s stack context address = top of stack saved: ebp, ebx, esi, edi what about other parts of context? eax, ecx, …: saved by swtch’s caller esp: same as address of context program counter: set by call of swtch save stack pointer to fjrst argument (stack pointer now has all info) restore stack pointer from second argument restore program counter (and other saved registers) from new context = where to save current context two arguments: .globl swtch pushl %edi swtch: movl 4(%esp), %eax movl 8(%esp), %edx # Save old callee-save registers pushl %ebp pushl %ebx pushl %esi # Switch stacks ret movl %esp, (%eax) movl %edx, %esp # Load new callee-save registers popl %edi popl %esi popl %ebx popl %ebp 41

  48. struct context **from_context struct context *to_context thread switching in xv6: assembly = where to fjnd new context context stored on thread’s stack context address = top of stack saved: ebp, ebx, esi, edi what about other parts of context? eax, ecx, …: saved by swtch’s caller esp: same as address of context program counter: set by call of swtch save stack pointer to fjrst argument (stack pointer now has all info) restore stack pointer from second argument restore program counter (and other saved registers) from new context = where to save current context two arguments: .globl swtch pushl %edi swtch: movl 4(%esp), %eax movl 8(%esp), %edx # Save old callee-save registers pushl %ebp pushl %ebx pushl %esi # Switch stacks ret movl %esp, (%eax) movl %edx, %esp # Load new callee-save registers popl %edi popl %esi popl %ebx popl %ebp 41

  49. struct context **from_context struct context *to_context thread switching in xv6: assembly = where to fjnd new context context stored on thread’s stack context address = top of stack saved: ebp, ebx, esi, edi what about other parts of context? eax, ecx, …: saved by swtch’s caller esp: same as address of context program counter: set by call of swtch save stack pointer to fjrst argument (stack pointer now has all info) restore stack pointer from second argument restore program counter (and other saved registers) from new context = where to save current context two arguments: .globl swtch pushl %edi swtch: movl 4(%esp), %eax movl 8(%esp), %edx # Save old callee-save registers pushl %ebp pushl %ebx pushl %esi # Switch stacks ret movl %esp, (%eax) movl %edx, %esp # Load new callee-save registers popl %edi popl %esi popl %ebx popl %ebp 41

  50. struct context **from_context struct context *to_context thread switching in xv6: assembly = where to fjnd new context context stored on thread’s stack context address = top of stack saved: ebp, ebx, esi, edi what about other parts of context? eax, ecx, …: saved by swtch’s caller esp: same as address of context program counter: set by call of swtch save stack pointer to fjrst argument (stack pointer now has all info) restore stack pointer from second argument restore program counter (and other saved registers) from new context = where to save current context two arguments: .globl swtch pushl %edi swtch: movl 4(%esp), %eax movl 8(%esp), %edx # Save old callee-save registers pushl %ebp pushl %ebx pushl %esi # Switch stacks ret movl %esp, (%eax) movl %edx, %esp # Load new callee-save registers popl %edi popl %esi popl %ebx popl %ebp 41

  51. juggling stacks %esp swtch return addr. saved ebp saved ebx saved esi saved edi to stack %esp %esp %esp %esp %esp caller-saved registers fjrst instruction executed by new thread bottom of new kernel stack saved user regs … from stack saved user regs … to stack swtch arguments from stack .globl swtch movl %edx, %esp swtch: movl 4(%esp), %eax movl 8(%esp), %edx # Save old callee-save registers pushl %ebp pushl %ebx pushl %esi pushl %edi # Switch stacks movl %esp, (%eax) # Load new callee-save registers saved edi popl %edi popl %esi popl %ebx popl %ebp ret caller-saved registers swtch arguments swtch return addr. saved ebp saved ebx saved esi 42

  52. juggling stacks %esp swtch arguments swtch return addr. saved ebp saved ebx saved esi saved edi to stack %esp %esp %esp %esp .globl swtch fjrst instruction executed by new thread bottom of new kernel stack saved user regs … from stack saved user regs … to stack caller-saved registers from stack saved edi movl %edx, %esp swtch: movl 4(%esp), %eax movl 8(%esp), %edx # Save old callee-save registers pushl %ebp pushl %ebx pushl %esi pushl %edi # Switch stacks movl %esp, (%eax) # Load new callee-save registers saved esi popl %edi popl %esi popl %ebx popl %ebp ret caller-saved registers swtch arguments swtch return addr. saved ebp saved ebx 42 %esp →

  53. juggling stacks %esp swtch arguments swtch return addr. saved ebp saved ebx saved esi saved edi to stack %esp %esp %esp %esp .globl swtch fjrst instruction executed by new thread bottom of new kernel stack saved user regs … from stack saved user regs … to stack caller-saved registers from stack saved edi movl %edx, %esp swtch: movl 4(%esp), %eax movl 8(%esp), %edx # Save old callee-save registers pushl %ebp pushl %ebx pushl %esi pushl %edi # Switch stacks movl %esp, (%eax) # Load new callee-save registers saved esi popl %edi popl %esi popl %ebx popl %ebp ret caller-saved registers swtch arguments swtch return addr. saved ebp saved ebx 42 %esp →

  54. juggling stacks %esp swtch arguments swtch return addr. saved ebp saved ebx saved esi saved edi to stack %esp %esp %esp %esp .globl swtch fjrst instruction executed by new thread bottom of new kernel stack saved user regs … from stack saved user regs … to stack caller-saved registers from stack saved edi movl %edx, %esp swtch: movl 4(%esp), %eax movl 8(%esp), %edx # Save old callee-save registers pushl %ebp pushl %ebx pushl %esi pushl %edi # Switch stacks movl %esp, (%eax) # Load new callee-save registers saved esi popl %edi popl %esi popl %ebx popl %ebp ret caller-saved registers swtch arguments swtch return addr. saved ebp saved ebx 42 ← %esp

  55. juggling stacks %esp swtch arguments swtch return addr. saved ebp saved ebx saved esi saved edi to stack %esp %esp %esp %esp .globl swtch fjrst instruction executed by new thread bottom of new kernel stack saved user regs … from stack saved user regs … to stack caller-saved registers from stack saved edi movl %edx, %esp swtch: movl 4(%esp), %eax movl 8(%esp), %edx # Save old callee-save registers pushl %ebp pushl %ebx pushl %esi pushl %edi # Switch stacks movl %esp, (%eax) # Load new callee-save registers saved esi popl %edi popl %esi popl %ebx popl %ebp ret caller-saved registers swtch arguments swtch return addr. saved ebp saved ebx 42 ← %esp

  56. juggling stacks %esp swtch arguments swtch return addr. saved ebp saved ebx saved esi saved edi to stack %esp %esp %esp %esp .globl swtch fjrst instruction executed by new thread bottom of new kernel stack saved user regs … from stack saved user regs … to stack caller-saved registers from stack saved edi movl %edx, %esp swtch: movl 4(%esp), %eax movl 8(%esp), %edx # Save old callee-save registers pushl %ebp pushl %ebx pushl %esi pushl %edi # Switch stacks movl %esp, (%eax) 42 saved esi # Load new callee-save registers popl %edi popl %esi popl %ebx popl %ebp ret caller-saved registers swtch arguments swtch return addr. saved ebp saved ebx ← %esp

  57. juggling stacks %esp swtch arguments swtch return addr. saved ebp saved ebx saved esi saved edi to stack %esp %esp %esp %esp .globl swtch fjrst instruction executed by new thread bottom of new kernel stack saved user regs … from stack saved user regs … to stack caller-saved registers from stack saved edi saved esi swtch: movl 4(%esp), %eax movl 8(%esp), %edx # Save old callee-save registers pushl %ebp pushl %ebx pushl %esi pushl %edi # Switch stacks movl %esp, (%eax) movl %edx, %esp # Load new callee-save registers popl %edi popl %esi popl %ebx popl %ebp ret caller-saved registers swtch arguments swtch return addr. saved ebp saved ebx 43 ← %esp

  58. kernel-space context switch summary swtch function saves registers on current kernel stack switches to new kernel stack and restores its registers initial setup — manually construct stack values 44

  59. juggling stacks %esp swtch return addr. saved ebp saved ebx saved esi saved edi to stack %esp %esp %esp %esp %esp caller-saved registers fjrst instruction executed by new thread bottom of new kernel stack saved user regs … from stack saved user regs … to stack swtch arguments from stack .globl swtch movl %edx, %esp swtch: movl 4(%esp), %eax movl 8(%esp), %edx # Save old callee-save registers pushl %ebp pushl %ebx pushl %esi pushl %edi # Switch stacks movl %esp, (%eax) # Load new callee-save registers saved edi popl %edi popl %esi popl %ebx popl %ebp ret caller-saved registers swtch arguments swtch return addr. saved ebp saved ebx saved esi 45

  60. the userspace part? user registers stored in ‘trapframe’ struct created on kernel stack when interrupt/trap happens restored before using iret to switch to user mode initial user registers created manually on stack (as if saved by system call) other code (not shown) handles setting address space 46

  61. the userspace part? user registers stored in ‘trapframe’ struct created on kernel stack when interrupt/trap happens restored before using iret to switch to user mode initial user registers created manually on stack (as if saved by system call) other code (not shown) handles setting address space 46

  62. xv6: where the context is save/restore B kernel stack pointer … ‘B’ process control block save/restore on trap() entry/exit on swtch() B’s saved kernel registers args to swtch() memory used to run process A memory accessable when running process A (= address space) ‘B’ kernel stack … ‘A’ process A’s saved user registers address space ‘B’ process address space kernel-only memory … ‘A’ user stack … B’s saved user registers A’s saved kernel registers ‘A’ kernel stack A’s kernel stack pointer … ‘A’ process control block … ‘B’ user stack 47

  63. xv6: where the context is (detail) ‘to’ user stack saved ebx saved esi saved edi ‘to’ kernel stack fjrst %esp value for ‘to’ process (arg to swtch ) main ’s return addr. main ’s vars … %esp after swtch return addr. return-from- exception kernel memory (shared between all processes) saved in ‘from’ struct proc retrieved via ‘to’ struct proc saved ebp swtch arguments saved user registers last %esp value trap return addr. … caller-saved registers swtch arguments swtch return addr. saved ebp saved ebx saved esi saved edi ‘from’ kernel stack for ‘from’ process caller-saved registers (saved by swtch ) main ’s return addr. main ’s vars … ‘from’ user stack %esp before exception saved user registers trap return addr. … 48

  64. xv6: where the context is (detail) ‘to’ user stack saved ebx saved esi saved edi ‘to’ kernel stack fjrst %esp value for ‘to’ process (arg to swtch ) main ’s return addr. main ’s vars … %esp after swtch return addr. return-from- exception kernel memory (shared between all processes) saved in ‘from’ struct proc retrieved via ‘to’ struct proc saved ebp swtch arguments saved user registers last %esp value trap return addr. … caller-saved registers swtch arguments swtch return addr. saved ebp saved ebx saved esi saved edi ‘from’ kernel stack for ‘from’ process caller-saved registers (saved by swtch ) main ’s return addr. main ’s vars … ‘from’ user stack %esp before exception saved user registers trap return addr. … 49

  65. xv6: where the context is (detail) ‘to’ user stack saved ebx saved esi saved edi ‘to’ kernel stack fjrst %esp value for ‘to’ process (arg to swtch ) main ’s return addr. main ’s vars … %esp after swtch return addr. return-from- exception kernel memory (shared between all processes) saved in ‘from’ struct proc retrieved via ‘to’ struct proc saved ebp swtch arguments saved user registers last %esp value trap return addr. … caller-saved registers swtch arguments swtch return addr. saved ebp saved ebx saved esi saved edi ‘from’ kernel stack for ‘from’ process caller-saved registers (saved by swtch ) main ’s return addr. main ’s vars … ‘from’ user stack %esp before exception saved user registers trap return addr. … 50

  66. exercise loop.exe’s eax stored? D. the kernel stack for the program switched to G. elsewhere C. the user stack of the program switched to F. a special register B. loop.exe’s kernel stack E. loop.exe’s heap A. loop.exe’s user stack when xv6 switches away from this program, where is the value of suppose xv6 is running this loop.exe : // goto start_loop jmp start_loop add $1, %eax start_loop: mov $0, %eax main: 51 // eax ← 0 // eax ← eax + 1

  67. 52

  68. backup slides 53

  69. backup slides 54

  70. write syscall in xv6: summary write function — syscall wrapper uses int $0x40 interrupt table entry setup points to assembly function vector64 (and switches to kernel stack) …which calls trap() with trap number set to 64 ( T_SYSCALL ) (after saving all registers into struct trapframe ) …which checks trap number, then calls syscall() …which checks syscall number (from eax) …and uses it to call sys_write …which reads arguments from the stack and does the write …then registers restored, return to user space 54

  71. write syscall in xv6: summary write function — syscall wrapper uses int $0x40 interrupt table entry setup points to assembly function vector64 (and switches to kernel stack) …which calls trap() with trap number set to 64 ( T_SYSCALL ) (after saving all registers into struct trapframe ) …which checks trap number, then calls syscall() …which checks syscall number (from eax) …and uses it to call sys_write …then registers restored, return to user space 55 …which reads arguments from the stack and does the write

  72. write syscall in xv6: summary write function — syscall wrapper uses int $0x40 interrupt table entry setup points to assembly function vector64 …which calls trap() with trap number set to 64 ( T_SYSCALL ) (after saving all registers into struct trapframe ) …which checks trap number, then calls syscall() …which checks syscall number (from eax) …and uses it to call sys_write …which reads arguments from the stack and does the write …then registers restored, return to user space 56 (and switches to kernel stack)

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

  74. 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 58

  75. 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 59

  76. syscalls in xv6 fork, exec, exit, wait, kill, getpid — process control open, read, write, close, fstat, dup — fjle operations mknod, unlink, link, chdir — directory operations … 60

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

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

Recommend


More recommend