<<

an

int main(void){ Processes and Exceptions while (1) { /* waste CPU time */ } }

If I run this on a lab machine, can you still use it? …even if the machine only has one core?

1 2 timing nothing doing nothing on a busy system

long times[NUM_TIMINGS]; time for empty loop body 108 int main(void){ for (int i = 0; i < N; ++i) { 107 long start, end; 106 start = get_time(); /* do nothing */ 105 end = get_time(); 104

times[i] = end − start; time (ns) } 103 output_timings(times); 2 } 10 same instructions — same difference each time? 101 3 0 200000 400000 600000 800000 1000000 4 sample # ... call get_time // whatever get_time does movq %rax, %rbp million cycle delay call get_time // whatever get_time does subq %rbp, %rax ...

doing nothing on a busy system time multiplexing

time for empty loop body loop.exe ssh.exe firefox.exe loop.exe ssh.exe 108 CPU: time 107

106

105

104 time (ns) 103

102

101 0 200000 400000 600000 800000 1000000 5 6 sample # time multiplexing time multiplexing

CPU: loop.exe ssh.exe firefox.exe loop.exe ssh.exe CPU: loop.exe ssh.exe firefox.exe loop.exe ssh.exe time time

...... call get_time call get_time // whatever get_time does // whatever get_time does movq %rax, %rbp movq %rax, %rbp million cycle delay million cycle delay call get_time call get_time // whatever get_time does // whatever get_time does subq %rbp, %rax subq %rbp, %rax ......

6 6 exception happens return from exception

illusion: dedicated processor time multiplexing really

time multiplexing: illusion of dedicated processor loop.exe ssh.exe firefox.exe loop.exe ssh.exe including dedicated registers sometimes called a =

illusion is perfect — except for performance

7 8 time multiplexing really OS and time multiplexing

loop.exe ssh.exe firefox.exe loop.exe ssh.exe starts running instead of normal program mechanism for this: exceptions (later) saves old program counter, registers somewhere = operating system sets new registers, jumps to new program counter called saved information called context exception happens return from exception

8 9 address space: map from program to real addresses

context context switch

all registers values context_switch(last, next): %rax %rbx, …, %rsp,… copy_preexception_pc last−>pc mov rax,last−>rax condition codes mov rcx, last−>rcx mov rdx, last−>rdx program counter ... mov next−>rdx, rdx i.e. all visible state in your CPU except memory mov next−>rcx, rcx mov next−>rax, rax jmp next−>pc

10 11 contexts (A running) contexts (B running)

in Memory in Memory

Process A memory: A memory: in CPU code, stack, etc. in CPU code, stack, etc. %rax %rax %rbx %rbx %rcx %rcx %rsp Process B memory: %rsp Process B memory: … code, stack, etc. … code, stack, etc. SF SF ZF OS memory: ZF OS memory: PC PC %rax SF %rax SF %rbx ZF %rbx ZF %rcx PC %rcx PC … … … …

12 13 result: %rax is 42 (always) result: might

memory protection

reading from another program’s memory? reading from another program’s memory? Program A Program B Program A Program B 0x10000: .word 42 0x10000: .word 42 // while A is working: // while A is working: // ... // ... movq $99, %rax movq $99, %rax // do work // do work movq %rax, 0x10000 movq %rax, 0x10000 // ... // ...... movq 0x10000, %rax movq 0x10000, %rax

result: %rax is 42 (always) result: might crash

14 14

Recall: program memory program memory (two programs)

0xFFFF FFFF FFFF FFFF Program A Program B Used by OS 0xFFFF 8000 0000 0000 Used by OS Used by OS 0x7F… Stack Stack Stack

Heap / other dynamic Heap / other dynamic Heap / other dynamic Writable data Writable data Writable data Code + Constants Code + Constants Code + Constants 0x0000 0000 0040 0000

15 16 = kernel-mode only

trigger error

= kernel-mode only

address space program memory (two programs)

