lib: Handle page/access fault caused by unpriv load/store

The unpriv load/store instruction from M-mode can cause page/access
fault to M-mode if S-mode page table did not have mappings OR it did
not have PMP access permission.

To tackle this, we redirect trap back to S-mode if unpriv load/store
instruction traps in M-mode.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
This commit is contained in:
Anup Patel
2019-05-23 13:30:58 +05:30
committed by Anup Patel
parent bb915780ac
commit a6395acd6c
9 changed files with 131 additions and 44 deletions

View File

@@ -9,6 +9,7 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_unpriv.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_error.h>
@@ -134,11 +135,12 @@ int sbi_trap_redirect(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;
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;
if (mcause & (1UL << (__riscv_xlen - 1))) {
mcause &= ~(1UL << (__riscv_xlen - 1));
@@ -175,6 +177,22 @@ void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch)
rc = sbi_ecall_handler(hartid, mcause, regs, scratch);
msg = "ecall handler failed";
break;
case CAUSE_LOAD_ACCESS:
case CAUSE_STORE_ACCESS:
case CAUSE_LOAD_PAGE_FAULT:
case CAUSE_STORE_PAGE_FAULT:
uptrap = sbi_hart_get_trap_info(scratch);
if ((regs->mstatus & MSTATUS_MPRV) && uptrap) {
rc = 0;
regs->mepc += uptrap->ilen;
uptrap->cause = mcause;
uptrap->tval = mtval;
} else {
rc = sbi_trap_redirect(regs, scratch, regs->mepc,
mcause, mtval);
}
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);