diff options
Diffstat (limited to 'target/riscv')
-rw-r--r-- | target/riscv/cpu.c | 2 | ||||
-rw-r--r-- | target/riscv/cpu.h | 7 | ||||
-rw-r--r-- | target/riscv/cpu_helper.c | 28 | ||||
-rw-r--r-- | target/riscv/csr.c | 5 | ||||
-rw-r--r-- | target/riscv/gdbstub.c | 36 | ||||
-rw-r--r-- | target/riscv/pmp.c | 13 |
6 files changed, 76 insertions, 15 deletions
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index f13e298..3939963 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -484,7 +484,7 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) cc->gdb_stop_before_watchpoint = true; cc->disas_set_info = riscv_cpu_disas_set_info; #ifndef CONFIG_USER_ONLY - cc->do_unassigned_access = riscv_cpu_unassigned_access; + cc->do_transaction_failed = riscv_cpu_do_transaction_failed; cc->do_unaligned_access = riscv_cpu_do_unaligned_access; cc->get_phys_page_debug = riscv_cpu_get_phys_page_debug; #endif diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 124ed33..8c64c68 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -264,8 +264,11 @@ void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); -void riscv_cpu_unassigned_access(CPUState *cpu, hwaddr addr, bool is_write, - bool is_exec, int unused, unsigned size); +void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, + vaddr addr, unsigned size, + MMUAccessType access_type, + int mmu_idx, MemTxAttrs attrs, + MemTxResult response, uintptr_t retaddr); char *riscv_isa_string(RISCVCPU *cpu); void riscv_cpu_list(void); diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 87dd6a6..f13131a 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -169,7 +169,8 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, /* NOTE: the env->pc value visible here will not be * correct, but the value visible to the exception handler * (riscv_cpu_do_interrupt) is correct */ - + MemTxResult res; + MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; int mode = mmu_idx; if (mode == PRV_M && access_type != MMU_INST_FETCH) { @@ -256,11 +257,16 @@ restart: 1 << MMU_DATA_LOAD, PRV_S)) { return TRANSLATE_PMP_FAIL; } + #if defined(TARGET_RISCV32) - target_ulong pte = ldl_phys(cs->as, pte_addr); + target_ulong pte = address_space_ldl(cs->as, pte_addr, attrs, &res); #elif defined(TARGET_RISCV64) - target_ulong pte = ldq_phys(cs->as, pte_addr); + target_ulong pte = address_space_ldq(cs->as, pte_addr, attrs, &res); #endif + if (res != MEMTX_OK) { + return TRANSLATE_FAIL; + } + hwaddr ppn = pte >> PTE_PPN_SHIFT; if (!(pte & PTE_V)) { @@ -402,20 +408,23 @@ hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) return phys_addr; } -void riscv_cpu_unassigned_access(CPUState *cs, hwaddr addr, bool is_write, - bool is_exec, int unused, unsigned size) +void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, + vaddr addr, unsigned size, + MMUAccessType access_type, + int mmu_idx, MemTxAttrs attrs, + MemTxResult response, uintptr_t retaddr) { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; - if (is_write) { + if (access_type == MMU_DATA_STORE) { cs->exception_index = RISCV_EXCP_STORE_AMO_ACCESS_FAULT; } else { cs->exception_index = RISCV_EXCP_LOAD_ACCESS_FAULT; } env->badaddr = addr; - riscv_raise_exception(&cpu->env, cs->exception_index, GETPC()); + riscv_raise_exception(&cpu->env, cs->exception_index, retaddr); } void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, @@ -446,9 +455,9 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr) { -#ifndef CONFIG_USER_ONLY RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; +#ifndef CONFIG_USER_ONLY hwaddr pa = 0; int prot; bool pmp_violation = false; @@ -499,7 +508,10 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, case MMU_DATA_STORE: cs->exception_index = RISCV_EXCP_STORE_PAGE_FAULT; break; + default: + g_assert_not_reached(); } + env->badaddr = address; cpu_loop_exit_restore(cs, retaddr); #endif } diff --git a/target/riscv/csr.c b/target/riscv/csr.c index f767ad2..974c9c2 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -801,7 +801,10 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, #if !defined(CONFIG_USER_ONLY) int csr_priv = get_field(csrno, 0x300); int read_only = get_field(csrno, 0xC00) == 3; - if ((write_mask && read_only) || (env->priv < csr_priv)) { + if ((!env->debugger) && (env->priv < csr_priv)) { + return -1; + } + if (write_mask && read_only) { return -1; } #endif diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c index ded140e..1a7947e 100644 --- a/target/riscv/gdbstub.c +++ b/target/riscv/gdbstub.c @@ -373,6 +373,32 @@ static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n) return 0; } +static int riscv_gdb_get_virtual(CPURISCVState *cs, uint8_t *mem_buf, int n) +{ + if (n == 0) { +#ifdef CONFIG_USER_ONLY + return gdb_get_regl(mem_buf, 0); +#else + return gdb_get_regl(mem_buf, cs->priv); +#endif + } + return 0; +} + +static int riscv_gdb_set_virtual(CPURISCVState *cs, uint8_t *mem_buf, int n) +{ + if (n == 0) { +#ifndef CONFIG_USER_ONLY + cs->priv = ldtul_p(mem_buf) & 0x3; + if (cs->priv == PRV_H) { + cs->priv = PRV_S; + } +#endif + return sizeof(target_ulong); + } + return 0; +} + void riscv_cpu_register_gdb_regs_for_features(CPUState *cs) { RISCVCPU *cpu = RISCV_CPU(cs); @@ -384,7 +410,10 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs) } gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr, - 4096, "riscv-32bit-csr.xml", 0); + 240, "riscv-32bit-csr.xml", 0); + + gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual, + 1, "riscv-32bit-virtual.xml", 0); #elif defined(TARGET_RISCV64) if (env->misa & RVF) { gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu, @@ -392,6 +421,9 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs) } gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr, - 4096, "riscv-64bit-csr.xml", 0); + 240, "riscv-64bit-csr.xml", 0); + + gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual, + 1, "riscv-64bit-virtual.xml", 0); #endif } diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index d4f1007..0e6b640 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -223,6 +223,7 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, { int i = 0; int ret = -1; + int pmp_size = 0; target_ulong s = 0; target_ulong e = 0; pmp_priv_t allowed_privs = 0; @@ -232,11 +233,21 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, return true; } + /* + * if size is unknown (0), assume that all bytes + * from addr to the end of the page will be accessed. + */ + if (size == 0) { + pmp_size = -(addr | TARGET_PAGE_MASK); + } else { + pmp_size = size; + } + /* 1.10 draft priv spec states there is an implicit order from low to high */ for (i = 0; i < MAX_RISCV_PMPS; i++) { s = pmp_is_in_range(env, i, addr); - e = pmp_is_in_range(env, i, addr + size - 1); + e = pmp_is_in_range(env, i, addr + pmp_size - 1); /* partially inside */ if ((s + e) == 1) { |