diff --git a/kernel/kernelvec.S b/kernel/kernelvec.S index 9aabe96..222b172 100644 --- a/kernel/kernelvec.S +++ b/kernel/kernelvec.S @@ -8,8 +8,10 @@ .globl kernelvec .align 4 kernelvec: + // make room to save registers. addi sp, sp, -256 + // save the registers. sd ra, 0(sp) sd sp, 8(sp) sd gp, 16(sp) @@ -42,8 +44,10 @@ kernelvec: sd t5, 232(sp) sd t6, 240(sp) + // call the C trap handler in trap.c call kerneltrap + // restore registers. ld ra, 0(sp) ld sp, 8(sp) ld gp, 16(sp) @@ -78,6 +82,7 @@ kernelvec: addi sp, sp, 256 + // return to whatever we were doing in the kernel. sret # diff --git a/kernel/trampoline.S b/kernel/trampoline.S index bc31974..6e436d2 100644 --- a/kernel/trampoline.S +++ b/kernel/trampoline.S @@ -2,77 +2,21 @@ # code to switch between user and kernel space. # # this code is mapped at the same virtual address - # in user and kernel space so that it continues - # to work when it switches page tables. + # (TRAMPOLINE) in user and kernel space so that + # it continues to work when it switches page tables. # - # kernel.ld causes userret to be aligned + # kernel.ld causes this to be aligned # to a page boundary. # .section trampsec .globl trampoline trampoline: -.globl userret -userret: - # userret(trapframe, pagetable) - # switch from kernel to user. - # usertrapret() calls here. - # a0: p->tf in user page table - # a1: new value for satp, for user page table - - # switch to the user page table. - sfence.vma zero, zero - csrw satp, a1 - - # put the saved user a0 in sscratch, so we - # can swap it with our a0 (p->tf) in the last step. - ld t0, 112(a0) - csrw sscratch, t0 - - # restore all but a0 from p->tf - 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, and save p->tf in sscratch - csrrw a0, sscratch, a0 - - # return to user mode and user pc. - # usertrapret() set up sstatus and sepc. - sret - .align 4 .globl uservec uservec: # - # trap.c set stvec to point here, so - # user interrupts and exceptions start here, + # trap.c sets stvec to point here, so + # traps from user space start here, # in supervisor mode, but with a # user page table. # @@ -139,3 +83,59 @@ uservec: # jump to usertrap(), which does not return jr t0 + +.globl userret +userret: + # userret(trapframe, pagetable) + # switch from kernel to user. + # usertrapret() calls here. + # a0: p->tf in user page table + # a1: new value for satp, for user page table + + # switch to the user page table. + sfence.vma zero, zero + csrw satp, a1 + + # put the saved user a0 in sscratch, so we + # can swap it with our a0 (p->tf) in the last step. + ld t0, 112(a0) + csrw sscratch, t0 + + # restore all but a0 from p->tf + 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, and save p->tf in sscratch + csrrw a0, sscratch, a0 + + # return to user mode and user pc. + # usertrapret() set up sstatus and sepc. + sret diff --git a/kernel/trap.c b/kernel/trap.c index ad2d0f8..ce7a65a 100644 --- a/kernel/trap.c +++ b/kernel/trap.c @@ -9,7 +9,7 @@ struct spinlock tickslock; uint ticks; -extern char trampoline[], uservec[]; +extern char trampoline[], uservec[], userret[]; // in kernelvec.S, calls kerneltrap(). void kernelvec(); @@ -123,7 +123,8 @@ usertrapret(void) // jump to trampoline.S at the top of memory, which // switches to the user page table, restores user registers, // and switches to user mode with sret. - ((void (*)(uint64,uint64))TRAMPOLINE)(TRAPFRAME, satp); + uint64 fn = TRAMPOLINE + (userret - trampoline); + ((void (*)(uint64,uint64))fn)(TRAPFRAME, satp); } // interrupts and exceptions from kernel code go here via kernelvec,