programs have illusion of own memory Program A Program B called a program’s address space Used by OS Used by OS real memory Program A mapping Program A code (set by OS) Stack Stack addresses Program B code Program A data Heap / other dynamic Heap / other dynamic Program B mapping Program B data addresses (set by OS) Writable data Writable data OS data … Code + Constants Code + Constants

17 18 address space address space mechanisms

programs have illusion of own memory next week’s topic called a program’s address space called real memory Program A mapping Program A code mapping called page tables addresses (set by OS) Program B code mapping part of what is changed in context switch Program A data Program B mapping Program B data addresses (set by OS) OS data …

trigger error 19 20 context The Process

all registers values process = thread(s) + address space %rax %rbx, …, %rsp,… illusion of dedicated machine: condition codes thread = illusion of own CPU address space = illusion of own memory program counter i.e. all visible state in your CPU except space: map from program to real addresses

21 22 time multiplexing really exceptions

loop.exe ssh.exe firefox.exe loop.exe ssh.exe special control transfer similar effect to function call but often not requested by the program = operating system usually from user programs to the OS example: from timer expiring keeps our infinite loop from running forever exception happens return from exception

23 24 types of exceptions timer

— externally-triggered (conceptually) external timer device timer — keep program from hogging CPU I/O devices — key presses, hard drives, networks, … OS configures before starting program faults — errors/events in programs sends to CPU after a fixed interval memory not in address space (“”) divide by zero invalid instruction traps — intentionally triggered exceptions system calls — ask OS to do something aborts

25 26 types of exceptions protection fault

interrupts — externally-triggered when program tries to access memory it doesn’t own timer — keep program from hogging CPU I/O devices — key presses, hard drives, networks, … e.g. trying to write to bad address faults — errors/events in programs OS gets control — can crash the program memory not in address space (“Segmentation fault”) or more interesting things divide by zero invalid instruction traps — intentionally triggered exceptions system calls — ask OS to do something aborts

27 28 synchronous versus asynchronous exception implementation

synchronous — triggered by a particular instruction detect condition (program error or external event) particular mov instruction save current value of PC somewhere asynchronous — comes from outside the program timer event jump to exception handler (part of OS) keypress, other input event jump done without program instruction to do so

29 30 exception implementation: notes locating exception handlers

exception table I/textbook describe a simplified version base register handle_divide_by_zero: movq %rax, save_rax real /x86-64 is a bit more complicated movq %rbx, save_rbx exception table (in memory) ... (mostly for historical reasons) address pointer base + 0x00 base + 0x08 … base + 0x10 … base + 0x18 … … … base + 0x40 … … handle_timer_interrupt: movq %rax, save_rax movq %rbx, save_rbx ...

31 32 running the exception handler exception handler structure

hardware saves the old program counter 1. save process’s state somewhere identifies location of exception handler via table 2. do work to handle exception 3. restore a process’s state (maybe a different one) then jumps to that location 4. jump back to program OS code can save registers, etc., etc. handle_timer_interrupt: mov_from_saved_pc save_pc_loc movq %rax, save_rax_loc ... // choose new process to run here movq new_rax_loc, %rax mov_to_saved_pc new_pc return_from_exception 33 34 added to CPU for exceptions added to CPU for exceptions

new instruction: set exception table base new instruction: set exception table base new logic: jump based on exception table new logic: jump based on exception table new logic: save the old PC new logic: save the old PC to special register or to memory to special register or to memory new instruction: return from exception new instruction: return from exception i.e. jump to saved PC i.e. jump to saved PC

35 35 added to CPU for exceptions why return from exception?

new instruction: set exception table base not just ret — can’t modify process’s stack would break the illusion of dedicated CPU new logic: jump based on exception table reasons related to address spaces, protection (later) new logic: save the old PC to special register or to memory new instruction: return from exception i.e. jump to saved PC

35 36 exceptions and time slicing defeating time slices?

