From 0e1322bacbaccb34f167ebe243ab04836b99105c Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Sun, 17 Nov 2019 14:16:24 +0530 Subject: lib: Better naming of unpriv APIs for wider use The unpriv APIs can be useful to external firmware and out-of-tree platform support code. This patch adds "sbi_" prefix to unpriv load/store APIs and rename struct riscv_unpriv to struct sbi_trap_info everywhere. We also place struct sbi_trap_info in sbi/sbi_trap.h so that we can use it for sbi_trap_redirect() as well. Overall, this patch will make naming of unpriv APIs consistent with other OpenSBI APIs. Signed-off-by: Anup Patel Reviewed-by: Atish Patra --- lib/sbi/objects.mk | 2 +- lib/sbi/riscv_unpriv.c | 164 ---------------------------------------- lib/sbi/sbi_ecall.c | 15 ++-- lib/sbi/sbi_illegal_insn.c | 26 ++++--- lib/sbi/sbi_ipi.c | 8 +- lib/sbi/sbi_misaligned_ldst.c | 64 +++++++++------- lib/sbi/sbi_trap.c | 42 ++++++----- lib/sbi/sbi_unpriv.c | 171 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 261 insertions(+), 231 deletions(-) delete mode 100644 lib/sbi/riscv_unpriv.c create mode 100644 lib/sbi/sbi_unpriv.c (limited to 'lib/sbi') diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk index f2e8494..0e247fe 100644 --- a/lib/sbi/objects.mk +++ b/lib/sbi/objects.mk @@ -11,7 +11,6 @@ libsbi-objs-y += riscv_asm.o libsbi-objs-y += riscv_atomic.o libsbi-objs-y += riscv_hardfp.o libsbi-objs-y += riscv_locks.o -libsbi-objs-y += riscv_unpriv.o libsbi-objs-y += sbi_console.o libsbi-objs-y += sbi_ecall.o @@ -28,3 +27,4 @@ libsbi-objs-y += sbi_timer.o libsbi-objs-y += sbi_tlb.o libsbi-objs-y += sbi_trap.o libsbi-objs-y += sbi_string.o +libsbi-objs-y += sbi_unpriv.o diff --git a/lib/sbi/riscv_unpriv.c b/lib/sbi/riscv_unpriv.c deleted file mode 100644 index e84c23e..0000000 --- a/lib/sbi/riscv_unpriv.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2019 Western Digital Corporation or its affiliates. - * - * Authors: - * Anup Patel - */ - -#include -#include -#include -#include -#include - -#define DEFINE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \ - type load_##type(const type *addr, \ - struct sbi_scratch *scratch, \ - struct unpriv_trap *trap) \ - { \ - register ulong __mstatus asm("a2"); \ - type val = 0; \ - trap->cause = 0; \ - trap->tval = 0; \ - sbi_hart_set_trap_info(scratch, trap); \ - asm volatile( \ - "csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \ - ".option push\n" \ - ".option norvc\n" \ - #insn " %1, %2\n" \ - ".option pop\n" \ - "csrw " STR(CSR_MSTATUS) ", %0" \ - : "+&r"(__mstatus), "=&r"(val) \ - : "m"(*addr), "r"(MSTATUS_MPRV)); \ - sbi_hart_set_trap_info(scratch, NULL); \ - return val; \ - } - -#define DEFINE_UNPRIVILEGED_STORE_FUNCTION(type, insn) \ - void store_##type(type *addr, type val, \ - struct sbi_scratch *scratch, \ - struct unpriv_trap *trap) \ - { \ - register ulong __mstatus asm("a3"); \ - trap->cause = 0; \ - trap->tval = 0; \ - sbi_hart_set_trap_info(scratch, trap); \ - asm volatile( \ - "csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \ - ".option push\n" \ - ".option norvc\n" \ - #insn " %1, %2\n" \ - ".option pop\n" \ - "csrw " STR(CSR_MSTATUS) ", %0" \ - : "+&r"(__mstatus) \ - : "r"(val), "m"(*addr), "r"(MSTATUS_MPRV)); \ - sbi_hart_set_trap_info(scratch, NULL); \ - } - -DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu) -DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu) -DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb) -DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh) -DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw) -DEFINE_UNPRIVILEGED_STORE_FUNCTION(u8, sb) -DEFINE_UNPRIVILEGED_STORE_FUNCTION(u16, sh) -DEFINE_UNPRIVILEGED_STORE_FUNCTION(u32, sw) -#if __riscv_xlen == 64 -DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu) -DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld) -DEFINE_UNPRIVILEGED_STORE_FUNCTION(u64, sd) -DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld) -#else -DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw) -DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw) - -u64 load_u64(const u64 *addr, - struct sbi_scratch *scratch, struct unpriv_trap *trap) -{ - u64 ret = load_u32((u32 *)addr, scratch, trap); - - if (trap->cause) - return 0; - ret |= ((u64)load_u32((u32 *)addr + 1, scratch, trap) << 32); - if (trap->cause) - return 0; - - return ret; -} - -void store_u64(u64 *addr, u64 val, - struct sbi_scratch *scratch, struct unpriv_trap *trap) -{ - store_u32((u32 *)addr, val, scratch, trap); - if (trap->cause) - return; - - store_u32((u32 *)addr + 1, val >> 32, scratch, trap); - if (trap->cause) - return; -} -#endif - -ulong get_insn(ulong mepc, struct sbi_scratch *scratch, - struct unpriv_trap *trap) -{ - ulong __mstatus = 0, val = 0; -#ifdef __riscv_compressed - ulong rvc_mask = 3, tmp; -#endif - - trap->cause = 0; - trap->tval = 0; - sbi_hart_set_trap_info(scratch, trap); - -#ifndef __riscv_compressed - asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" - ".option push\n" - ".option norvc\n" -#if __riscv_xlen == 64 - STR(LWU) " %[insn], (%[addr])\n" -#else - STR(LW) " %[insn], (%[addr])\n" -#endif - ".option pop\n" - "csrw " STR(CSR_MSTATUS) ", %[mstatus]" - : [mstatus] "+&r"(__mstatus), [insn] "=&r"(val) - : [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(mepc)); -#else - asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" - ".option push\n" - ".option norvc\n" - "lhu %[insn], (%[addr])\n" - ".option pop\n" - "and %[tmp], %[insn], %[rvc_mask]\n" - "bne %[tmp], %[rvc_mask], 2f\n" - ".option push\n" - ".option norvc\n" - "lhu %[tmp], 2(%[addr])\n" - ".option pop\n" - "sll %[tmp], %[tmp], 16\n" - "add %[insn], %[insn], %[tmp]\n" - "2: csrw " STR(CSR_MSTATUS) ", %[mstatus]" - : [mstatus] "+&r"(__mstatus), [insn] "=&r"(val), [tmp] "=&r"(tmp) - : [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(mepc), - [rvc_mask] "r"(rvc_mask)); -#endif - - sbi_hart_set_trap_info(scratch, NULL); - switch (trap->cause) { - case CAUSE_LOAD_ACCESS: - trap->cause = CAUSE_FETCH_ACCESS; - trap->tval = mepc; - break; - case CAUSE_LOAD_PAGE_FAULT: - trap->cause = CAUSE_FETCH_PAGE_FAULT; - trap->tval = mepc; - break; - default: - break; - }; - - return val; -} diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c index 5864590..a393919 100644 --- a/lib/sbi/sbi_ecall.c +++ b/lib/sbi/sbi_ecall.c @@ -118,7 +118,7 @@ int sbi_ecall_0_1_handler(struct sbi_scratch *scratch, unsigned long extid, int ret = 0; struct sbi_tlb_info tlb_info; u32 source_hart = sbi_current_hartid(); - struct unpriv_trap uptrap = {0}; + struct sbi_trap_info uptrap = {0}; switch (extid) { case SBI_EXT_0_1_SET_TIMER: @@ -190,9 +190,8 @@ int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs, int ret = 0; unsigned long extension_id = regs->a7; unsigned long func_id = regs->a6; + struct sbi_trap_info trap = {0}; unsigned long out_val; - unsigned long out_tval; - unsigned long out_tcause; bool is_0_1_spec = 0; unsigned long args[6]; @@ -206,24 +205,24 @@ int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs, if (extension_id >= SBI_EXT_0_1_SET_TIMER && extension_id <= SBI_EXT_0_1_SHUTDOWN) { ret = sbi_ecall_0_1_handler(scratch, extension_id, args, - &out_tval, &out_tcause); + &trap.tval, &trap.cause); is_0_1_spec = 1; } else if (extension_id == SBI_EXT_BASE) ret = sbi_ecall_base_handler(scratch, extension_id, func_id, args, &out_val, - &out_tval, &out_tcause); + &trap.tval, &trap.cause); else if (extension_id >= SBI_EXT_VENDOR_START && extension_id <= SBI_EXT_VENDOR_END) { ret = sbi_ecall_vendor_ext_handler(scratch, extension_id, func_id, args, &out_val, - &out_tval, &out_tcause); + &trap.tval, &trap.cause); } else { ret = SBI_ENOTSUPP; } if (ret == SBI_ETRAP) { - sbi_trap_redirect(regs, scratch, regs->mepc, - out_tcause, out_tval); + trap.epc = regs->mepc; + sbi_trap_redirect(regs, &trap, scratch); } else { /* This function should return non-zero value only in case of * fatal error. However, there is no good way to distinguish diff --git a/lib/sbi/sbi_illegal_insn.c b/lib/sbi/sbi_illegal_insn.c index 56d51a0..021ae37 100644 --- a/lib/sbi/sbi_illegal_insn.c +++ b/lib/sbi/sbi_illegal_insn.c @@ -9,12 +9,12 @@ #include #include -#include #include #include #include #include #include +#include typedef int (*illegal_insn_func)(ulong insn, u32 hartid, ulong mcause, struct sbi_trap_regs *regs, @@ -24,7 +24,13 @@ static int truly_illegal_insn(ulong insn, u32 hartid, ulong mcause, struct sbi_trap_regs *regs, struct sbi_scratch *scratch) { - return sbi_trap_redirect(regs, scratch, regs->mepc, mcause, insn); + struct sbi_trap_info trap; + + trap.epc = regs->mepc; + trap.cause = mcause; + trap.tval = insn; + + return sbi_trap_redirect(regs, &trap, scratch); } static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause, @@ -46,8 +52,8 @@ static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause, if ((regs->mstatus & MSTATUS_MPV) && #endif (insn & INSN_MASK_WFI) == INSN_MATCH_WFI) - return sbi_trap_redirect(regs, scratch, - regs->mepc, mcause, insn); + return truly_illegal_insn(insn, hartid, mcause, + regs, scratch); if (sbi_emulate_csr_read(csr_num, hartid, regs, scratch, &csr_val)) return truly_illegal_insn(insn, hartid, mcause, @@ -130,14 +136,16 @@ int sbi_illegal_insn_handler(u32 hartid, ulong mcause, struct sbi_scratch *scratch) { ulong insn = csr_read(CSR_MTVAL); - struct unpriv_trap uptrap; + struct sbi_trap_info uptrap; if (unlikely((insn & 3) != 3)) { if (insn == 0) { - insn = get_insn(regs->mepc, scratch, &uptrap); - if (uptrap.cause) - return sbi_trap_redirect(regs, scratch, - regs->mepc, uptrap.cause, uptrap.tval); + insn = sbi_get_insn(regs->mepc, scratch, &uptrap); + if (uptrap.cause) { + uptrap.epc = regs->mepc; + return sbi_trap_redirect(regs, &uptrap, + scratch); + } } if ((insn & 3) != 3) return truly_illegal_insn(insn, hartid, mcause, regs, diff --git a/lib/sbi/sbi_ipi.c b/lib/sbi/sbi_ipi.c index 1c84f9e..af8d62d 100644 --- a/lib/sbi/sbi_ipi.c +++ b/lib/sbi/sbi_ipi.c @@ -11,12 +11,13 @@ #include #include #include -#include #include #include #include #include #include +#include +#include static unsigned long ipi_data_off; @@ -57,7 +58,8 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 hartid, u32 event, return 0; } -int sbi_ipi_send_many(struct sbi_scratch *scratch, struct unpriv_trap *uptrap, +int sbi_ipi_send_many(struct sbi_scratch *scratch, + struct sbi_trap_info *uptrap, ulong *pmask, u32 event, void *data) { ulong i, m; @@ -65,7 +67,7 @@ int sbi_ipi_send_many(struct sbi_scratch *scratch, struct unpriv_trap *uptrap, u32 hartid = sbi_current_hartid(); if (pmask) { - mask &= load_ulong(pmask, scratch, uptrap); + mask &= sbi_load_ulong(pmask, scratch, uptrap); if (uptrap->cause) return SBI_ETRAP; } diff --git a/lib/sbi/sbi_misaligned_ldst.c b/lib/sbi/sbi_misaligned_ldst.c index a41b908..57c7af4 100644 --- a/lib/sbi/sbi_misaligned_ldst.c +++ b/lib/sbi/sbi_misaligned_ldst.c @@ -9,11 +9,11 @@ #include #include -#include #include #include #include #include +#include union reg_data { u8 data_bytes[8]; @@ -26,14 +26,15 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause, struct sbi_scratch *scratch) { union reg_data val; - struct unpriv_trap uptrap; + struct sbi_trap_info uptrap; ulong addr = csr_read(CSR_MTVAL); int i, fp = 0, shift = 0, len = 0; - ulong insn = get_insn(regs->mepc, scratch, &uptrap); + ulong insn = sbi_get_insn(regs->mepc, scratch, &uptrap); - if (uptrap.cause) - return sbi_trap_redirect(regs, scratch, regs->mepc, - uptrap.cause, uptrap.tval); + if (uptrap.cause) { + uptrap.epc = regs->mepc; + return sbi_trap_redirect(regs, &uptrap, scratch); + } if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) { len = 4; @@ -96,17 +97,21 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause, #endif #endif #endif - } else - return sbi_trap_redirect(regs, scratch, regs->mepc, - mcause, addr); + } else { + uptrap.epc = regs->mepc; + uptrap.cause = mcause; + uptrap.tval = addr; + return sbi_trap_redirect(regs, &uptrap, scratch); + } val.data_u64 = 0; for (i = 0; i < len; i++) { - val.data_bytes[i] = load_u8((void *)(addr + i), - scratch, &uptrap); - if (uptrap.cause) - return sbi_trap_redirect(regs, scratch, regs->mepc, - uptrap.cause, uptrap.tval); + val.data_bytes[i] = sbi_load_u8((void *)(addr + i), + scratch, &uptrap); + if (uptrap.cause) { + uptrap.epc = regs->mepc; + return sbi_trap_redirect(regs, &uptrap, scratch); + } } if (!fp) @@ -128,14 +133,15 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause, struct sbi_scratch *scratch) { union reg_data val; - struct unpriv_trap uptrap; + struct sbi_trap_info uptrap; ulong addr = csr_read(CSR_MTVAL); int i, len = 0; - ulong insn = get_insn(regs->mepc, scratch, &uptrap); + ulong insn = sbi_get_insn(regs->mepc, scratch, &uptrap); - if (uptrap.cause) - return sbi_trap_redirect(regs, scratch, regs->mepc, - uptrap.cause, uptrap.tval); + if (uptrap.cause) { + uptrap.epc = regs->mepc; + return sbi_trap_redirect(regs, &uptrap, scratch); + } val.data_ulong = GET_RS2(insn, regs); @@ -189,16 +195,20 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause, #endif #endif #endif - } else - return sbi_trap_redirect(regs, scratch, regs->mepc, - mcause, addr); + } else { + uptrap.epc = regs->mepc; + uptrap.cause = mcause; + uptrap.tval = addr; + return sbi_trap_redirect(regs, &uptrap, scratch); + } for (i = 0; i < len; i++) { - store_u8((void *)(addr + i), val.data_bytes[i], - scratch, &uptrap); - if (uptrap.cause) - return sbi_trap_redirect(regs, scratch, regs->mepc, - uptrap.cause, uptrap.tval); + sbi_store_u8((void *)(addr + i), val.data_bytes[i], + scratch, &uptrap); + if (uptrap.cause) { + uptrap.epc = regs->mepc; + return sbi_trap_redirect(regs, &uptrap, scratch); + } } regs->mepc += INSN_LEN(insn); diff --git a/lib/sbi/sbi_trap.c b/lib/sbi/sbi_trap.c index 5274c8b..7025ad9 100644 --- a/lib/sbi/sbi_trap.c +++ b/lib/sbi/sbi_trap.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -69,15 +68,14 @@ static void __noreturn sbi_trap_error(const char *msg, int rc, u32 hartid, * Redirect trap to lower privledge mode (S-mode or U-mode) * * @param regs pointer to register state + * @param trap pointer to trap details * @param scratch pointer to sbi_scratch of current HART - * @param epc error PC for lower privledge mode - * @param cause exception cause for lower privledge mode - * @param tval trap value for lower privledge mode * * @return 0 on success and negative error code on failure */ -int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch, - ulong epc, ulong cause, ulong tval) +int sbi_trap_redirect(struct sbi_trap_regs *regs, + struct sbi_trap_info *trap, + struct sbi_scratch *scratch) { ulong hstatus, vsstatus, prev_mode; #if __riscv_xlen == 32 @@ -97,7 +95,7 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch, /* For certain exceptions from VS/VU-mode we redirect to VS-mode */ if (misa_extension('H') && prev_virt && !prev_stage2) { - switch (cause) { + switch (trap->cause) { case CAUSE_FETCH_PAGE_FAULT: case CAUSE_LOAD_PAGE_FAULT: case CAUSE_STORE_PAGE_FAULT: @@ -137,9 +135,9 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch, /* Update exception related CSRs */ if (next_virt) { /* Update VS-mode exception info */ - csr_write(CSR_VSTVAL, tval); - csr_write(CSR_VSEPC, epc); - csr_write(CSR_VSCAUSE, cause); + csr_write(CSR_VSTVAL, trap->tval); + csr_write(CSR_VSEPC, trap->epc); + csr_write(CSR_VSCAUSE, trap->cause); /* Set MEPC to VS-mode exception vector base */ regs->mepc = csr_read(CSR_VSTVEC); @@ -168,9 +166,9 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch, csr_write(CSR_VSSTATUS, vsstatus); } else { /* Update S-mode exception info */ - csr_write(CSR_STVAL, tval); - csr_write(CSR_SEPC, epc); - csr_write(CSR_SCAUSE, cause); + csr_write(CSR_STVAL, trap->tval); + csr_write(CSR_SEPC, trap->epc); + csr_write(CSR_SCAUSE, trap->cause); /* Set MEPC to S-mode exception vector base */ regs->mepc = csr_read(CSR_STVEC); @@ -211,14 +209,15 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch, * @param regs pointer to register state * @param scratch pointer to sbi_scratch of current HART */ -void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch) +void sbi_trap_handler(struct sbi_trap_regs *regs, + struct sbi_scratch *scratch) { int rc = SBI_ENOTSUPP; const char *msg = "trap handler failed"; u32 hartid = sbi_current_hartid(); ulong mcause = csr_read(CSR_MCAUSE); ulong mtval = csr_read(CSR_MTVAL); - struct unpriv_trap *uptrap; + struct sbi_trap_info trap, *uptrap; if (mcause & (1UL << (__riscv_xlen - 1))) { mcause &= ~(1UL << (__riscv_xlen - 1)); @@ -262,19 +261,24 @@ void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch) uptrap = sbi_hart_get_trap_info(scratch); if ((regs->mstatus & MSTATUS_MPRV) && uptrap) { rc = 0; + uptrap->epc = regs->mepc; regs->mepc += 4; uptrap->cause = mcause; uptrap->tval = mtval; } else { - rc = sbi_trap_redirect(regs, scratch, regs->mepc, - mcause, mtval); + trap.epc = regs->mepc; + trap.cause = mcause; + trap.tval = mtval; + rc = sbi_trap_redirect(regs, &trap, scratch); } msg = "page/access fault handler failed"; break; default: /* If the trap came from S or U mode, redirect it there */ - rc = sbi_trap_redirect(regs, scratch, regs->mepc, - mcause, mtval); + trap.epc = regs->mepc; + trap.cause = mcause; + trap.tval = mtval; + rc = sbi_trap_redirect(regs, &trap, scratch); break; }; diff --git a/lib/sbi/sbi_unpriv.c b/lib/sbi/sbi_unpriv.c new file mode 100644 index 0000000..aa74c43 --- /dev/null +++ b/lib/sbi/sbi_unpriv.c @@ -0,0 +1,171 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Anup Patel + */ + +#include +#include +#include +#include +#include +#include + +#define DEFINE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \ + type sbi_load_##type(const type *addr, \ + struct sbi_scratch *scratch, \ + struct sbi_trap_info *trap) \ + { \ + register ulong __mstatus asm("a2"); \ + type val = 0; \ + trap->epc = 0; \ + trap->cause = 0; \ + trap->tval = 0; \ + sbi_hart_set_trap_info(scratch, trap); \ + asm volatile( \ + "csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \ + ".option push\n" \ + ".option norvc\n" \ + #insn " %1, %2\n" \ + ".option pop\n" \ + "csrw " STR(CSR_MSTATUS) ", %0" \ + : "+&r"(__mstatus), "=&r"(val) \ + : "m"(*addr), "r"(MSTATUS_MPRV)); \ + sbi_hart_set_trap_info(scratch, NULL); \ + return val; \ + } + +#define DEFINE_UNPRIVILEGED_STORE_FUNCTION(type, insn) \ + void sbi_store_##type(type *addr, type val, \ + struct sbi_scratch *scratch, \ + struct sbi_trap_info *trap) \ + { \ + register ulong __mstatus asm("a3"); \ + trap->epc = 0; \ + trap->cause = 0; \ + trap->tval = 0; \ + sbi_hart_set_trap_info(scratch, trap); \ + asm volatile( \ + "csrrs %0, " STR(CSR_MSTATUS) ", %3\n" \ + ".option push\n" \ + ".option norvc\n" \ + #insn " %1, %2\n" \ + ".option pop\n" \ + "csrw " STR(CSR_MSTATUS) ", %0" \ + : "+&r"(__mstatus) \ + : "r"(val), "m"(*addr), "r"(MSTATUS_MPRV)); \ + sbi_hart_set_trap_info(scratch, NULL); \ + } + +DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu) +DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu) +DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb) +DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh) +DEFINE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw) +DEFINE_UNPRIVILEGED_STORE_FUNCTION(u8, sb) +DEFINE_UNPRIVILEGED_STORE_FUNCTION(u16, sh) +DEFINE_UNPRIVILEGED_STORE_FUNCTION(u32, sw) +#if __riscv_xlen == 64 +DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu) +DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld) +DEFINE_UNPRIVILEGED_STORE_FUNCTION(u64, sd) +DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld) +#else +DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw) +DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw) + +u64 sbi_load_u64(const u64 *addr, + struct sbi_scratch *scratch, + struct sbi_trap_info *trap) +{ + u64 ret = sbi_load_u32((u32 *)addr, scratch, trap); + + if (trap->cause) + return 0; + ret |= ((u64)sbi_load_u32((u32 *)addr + 1, scratch, trap) << 32); + if (trap->cause) + return 0; + + return ret; +} + +void sbi_store_u64(u64 *addr, u64 val, + struct sbi_scratch *scratch, + struct sbi_trap_info *trap) +{ + sbi_store_u32((u32 *)addr, val, scratch, trap); + if (trap->cause) + return; + + sbi_store_u32((u32 *)addr + 1, val >> 32, scratch, trap); + if (trap->cause) + return; +} +#endif + +ulong sbi_get_insn(ulong mepc, struct sbi_scratch *scratch, + struct sbi_trap_info *trap) +{ + ulong __mstatus = 0, val = 0; +#ifdef __riscv_compressed + ulong rvc_mask = 3, tmp; +#endif + + trap->epc = 0; + trap->cause = 0; + trap->tval = 0; + sbi_hart_set_trap_info(scratch, trap); + +#ifndef __riscv_compressed + asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" + ".option push\n" + ".option norvc\n" +#if __riscv_xlen == 64 + STR(LWU) " %[insn], (%[addr])\n" +#else + STR(LW) " %[insn], (%[addr])\n" +#endif + ".option pop\n" + "csrw " STR(CSR_MSTATUS) ", %[mstatus]" + : [mstatus] "+&r"(__mstatus), [insn] "=&r"(val) + : [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(mepc)); +#else + asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" + ".option push\n" + ".option norvc\n" + "lhu %[insn], (%[addr])\n" + ".option pop\n" + "and %[tmp], %[insn], %[rvc_mask]\n" + "bne %[tmp], %[rvc_mask], 2f\n" + ".option push\n" + ".option norvc\n" + "lhu %[tmp], 2(%[addr])\n" + ".option pop\n" + "sll %[tmp], %[tmp], 16\n" + "add %[insn], %[insn], %[tmp]\n" + "2: csrw " STR(CSR_MSTATUS) ", %[mstatus]" + : [mstatus] "+&r"(__mstatus), [insn] "=&r"(val), [tmp] "=&r"(tmp) + : [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(mepc), + [rvc_mask] "r"(rvc_mask)); +#endif + + sbi_hart_set_trap_info(scratch, NULL); + + switch (trap->cause) { + case CAUSE_LOAD_ACCESS: + trap->cause = CAUSE_FETCH_ACCESS; + trap->tval = mepc; + break; + case CAUSE_LOAD_PAGE_FAULT: + trap->cause = CAUSE_FETCH_PAGE_FAULT; + trap->tval = mepc; + break; + default: + break; + }; + + return val; +} -- cgit v1.2.3