// TODO: CHECK/REPLACE/UPDATE OLD CODE (this file is based on xv6) // // low-level code to handle traps from user space into // the kernel, and returns from kernel to user. // // the kernel maps the page holding this code // at the same virtual address (TRAMPOLINE) // in user and kernel space so that it continues // to work when it switches page tables. // kernel.ld causes this code to start at // a page boundary. // // NOTES COPIED FROM OLD LAYOUT // uservec in trampoline.S saves user registers in the trapframe, // then initializes registers from the trapframe's // kernel_sp, kernel_hartid, kernel_satp, and jumps to kernel_trap. // usertrapret() and userret in trampoline.S set up // the trapframe's kernel_* [NOW kmode_], restore user registers from the // trapframe, switch to the user page table, and enter user space. // the trapframe includes callee-saved user registers like s0-s11 because the // return-to-user path via usertrapret() doesn't return through // the entire kernel call stack. #include "riscv.h" #include "memlayout.h" .option norvc .section trampsec .globl trampoline .globl usertrap trampoline: .align 4 .globl uservec uservec: // // trap.c sets stvec to point here, so // traps from user space start here, // in supervisor mode, but with a // user page table. // // save user a0 in sscratch so // a0 can be used to get at TRAPFRAME. csrw sscratch, a0 // each process has a separate p->trapframe memory area, // but it's mapped to the same virtual address // (TRAPFRAME) in every process's user page table. li a0, TRAPFRAME // save the user registers in TRAPFRAME sd ra, 40(a0) sd sp, 48(a0) sd gp, 56(a0) sd tp, 64(a0) sd t0, 72(a0) sd t1, 80(a0) sd t2, 88(a0) sd s0, 96(a0) sd s1, 104(a0) sd a1, 120(a0) sd a2, 128(a0) sd a3, 136(a0) sd a4, 144(a0) sd a5, 152(a0) sd a6, 160(a0) sd a7, 168(a0) sd s2, 176(a0) sd s3, 184(a0) sd s4, 192(a0) sd s5, 200(a0) sd s6, 208(a0) sd s7, 216(a0) sd s8, 224(a0) sd s9, 232(a0) sd s10, 240(a0) sd s11, 248(a0) sd t3, 256(a0) sd t4, 264(a0) sd t5, 272(a0) sd t6, 280(a0) // save the user a0 in p->trapframe->a0 csrr t0, sscratch sd t0, 112(a0) // initialize kernel stack pointer, from p->trapframe->kmode_sp ld sp, 8(a0) // make tp hold the current hartid, from p->trapframe->kmode_hartid ld tp, 32(a0) // load the address of usertrap(), from p->trapframe->kmode_trap ld t0, 16(a0) // fetch the kernel page table address, from p->trapframe->kmode_satp. ld t1, 0(a0) // wait for any previous memory operations to complete, so that // they use the user page table. sfence.vma zero, zero // install the kernel page table. csrw satp, t1 // flush now-stale user entries from the TLB. sfence.vma zero, zero // jump to usertrap(), which does not return jr t0 .globl userret userret: // userret(pagetable) // called by usertrapret() in trap.c to // switch from kernel to user. // a0: user page table, for satp. // switch to the user page table. sfence.vma zero, zero csrw satp, a0 sfence.vma zero, zero li a0, TRAPFRAME // restore all but a0 from TRAPFRAME ld ra, 40(a0) ld sp, 48(a0) ld gp, 56(a0) ld tp, 64(a0) ld t0, 72(a0) ld t1, 80(a0) ld t2, 88(a0) ld s0, 96(a0) ld s1, 104(a0) ld a1, 120(a0) ld a2, 128(a0) ld a3, 136(a0) ld a4, 144(a0) ld a5, 152(a0) ld a6, 160(a0) ld a7, 168(a0) ld s2, 176(a0) ld s3, 184(a0) ld s4, 192(a0) ld s5, 200(a0) ld s6, 208(a0) ld s7, 216(a0) ld s8, 224(a0) ld s9, 232(a0) ld s10, 240(a0) ld s11, 248(a0) ld t3, 256(a0) ld t4, 264(a0) ld t5, 272(a0) ld t6, 280(a0) // restore user a0 ld a0, 112(a0) // return to user mode and user pc. // usertrapret() set up sstatus and sepc. sret