loop.exe ssh.exe firefox.exe loop.exe ssh.exe my_exception_table: ... my_handle_timer_interrupt: timer interrupt // HA! Keep running me! return_from_exception exception table lookup main: set_exception_table_base my_exception_table loop: handle_timer_interrupt: jmp loop ...... set_address_space ssh_address_space mov_to_saved_pc saved_ssh_pc return_from_exception 37 38 defeating time slices? privileged instructions

wrote a program that tries to set the exception table: can’t let any program run some instructions

my_exception_table: allows machines to be shared between users (e.g. lab ... servers) examples: main: set exception table // "Load Interrupt // Descriptor Table" set address space // x86 instruction to set exception table talk to I/O device (hard drive, keyboard, display, …) lidt my_exception_table … ret processor has two modes: kernel mode — privileged instructions work result: Segmentation fault (exception!) user mode — privileged instructions cause exception instead 39 40 kernel mode program memory (two programs)

Program A Program B extra one-bit register: “are we in kernel mode” Used by OS Used by OS exceptions enter kernel mode return from exception instruction leaves kernel mode Stack Stack

Heap / other dynamic Heap / other dynamic Writable data Writable data Code + Constants Code + Constants

41 42 address space kernel services

programs have illusion of own memory allocating memory? (change address space) called a program’s address space reading/writing to file? (communicate with hard real memory drive) Program A mapping Program A code (set by OS) read input? (communicate with keyborad) addresses Program B code Program A data all need privileged instructions! mapping Program B Program B data need to run code in kernel mode addresses (set by OS) OS data = kernel-mode only …

trigger error 43 44 types of exceptions x86-64 system calls

interrupts — externally-triggered special instruction: syscall timer — keep program from hogging CPU I/O devices — key presses, hard drives, networks, … triggers (deliberate exception) faults — errors/events in programs memory not in address space (“Segmentation fault”) divide by zero invalid instruction traps — intentionally triggered exceptions system calls — ask OS to do something aborts

45 46 Linux syscall calling convention Linux x86-64 hello world before syscall: .globl _start .data %rax — number hello_str: .asciz "Hello,␣World!\n" .text %rdi, %rsi, %rdx, %r10, %r8, %r9 — args _start: movq $1, %rax # 1 = "write" movq $1, %rdi # file descriptor 1 = stdout after syscall: movq $hello_str, %rsi movq $15, %rdx # 15 = strlen("Hello, World!\n") %rax — return value syscall %rax on error: contains -1 times “error number” movq $60, %rax # 60 = exit movq $0, %rdi almost the same as normal function calls syscall 47 48 approx. system call handler Linux system call examples sys_call_table: mmap, brk — allocate memory .quad handle_read_syscall .quad handle_write_syscall fork — create new process // ... execve — run a program in the current process handle_syscall: ... // save old PC, etc. _exit pushq %rcx // save registers — terminate a process pushq %rdi open, read, write — access files ... call *sys_call_table(,%rax,8) terminals, etc. count as files, too ... popq %rdi popq %rcx return_from_exception 49 50 system calls and protection careful exception handlers

exceptions are only way to access kernel mode movq $important_os_address, %rsp operating system controls what proceses can do can’t trust user’s stack pointer! … by writing exception handlers very carefully need to have own stack in kernel-mode-only memory need to check all inputs really carefully

51 52 reading keyboard input keyboard input timeline

int main(void){ char buf[1024]; /* read a line from stdin −−− read_input.exe read_input.exe waits for keyboard input */ if (fgets(buf, sizeof buf, stdin) != NULL) { = operating system printf("You␣typed␣[%s]\n", buf); } } trap — read system call

fgets uses read system call interrupt — from keyboard

53 54 system call wrappers system call wrappers library functions to not write assembly: library functions to not write assembly: open: open: movq $2, %rax // 2 = sys_open movq $2, %rax // 2 = sys_open // 2 arguments happen to use same registers // 2 arguments happen to use same registers syscall syscall // return value in %eax // return value in %eax cmp $0, %rax cmp $0, %rax jl has_error jl has_error ret ret has_error: has_error: neg %rax neg %rax movq %rax, errno movq %rax, errno movq $−1, %rax movq $−1, %rax ret ret 55 55 system call wrapper: usage system call wrapper: usage

