diff options
author | Andrew Waterman <waterman@cs.berkeley.edu> | 2016-02-10 23:57:38 -0800 |
---|---|---|
committer | Andrew Waterman <waterman@cs.berkeley.edu> | 2016-02-19 13:01:11 -0800 |
commit | 3c0620321d6316aaa5559a97dadeba5547171576 (patch) | |
tree | 8be65db2b29a31092f181695fc4f10e3a600fc39 /pk | |
parent | e984b263e07d2a2085e1856921253bc04c09d12c (diff) | |
download | pk-3c0620321d6316aaa5559a97dadeba5547171576.zip pk-3c0620321d6316aaa5559a97dadeba5547171576.tar.gz pk-3c0620321d6316aaa5559a97dadeba5547171576.tar.bz2 |
WIP on priv spec v1.9
Diffstat (limited to 'pk')
-rw-r--r-- | pk/devicetree.c | 1 | ||||
-rw-r--r-- | pk/emulation.c | 21 | ||||
-rw-r--r-- | pk/encoding.h | 8 | ||||
-rw-r--r-- | pk/init.c | 8 | ||||
-rw-r--r-- | pk/mentry.S | 238 | ||||
-rw-r--r-- | pk/minit.c | 9 | ||||
-rw-r--r-- | pk/mtrap.c | 33 | ||||
-rw-r--r-- | pk/mtrap.h | 41 | ||||
-rw-r--r-- | pk/pk.ld | 8 |
9 files changed, 167 insertions, 200 deletions
diff --git a/pk/devicetree.c b/pk/devicetree.c index 242f013..a60645a 100644 --- a/pk/devicetree.c +++ b/pk/devicetree.c @@ -1,6 +1,5 @@ #include "devicetree.h" #include "encoding.h" -#include "pk.h" #include "mtrap.h" #include <stdbool.h> diff --git a/pk/emulation.c b/pk/emulation.c index edc14bd..9b8d65d 100644 --- a/pk/emulation.c +++ b/pk/emulation.c @@ -16,7 +16,9 @@ void redirect_trap(uintptr_t epc, uintptr_t mstatus) mstatus = INSERT_FIELD(mstatus, MSTATUS_MPP, PRV_S); mstatus = INSERT_FIELD(mstatus, MSTATUS_MPIE, 0); write_csr(mstatus, mstatus); - leave(); + + extern void __redirect_trap(); + return __redirect_trap(); } void __attribute__((noinline)) truly_illegal_insn(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc, uintptr_t mstatus, insn_t insn) @@ -26,8 +28,8 @@ void __attribute__((noinline)) truly_illegal_insn(uintptr_t* regs, uintptr_t mca void misaligned_load_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc) { - uintptr_t mstatus = read_csr(mstatus); - insn_t insn = get_insn(mepc); + uintptr_t mstatus; + insn_t insn = get_insn(mepc, &mstatus); int shift = 0, fp = 0, len; if ((insn & MASK_LW) == MATCH_LW) @@ -74,8 +76,8 @@ void misaligned_load_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc) void misaligned_store_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc) { - uintptr_t mstatus = read_csr(mstatus); - insn_t insn = get_insn(mepc); + uintptr_t mstatus; + insn_t insn = get_insn(mepc, &mstatus); uintptr_t val = GET_RS2(insn, regs), error; int len; @@ -118,7 +120,7 @@ DECLARE_EMULATION_FUNC(emulate_float_load) return misaligned_load_trap(regs, mcause, mepc); unpriv_mem_access("lw %[val_lo], (%[addr])", - val_lo, unused1, unused2, addr, mstatus/*X*/); + val_lo, unused1, unused2, addr, mepc/*X*/); SET_F32_RD(insn, regs, val_lo); break; @@ -128,11 +130,11 @@ DECLARE_EMULATION_FUNC(emulate_float_load) #ifdef __riscv64 unpriv_mem_access("ld %[val], (%[addr])", - val, val_hi/*X*/, unused1, addr, mstatus/*X*/); + val, val_hi/*X*/, unused1, addr, mepc/*X*/); #else unpriv_mem_access("lw %[val_lo], (%[addr]);" "lw %[val_hi], 4(%[addr])", - val_lo, val_hi, unused1, addr, mstatus/*X*/); + val_lo, val_hi, unused1, addr, mepc/*X*/); val = val_lo | ((uint64_t)val_hi << 32); #endif SET_F64_RD(insn, regs, val); @@ -592,6 +594,9 @@ DECLARE_EMULATION_FUNC(emulate_fcvt_if) else result = (uint64_t)uint_val; break; + + default: + __builtin_unreachable(); } if (uint_val > limit) { diff --git a/pk/encoding.h b/pk/encoding.h index df04845..a88205f 100644 --- a/pk/encoding.h +++ b/pk/encoding.h @@ -65,7 +65,9 @@ #define IMPL_ROCKET 1 -#define DEFAULT_MTVEC 0x100 +#define DEFAULT_RSTVEC 0x0 +#define DEFAULT_NMIVEC 0x4 +#define DEFAULT_MTVEC 0x8 // page table entry (PTE) fields #define PTE_V 0x001 // Valid @@ -662,6 +664,7 @@ #define CSR_MCAUSE 0x342 #define CSR_MBADADDR 0x343 #define CSR_MIP 0x344 +#define CSR_MIPI 0x345 #define CSR_MTIME 0x701 #define CSR_MCPUID 0xf00 #define CSR_MIMPID 0xf01 @@ -669,7 +672,6 @@ #define CSR_MTOHOST 0x780 #define CSR_MFROMHOST 0x781 #define CSR_MRESET 0x782 -#define CSR_MIPI 0x783 #define CSR_MIOBASE 0x784 #define CSR_CYCLEH 0xc80 #define CSR_TIMEH 0xc81 @@ -971,6 +973,7 @@ DECLARE_CSR(mepc, CSR_MEPC) DECLARE_CSR(mcause, CSR_MCAUSE) DECLARE_CSR(mbadaddr, CSR_MBADADDR) DECLARE_CSR(mip, CSR_MIP) +DECLARE_CSR(mipi, CSR_MIPI) DECLARE_CSR(mtime, CSR_MTIME) DECLARE_CSR(mcpuid, CSR_MCPUID) DECLARE_CSR(mimpid, CSR_MIMPID) @@ -978,7 +981,6 @@ DECLARE_CSR(mhartid, CSR_MHARTID) DECLARE_CSR(mtohost, CSR_MTOHOST) DECLARE_CSR(mfromhost, CSR_MFROMHOST) DECLARE_CSR(mreset, CSR_MRESET) -DECLARE_CSR(mipi, CSR_MIPI) DECLARE_CSR(miobase, CSR_MIOBASE) DECLARE_CSR(cycleh, CSR_CYCLEH) DECLARE_CSR(timeh, CSR_TIMEH) @@ -68,11 +68,3 @@ void boot_loader(struct mainvars* args) run_loaded_program(args); } - -void prepare_supervisor_mode() -{ - uintptr_t mstatus = read_csr(mstatus); - mstatus = INSERT_FIELD(mstatus, MSTATUS_MPP, PRV_S); - mstatus = INSERT_FIELD(mstatus, MSTATUS_MPIE, 0); - write_csr(mstatus, mstatus); -} diff --git a/pk/mentry.S b/pk/mentry.S index 0bc56f0..ed1d53c 100644 --- a/pk/mentry.S +++ b/pk/mentry.S @@ -20,139 +20,35 @@ trap_table: #define HTIF_INTERRUPT_VECTOR 12 .word htif_interrupt #define TRAP_FROM_MACHINE_MODE_VECTOR 13 - .word trap_from_machine_mode - .word bad_trap - .word bad_trap + .word __trap_from_machine_mode .option norvc .section .text.init,"ax",@progbits - .globl mentry -mentry: - .align 6 - # Entry point from user mode (mtvec + 0x000) - csrrw sp, mscratch, sp - STORE a0, 10*REGBYTES(sp) - STORE a1, 11*REGBYTES(sp) + .globl reset_vector +reset_vector: + j do_reset - csrr a1, mcause - bltz a1, .Linterrupt - j .Lhandle_trap_in_machine_mode +nmi_vector: +.Lunhandleable_trap: + j bad_trap - .align 6 - # Entry point from supervisor mode (mtvec + 0x040) +trap_vector: csrrw sp, mscratch, sp + beqz sp, .Ltrap_from_machine_mode + STORE a0, 10*REGBYTES(sp) STORE a1, 11*REGBYTES(sp) csrr a1, mcause - bltz a1, .Linterrupt - j .Lhandle_trap_in_machine_mode - - .align 6 - # Entry point from hypervisor mode (mtvec + 0x080) - # Not implemented. - j bad_trap - - .align 6 - # Entry point from machine mode (mtvec + 0x0C0) - # These are rare, so punt to C code. - csrw mscratch, sp - addi sp, sp, -INTEGER_CONTEXT_SIZE - STORE a0,10*REGBYTES(sp) - STORE a1,11*REGBYTES(sp) - li a1, TRAP_FROM_MACHINE_MODE_VECTOR - j .Lhandle_trap_in_machine_mode - - nop - nop - nop - nop - nop - nop - nop - nop - nop - - # Entry point for NMIs (mtvec + 0x0FC) - # Not implemented. - j bad_trap - - # Entry point for power-on reset (mtvec + 0x100) - - # Zero registers for debuggability - li x1, 0 - li x2, 0 - li x3, 0 - li x4, 0 - li x5, 0 - li x6, 0 - li x7, 0 - li x8, 0 - li x9, 0 - li x10, 0 - li x11, 0 - li x12, 0 - li x13, 0 - li x14, 0 - li x15, 0 - li x16, 0 - li x17, 0 - li x18, 0 - li x19, 0 - li x20, 0 - li x21, 0 - li x22, 0 - li x23, 0 - li x24, 0 - li x25, 0 - li x26, 0 - li x27, 0 - li x28, 0 - li x29, 0 - li x30, 0 - li x31, 0 - - csrr a0, mhartid - bnez a0, .LmultiHart - - # sp <- end of first full page after the end of the binary - la sp, _end + 2*RISCV_PGSIZE - 1 - li t0, -RISCV_PGSIZE - and sp, sp, t0 - addi sp, sp, -MENTRY_FRAME_SIZE - - csrw mscratch, sp - j init_first_hart - -.LmultiHart: -#if MAX_HARTS > 1 - # make sure our hart id is within a valid range - li a1, MAX_HARTS - bgeu a0, a1, .LmultiHart - - # signal we're ready to boot - csrw mscratch, x0 - fence - li a1, 1 - sll a1, a1, a0 - la a2, booted_harts_mask - amoor.w x0, a1, (a2) + bgez a1, .Lhandle_trap_in_machine_mode - # wait for main hart to grant us a stack -1:csrr sp, mscratch - beqz sp, 1b + # This is an interrupt. Discard the mcause MSB and decode the rest. + sll a1, a1, 1 - j init_other_hart -#else - j .LmultiHart -#endif - -.Linterrupt: - sll a1, a1, 1 # discard MSB - - # See if this is a timer interrupt; post a supervisor interrupt if so. + # Is it a machine timer interrupt? li a0, IRQ_M_TIMER * 2 bne a0, a1, 1f + # Yes. Post a supervisor timer interrupt. li a0, MIP_MTIP csrc mie, a0 li a0, MIP_STIP @@ -166,23 +62,22 @@ mentry: eret 1: - # See if this is an IPI; register a supervisor SW interrupt if so. + # Is it an IPI? li a0, IRQ_M_SOFT * 2 bne a0, a1, 1f + # Yes. Post a supervisor software interrupt. csrc mip, MIP_MSIP csrs mip, MIP_SSIP j .Leret 1: - - # See if this is an HTIF interrupt; if so, handle it in machine mode. + # By process of elimination, it must be an HTIF interrupt. li a0, IRQ_HOST * 2 - bne a0, a1, .Lbad_trap + bne a0, a1, .Lunhandleable_trap li a1, HTIF_INTERRUPT_VECTOR .Lhandle_trap_in_machine_mode: # Preserve the registers. Compute the address of the trap handler. STORE ra, 1*REGBYTES(sp) - csrrw ra, mscratch, sp # ra <- user sp STORE gp, 3*REGBYTES(sp) STORE tp, 4*REGBYTES(sp) STORE t0, 5*REGBYTES(sp) @@ -198,6 +93,7 @@ mentry: STORE a2,12*REGBYTES(sp) csrr a2, mepc # a2 <- mepc STORE a3,13*REGBYTES(sp) + csrrw t1, mscratch, x0 # t1 <- user sp STORE a4,14*REGBYTES(sp) STORE a5,15*REGBYTES(sp) STORE a6,16*REGBYTES(sp) @@ -216,7 +112,7 @@ mentry: STORE t4,29*REGBYTES(sp) STORE t5,30*REGBYTES(sp) STORE t6,31*REGBYTES(sp) - STORE ra, 2*REGBYTES(sp) # sp + STORE t1, 2*REGBYTES(sp) # sp #ifndef __riscv_hard_float lw tp, (sp) # Move the emulated FCSR from x0's save slot into tp. @@ -230,6 +126,10 @@ mentry: sw tp, (sp) # Move the emulated FCSR from tp into x0's save slot. #endif +restore_mscratch: + # Restore mscratch, so future traps will know they didn't come from M-mode. + csrw mscratch, sp + restore_regs: # Restore all of the registers. LOAD ra, 1*REGBYTES(sp) @@ -265,13 +165,93 @@ restore_regs: LOAD sp, 2*REGBYTES(sp) eret -.globl leave -leave: +.Ltrap_from_machine_mode: csrr sp, mscratch + addi sp, sp, -INTEGER_CONTEXT_SIZE + STORE a0,10*REGBYTES(sp) + STORE a1,11*REGBYTES(sp) + li a1, TRAP_FROM_MACHINE_MODE_VECTOR + j .Lhandle_trap_in_machine_mode + + .globl __redirect_trap +__redirect_trap: + # reset sp to top of M-mode stack + li t0, MACHINE_STACK_SIZE + add sp, sp, t0 + neg t0, t0 + and sp, sp, t0 + addi sp, sp, -MENTRY_FRAME_SIZE + j restore_mscratch + +__trap_from_machine_mode: + jal trap_from_machine_mode j restore_regs -.Lbad_trap: - j bad_trap +do_reset: + li x1, 0 + li x2, 0 + li x3, 0 + li x4, 0 + li x5, 0 + li x6, 0 + li x7, 0 + li x8, 0 + li x9, 0 + li x10, 0 + li x11, 0 + li x12, 0 + li x13, 0 + li x14, 0 + li x15, 0 + li x16, 0 + li x17, 0 + li x18, 0 + li x19, 0 + li x20, 0 + li x21, 0 + li x22, 0 + li x23, 0 + li x24, 0 + li x25, 0 + li x26, 0 + li x27, 0 + li x28, 0 + li x29, 0 + li x30, 0 + li x31, 0 + csrw mscratch, x0 + + csrr a0, mhartid + bnez a0, .LmultiHart + + # sp <- end of first full page after the end of the binary + la sp, _end + 2*RISCV_PGSIZE - 1 + li t0, -RISCV_PGSIZE + and sp, sp, t0 + addi sp, sp, -MENTRY_FRAME_SIZE + + j init_first_hart + +.LmultiHart: +#if MAX_HARTS > 1 + # make sure our hart id is within a valid range + li a1, MAX_HARTS + bgeu a0, a1, .LmultiHart + + # signal we're ready to boot + li a1, 1 + sll a1, a1, a0 + la a2, booted_harts_mask + amoor.w x0, a1, (a2) + + # wait for main hart to grant us a stack +1:csrrw sp, mscratch, x0 + beqz sp, 1b + + j init_other_hart +#else + j .LmultiHart +#endif # XXX depend on sbi_base to force its linkage la x0, sbi_base @@ -121,3 +121,12 @@ void init_other_hart() boot_other_hart(); } + +void prepare_supervisor_mode() +{ + uintptr_t mstatus = read_csr(mstatus); + mstatus = INSERT_FIELD(mstatus, MSTATUS_MPP, PRV_S); + mstatus = INSERT_FIELD(mstatus, MSTATUS_MPIE, 0); + write_csr(mstatus, mstatus); + write_csr(mscratch, MACHINE_STACK_TOP() - MENTRY_FRAME_SIZE); +} @@ -62,9 +62,8 @@ void illegal_insn_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc) " .word truly_illegal_insn\n" " .popsection"); - uintptr_t mstatus = read_csr(mstatus); - - insn_t insn = get_insn(mepc); + uintptr_t mstatus; + insn_t insn = get_insn(mepc, &mstatus); if ((insn & 3) != 3) return truly_illegal_insn(regs, mcause, mepc, mstatus, insn); @@ -288,40 +287,26 @@ void mcall_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc) static void machine_page_fault(uintptr_t* regs, uintptr_t mepc) { - // See if this trap occurred when emulating an instruction on behalf of - // a lower privilege level. - extern int32_t unprivileged_access_ranges[]; - extern int32_t unprivileged_access_ranges_end[]; - int32_t* p = unprivileged_access_ranges; - do { - if (mepc >= p[0] && mepc < p[1]) { - // Yes. Redirect the trap to the supervisor. - write_csr(sbadaddr, read_csr(mbadaddr)); - redirect_trap(regs[14], regs[5]); - return; - } - p += 2; - } while (p < unprivileged_access_ranges_end); - - // No. We're boned. + // MPRV=1 iff this trap occurred while emulating an instruction on behalf + // of a lower privilege level, MPRV=1. In that case, a2=epc and a3=mstatus. + if (read_csr(mstatus) & MSTATUS_MPRV) { + write_csr(sbadaddr, read_csr(mbadaddr)); + return redirect_trap(regs[12], regs[13]); + } bad_trap(); } void trap_from_machine_mode(uintptr_t* regs, uintptr_t dummy, uintptr_t mepc) { uintptr_t mcause = read_csr(mcause); - // restore mscratch, since we clobbered it. - write_csr(mscratch, MACHINE_STACK_TOP() - MENTRY_FRAME_SIZE); switch (mcause) { case CAUSE_FAULT_LOAD: case CAUSE_FAULT_STORE: return machine_page_fault(regs, mepc); - case CAUSE_ILLEGAL_INSTRUCTION: - return bad_trap(); case CAUSE_MACHINE_ECALL: - return mcall_trap(regs, dummy, mepc); + return mcall_trap(regs, mcause, mepc); default: bad_trap(); } @@ -17,19 +17,17 @@ #define unpriv_mem_access2(a, b, c, d, e, f) ({ uintptr_t z = 0; unpriv_mem_access_base(a, b, c, d, e, f, z); }) #define unpriv_mem_access3(a, b, c, d, e, f, g) unpriv_mem_access_base(a, b, c, d, e, f, g) #define unpriv_mem_access_base(code, o0, o1, o2, i0, i1, i2) ({ \ - register uintptr_t scratch asm ("t0") = MSTATUS_MPRV; \ - register uintptr_t __mepc asm ("a4") = mepc; \ + register uintptr_t mstatus asm ("a3") = MSTATUS_MPRV; \ + register uintptr_t __mepc asm ("a2") = mepc; \ uintptr_t unused1, unused2, unused3 __attribute__((unused)); \ - asm volatile ("csrrs %[scratch], mstatus, %[scratch]\n" \ - "98: " code "\n" \ - "99: csrw mstatus, %[scratch]\n" \ - ".pushsection .unpriv,\"a\",@progbits\n" \ - ".word 98b; .word 99b\n" \ - ".popsection" \ + asm volatile ("csrrs %[mstatus], mstatus, %[mstatus]\n" \ + code "\n" \ + "csrw mstatus, %[mstatus]\n" \ : [o0] "=&r"(o0), [o1] "=&r"(o1), [o2] "=&r"(o2), \ - [scratch] "+&r"(scratch) \ + [mstatus] "+&r"(mstatus) \ : [i0] "rJ"(i0), [i1] "rJ"(i1), [i2] "rJ"(i2), \ "r"(__mepc)); \ + (mstatus); \ }) typedef uint32_t insn_t; @@ -38,7 +36,6 @@ typedef void (*emulation_func)(uintptr_t*, uintptr_t, uintptr_t, uintptr_t, insn void truly_illegal_insn(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc, uintptr_t mstatus, insn_t insn); void redirect_trap(uintptr_t epc, uintptr_t mstatus); -void leave(); #define GET_REG(insn, pos, regs) ({ \ int mask = (1 << (5+LOG_REGBYTES)) - (1 << LOG_REGBYTES); \ @@ -126,23 +123,23 @@ void leave(); #define SET_F64_RD(insn, regs, val) (SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY()) #define SET_FS_DIRTY() set_csr(mstatus, MSTATUS_FS) -static insn_t __attribute__((always_inline)) get_insn(uintptr_t mepc) +static insn_t __attribute__((always_inline)) get_insn(uintptr_t mepc, uintptr_t* mstatus) { insn_t insn; #ifdef __riscv_compressed int rvc_mask = 3, insn_hi; - unpriv_mem_access("lhu %[insn], 0(%[mepc]);" - "and %[insn_hi], %[insn], %[rvc_mask];" - "bne %[insn_hi], %[rvc_mask], 1f;" - "lh %[insn_hi], 2(%[mepc]);" - "sll %[insn_hi], %[insn_hi], 16;" - "or %[insn], %[insn], %[insn_hi];" - "1:", - insn, insn_hi, unused1, mepc, rvc_mask); + *mstatus = unpriv_mem_access("lhu %[insn], 0(%[mepc]);" + "and %[insn_hi], %[insn], %[rvc_mask];" + "bne %[insn_hi], %[rvc_mask], 1f;" + "lh %[insn_hi], 2(%[mepc]);" + "sll %[insn_hi], %[insn_hi], 16;" + "or %[insn], %[insn], %[insn_hi];" + "1:", + insn, insn_hi, unused1, mepc, rvc_mask); #else - unpriv_mem_access("lw %[insn], 0(%[mepc])", - insn, unused1, unused2, mepc); + *mstatus = unpriv_mem_access("lw %[insn], 0(%[mepc])", + insn, unused1, unused2, mepc); #endif return insn; @@ -187,6 +184,8 @@ void hls_init(uint32_t hart_id, uintptr_t* csrs); #define OTHER_STACK_TOP(id) (MACHINE_STACK_TOP() + RISCV_PGSIZE * ((id) - HLS()->hart_id)) #define OTHER_HLS(id) ((hls_t*)((void*)HLS() + RISCV_PGSIZE * ((id) - HLS()->hart_id))) +#define printk printm + #endif // !__ASSEMBLER__ #define MACHINE_STACK_SIZE RISCV_PGSIZE @@ -1,6 +1,6 @@ OUTPUT_ARCH( "riscv" ) -ENTRY( mentry ) +ENTRY( reset_vector ) SECTIONS { @@ -10,7 +10,7 @@ SECTIONS /*--------------------------------------------------------------------*/ /* Begining of code and text segment */ - . = 0x100; + . = 0; _ftext = .; PROVIDE( eprol = . ); @@ -34,10 +34,6 @@ SECTIONS *(.rodata) *(.rodata.*) *(.gnu.linkonce.r.*) - - unprivileged_access_ranges = .; - *(.unpriv) - unprivileged_access_ranges_end = .; } /* End of code and read-only segment */ |