Trap from User Space Sequence
sequenceDiagram autonumber actor U as User code participant CPU as RISC-V hardware / CSRs participant UV as uservec<br/>(trampoline.S) participant TF as p->trapframe participant UT as usertrap()<br/>(trap.c) participant H as handler logic<br/>syscall / devintr / vmfault participant PR as prepare_return()<br/>(trap.c) participant UR as userret<br/>(trampoline.S) Note over U,CPU: Mode = U<br/>satp = user page table<br/>stvec = TRAMPOLINE + uservec U->>CPU: ecall / exception / interrupt CPU->>CPU: save trap state<br/>sepc = faulting/interrupted PC<br/>scause = cause<br/>stval = fault address if any CPU->>CPU: switch privilege<br/>U mode -> S mode CPU->>UV: set PC = stvec<br/>enter uservec Note over UV,CPU: Mode = S<br/>satp still = user page table UV->>CPU: csrw sscratch, a0<br/>save original user a0 in CSR UV->>UV: li a0, TRAPFRAME UV->>TF: save user registers except a0 UV->>CPU: csrr t0, sscratch UV->>TF: save original user a0<br/>trapframe->a0 = t0 UV->>TF: load kernel_sp UV->>TF: load kernel_hartid UV->>TF: load kernel_trap = usertrap UV->>TF: load kernel_satp UV->>CPU: sfence.vma UV->>CPU: write satp = kernel_satp UV->>CPU: sfence.vma UV->>UT: jump to usertrap() Note over UT,CPU: Mode = S<br/>satp = kernel page table UT->>CPU: set stvec = kernelvec UT->>CPU: read scause, sepc, stval UT->>TF: trapframe->epc = sepc alt scause == 8: system call exception UT->>TF: trapframe->epc += 4<br/>skip ecall on return UT->>CPU: intr_on() UT->>H: syscall() H->>TF: read syscall number from a7 H->>TF: read syscall arguments from a0-a5 H->>H: validate syscall number H->>H: lookup syscalls[num] H->>H: call selected sys_* handler H->>TF: write return value to a0 else interrupt recognized by devintr() UT->>H: devintr() H->>CPU: read scause alt supervisor external interrupt H->>H: plic_claim() H->>H: if UART0_IRQ: uartintr() H->>H: if VIRTIO0_IRQ: virtio_disk_intr() H->>H: plic_complete(irq) H-->>UT: return 1<br/>ordinary device interrupt handled UT->>UT: continue return path<br/>no yield else supervisor timer interrupt H->>H: clockintr() H->>H: ticks++ H->>H: wakeup(&ticks) H->>CPU: set next stimecmp H-->>UT: return 2<br/>timer interrupt handled UT->>UT: yield()<br/>later resume in usertrap() else not recognized H-->>UT: return 0 end else scause == 13 or 15: page fault UT->>CPU: read stval<br/>faulting virtual address UT->>H: vmfault(pagetable, stval, read/write) alt vmfault succeeds H->>H: allocate missing lazy page H->>H: map page into user pagetable H-->>UT: same instruction can retry else vmfault fails H-->>UT: fatal user page fault<br/>return path omitted end else unexpected user exception UT->>UT: fatal user exception<br/>return path omitted end UT->>PR: prepare_return() PR->>CPU: intr_off() PR->>CPU: set stvec = TRAMPOLINE + uservec PR->>TF: fill kernel_satp PR->>TF: fill kernel_sp PR->>TF: fill kernel_trap = usertrap PR->>TF: fill kernel_hartid PR->>CPU: set sstatus.SPP = user PR->>CPU: set sstatus.SPIE = enabled PR->>CPU: set sepc = trapframe->epc PR-->>UT: return UT-->>UR: return user satp in a0 Note over UR,CPU: Mode = S<br/>satp still = kernel page table UR->>CPU: sfence.vma UR->>CPU: write satp = user page table UR->>CPU: sfence.vma UR->>UR: li a0, TRAPFRAME UR->>TF: restore user registers except a0 UR->>TF: restore user a0 from trapframe UR->>CPU: sret CPU->>U: resume at sepc Note over U,CPU: Mode = U<br/>satp = user page table