Week 6 CS4973/CS6640 02/10 2025 https://naizhengtan.github.io/25spring/ □ 1. last time: egos □ 2. egos exception handling □ 3. syscall in egos □ 4. CPU privilege levels □ 5. System virtualization (skipped) --- - lab4: OS protection -- exception -- instructions -- memory 1. last time: egos * OS organization * egos design: -- three layers: earth, grass, and apps -- egos is a microkernel OS (relying on IPC) -- four (special) system services -- syscall: sys_send/recv/yield Q: which layer does scheduler belong to? [Answer: grass; it is part of kernel] * egos boot: Q: How does egos boot? CPU jmps to 0x20400000 +-> earth.S:_enter +-> earth.c:main +-> grass.S:_enter +-> grass.c:main +-> app.S:_enter +-> sys_proc.c:main ... +-> sys_shell.c:main * kernel ~= three handlers Q: what are the three ways to trap to kernel? (1) interrupts We've learned this. Q: How does the CPU determine what to execute when an interrupt is triggered? A: mtvec Q: After handling an interrupt, where does the CPU resume execution? A: mepc Q: How does the kernel identify which interrupt was triggered? A: mcause Q: Put it altogether: how do interrupts work? [draw a cpu + memory] (2) exceptions (talk about this next) (3) syscalls 2. egos exception handling Q: What is an exception? CPU: "I don't know how to make progress". Show trap reason table [see handout] Q: ask students which exception the examples will trigger Examples: * read/write invalid memory * run invalid instructions * jump vs. call * run privileged instructions in unprivileged mode These are synchronized traps. Q: how the exception works on RISC-V CPUs? Similar to interrupts. Again, mtvec, mcause, mepc, Q: if the same, how to tell exceptions from interrupts? Check the first bit of mcause. Code: go through a complete pass of the exception handling. trap_entry (cpu_intr.c) | +-> trap_handler (kernel.c) | (ctx_start) | +-> ctx_entry() | +-> excp_entry(id) | +->[your code] | +-> ctx_switch() // back to user stack | +-> [end of trap_handler] | +-> [end of trap_entry] -> [user space] 3. egos syscall implementation Interfaces for user applications to "talk" to kernel. Some Linux syscalls: -- open/read/write/close/dup2 -- mkdir/chmod/stat -- socket/bind/listen/connect -- pipe/fork/exec/exit Leading to the next section. Multiple design questions for kernel developers (you). Now, imagine you were a kernel designer: Q1: how does control transfer to the kernel? (trap to kernel) // Kernel has a function proc_yield(). // A user app which is another program want to call proc_yield(). // How to do this? Q2: how does kernel understand what the application wants? That is, what information is needed for handling a syscall? // Syscall type // Syscall arguments // Syscall return value Q3: where is syscall-related information stored? // registers? // stacks? // well-known memory places? Overview, take a look at the workflow. [see handout] a) answers to Q1: sys_invoke() so far, MISP Example: explore MISP (in CPU manual) vs. mip.MISP (in RISC-V spec) (gdb) display/t $mip (gdb) b syscall.c:46 // based on egos-upstream:lab4 Q: why we have a loop here? Q: can we do better? b) answers to Q2: [read grass/syscall.h] struct syscall c) answers to Q3: [read grass/syscall.c] SYSCALL_ARGS (a well-known memory address) 4. Privilege levels [draw figure] hw, kernel, apps M/S/U-Mode Overall topics: -- Why do we need privilege levels? -- What are the differences between them? -- How to switch privilege levels? * Motivating example: a user program allocating too much memory. The kernel will crash/panic/fatal error. This is not ideal. Ideally, an OS should kill the process. Example: [read example] Run an example "malloc" on MacOS. $ malloc (on one terminal) $ htop -F malloc (on another terminal) Q: What do you expect to see? Will see: """ ... allocated 107.00 GB memory zsh: killed ./malloc """ Q: motivation: why do people want privilege levels? -- resource multiplexing -- security purpose -- isolating faults -- providing abstractions -- what else? CPU privilege levels define what "you" can and cannot do: * controlling over system operations * accessing system resources - recall what a program is. It has: instructions, registers, memory. Q: running the same piece of code in unprivileged and privileged mode, what will be the difference? Three differences: - privileged instructions, - touching privileged registers (CSRs), - accessing privileged memory [1min intro to virtual memory] Protection mechanics: exceptions [what we just learned] How to switch privilege levels? - interrupt - exception - ecall - mret Q: How could I know what privilege level the current CPU is running in? """ RISC-V deliberately doesn't make it easy for code to discover what mode it is running it because this is a virtualisation hole. As a general principle, code should be designed for and implicitly know what mode it will run in. Applications code should assume it is in U mode. The operating system should assume it is in S mode (it might in fact be virtualised and running in U mode, with things U mode can’t do trapped and emulated by the hypervisor). """ [from https://forums.sifive.com/t/how-to-determine-the-current-execution-privilege-mode/2823]