diff --git a/src/riscv_hart.c b/src/riscv_hart.c index b39e7d818..8a31e8cfe 100644 --- a/src/riscv_hart.c +++ b/src/riscv_hart.c @@ -121,6 +121,19 @@ void riscv_hart_run(rvvm_hart_t* vm) } } +rvvm_addr_t riscv_hart_run_userland(rvvm_hart_t* vm) +{ + vm->user_traps = true; + atomic_store_uint32(&vm->wait_event, HART_RUNNING); +#ifdef USE_SJLJ + setjmp(vm->unwind); +#endif + if (atomic_load_uint32(&vm->wait_event)) { + riscv_run_till_event(vm); + } + return vm->csr.cause[PRIVILEGE_USER]; +} + #ifdef USE_RV64 void riscv_update_xlen(rvvm_hart_t* vm) { @@ -199,22 +212,30 @@ static void riscv_trap_priv_helper(rvvm_hart_t* vm, uint8_t target_priv) void riscv_trap(rvvm_hart_t* vm, bitcnt_t cause, maxlen_t tval) { - // Target privilege mode - uint8_t priv = PRIVILEGE_MACHINE; - // Delegate to lower privilege mode if needed - while ((priv > vm->priv_mode) && (vm->csr.edeleg[priv] & (1 << cause))) priv--; - //rvvm_info("Hart %p trap at %08"PRIxXLEN" -> %08"PRIxXLEN", cause %x, tval %08"PRIxXLEN"\n", vm, vm->registers[REGISTER_PC], vm->csr.tvec[priv] & (~3UL), cause, tval); - // Write exception info - vm->csr.epc[priv] = vm->registers[REGISTER_PC]; - vm->csr.cause[priv] = cause; - vm->csr.tval[priv] = tval; - // Modify exception stack in csr.status - riscv_trap_priv_helper(vm, priv); - // Jump to trap vector, switch to target priv - vm->registers[REGISTER_PC] = vm->csr.tvec[priv] & (~3ULL); vm->trap = true; - riscv_switch_priv(vm, priv); - if (cause < TRAP_ENVCALL_UMODE || cause > TRAP_ENVCALL_MMODE) riscv_jit_discard(vm); + if (cause < TRAP_ENVCALL_UMODE || cause > TRAP_ENVCALL_MMODE) { + riscv_jit_discard(vm); + } + if (vm->user_traps) { + // Defer usermode trap + vm->csr.cause[PRIVILEGE_USER] = cause; + vm->csr.tval[PRIVILEGE_USER] = tval; + } else { + // Target privilege mode + uint8_t priv = PRIVILEGE_MACHINE; + // Delegate to lower privilege mode if needed + while ((priv > vm->priv_mode) && (vm->csr.edeleg[priv] & (1 << cause))) priv--; + //rvvm_info("Hart %p trap at %08"PRIxXLEN" -> %08"PRIxXLEN", cause %x, tval %08"PRIxXLEN"\n", vm, vm->registers[REGISTER_PC], vm->csr.tvec[priv] & (~3UL), cause, tval); + // Write exception info + vm->csr.epc[priv] = vm->registers[REGISTER_PC]; + vm->csr.cause[priv] = cause; + vm->csr.tval[priv] = tval; + // Modify exception stack in csr.status + riscv_trap_priv_helper(vm, priv); + // Jump to trap vector, switch to target priv + vm->registers[REGISTER_PC] = vm->csr.tvec[priv] & (~3ULL); + riscv_switch_priv(vm, priv); + } #ifdef USE_SJLJ longjmp(vm->unwind, 1); #else diff --git a/src/riscv_hart.h b/src/riscv_hart.h index 5eced30c4..c4b4fed1c 100644 --- a/src/riscv_hart.h +++ b/src/riscv_hart.h @@ -31,12 +31,14 @@ void riscv_hart_free(rvvm_hart_t* vm); /* Hart-thread routines */ -/* - * Executes the hart in a current thread - * Returns upon receiving EXT_EVENT_PAUSE - */ +// Executes the hart in a current thread +// Returns upon receiving EXT_EVENT_PAUSE void riscv_hart_run(rvvm_hart_t* vm); +// Execute a userland context in current thread +// Returns trap cause upon any CPU trap +rvvm_addr_t riscv_hart_run_userland(rvvm_hart_t* vm); + // Correctly applies side-effects of switching privileges void riscv_switch_priv(rvvm_hart_t* vm, uint8_t priv_mode); diff --git a/src/rvvm.h b/src/rvvm.h index 13f238626..85db7ffec 100644 --- a/src/rvvm.h +++ b/src/rvvm.h @@ -214,7 +214,11 @@ struct rvvm_hart_t { uint8_t priv_mode; bool rv64; bool trap; - maxlen_t trap_pc; + + bool user_traps; + + bool lrsc; + maxlen_t lrsc_cas; struct { maxlen_t hartid; @@ -231,8 +235,6 @@ struct rvvm_hart_t { maxlen_t ip; maxlen_t fcsr; } csr; - maxlen_t lrsc_cas; - bool lrsc; #ifdef USE_JIT rvjit_block_t jit; bool jit_enabled; @@ -264,9 +266,14 @@ struct rvvm_machine_t { rvfile_t* bootrom_file; rvfile_t* kernel_file; rvfile_t* dtb_file; + rvvm_reset_handler_t on_reset; void* reset_data; + paddr_t dtb_addr; + + plic_ctx_t* plic; + pci_bus_t* pci_bus; #ifdef USE_FDT // FDT nodes for device tree generation struct fdt_node* fdt;