/* unistd.h contains definitions of: /* unistd.h contains definitions of: O_RDONLY (integer constant), open() */ O_RDONLY (integer constant), open() */ #include #include int main(void){ int main(void){ int file_descriptor; int file_descriptor; file_descriptor = open("input.txt", O_RDONLY); file_descriptor = open("input.txt", O_RDONLY); if (file_descriptor < 0) { if (file_descriptor < 0){ printf("error:␣%s\n", strerror(errno)); printf("error:␣%s\n", strerror(errno)); exit(1); exit(1); } } ...... result = read(file_descriptor, ...); result = read(file_descriptor, ...); ...... } }

56 56 types of exceptions a note on terminology

interrupts — externally-triggered the real world does not use consistent terms for timer — keep program from hogging CPU exceptions I/O devices — key presses, hard drives, networks, … we will follow textbook’s terms in this course faults — errors/events in programs memory not in address space (“Segmentation fault”) divide by zero the real world won’t invalid instruction you might see: traps — intentionally triggered exceptions ‘interrupt’ meaning what we call ‘exception’ (x86) system calls — ask OS to do something ‘exception’ meaning what we call ‘fault’ ‘fault‘ meaning what we call ‘fault’ or ‘abort’ (ARM) aborts … and more

57 58 signals signal API

Unix-like operating system feature sigaction — register handler for signal like interrupts for processes: — send signal to process pause — put process to sleep until signal received can be triggered by external process (instead of device) sigprocmask — block some signals from being kill command/system call received until ready can be triggered by special events … and much more pressing control- can invoke signal handler

59 60 example signal program signal delivery (1)

#include signal happens while foo() is running #include OS writes stack from to user stack void handle_sigint(int signum) { write(1, "Got␣signal!\n", sizeof("Got␣signal!\n"));OS modifies registers to call signal handler _exit(0); } the stack stack pointer address of __restore_rt int main(void){ saved registers when signal handler started struct sigaction act; PC when signal happened stack pointer act.sa_handler = &handle_sigint; local variables for foo before signal delivered sigemptyset(&act.sa_mask); … sigaction(&act);

char buf[1024]; while (fgets(buf, sizeof buf, stdin)) { 61 62 printf("read␣%s", buf); } signal} delivery (2) signal handler unsafety (1) handle_sigint: void *malloc(size_t size) { ...... ret to_return = next_to_return; ... /* SIGNAL HAPPENS HERE */ __restore_rt: next_to_return += size; // 15 = "sigreturn" system call return to_return; movq $15, %rax } syscall void foo() { __restore_rt is return address for signal handler /* This malloc() call interrupted */ char *p = malloc(1024); system call restores pre-signal state, then returns p[0] = 'x'; }

void handle_sigint() { 63 // printf might use malloc() 64 printf("You␣pressed␣control−C.\n"); } setjmp/longjmp implementing setjmp/lonjmp

C flow control setjmp: jmp_buf env; copy all registers to jmp_buf … including stack pointer main() { if (setjmp(env) == 0) { // like try { longjmp ... copy registers from jmp_buf read_file() … but change %rax (return value) ... } else { // like catch printf("some␣error␣happened\n"); } } read_file() { ... 65 66 if (open failed) { longjmp(env, 1) // like throw } setjmp... weirdness — local variables setjmp weirdness — fix } : Defined behavior: int x = 0; volatile int x = 0; if (setjmp(env) == 0) { if (setjmp(env) == 0) { ...... x += 1; x += 1; longjmp(env, 1); longjmp(env, 1); } else { } else { printf("%d\n", x); printf("%d\n", x); } }

67 68 on implementing try/catch could do something like setjmp()/longjmp() but want try to be really fast! instead: tables of information indexed by program counters: where register values are stored on stack/in other registers where old program counters are stored on stack where catch blocks are located

69