diff options
Diffstat (limited to 'target')
| -rw-r--r-- | target/hppa/translate.c | 15 | ||||
| -rw-r--r-- | target/i386/kvm.c | 4 | ||||
| -rw-r--r-- | target/mips/cpu.c | 2 | ||||
| -rw-r--r-- | target/mips/gdbstub.c | 3 | ||||
| -rw-r--r-- | target/mips/internal.h | 8 | ||||
| -rw-r--r-- | target/mips/op_helper.c | 24 | ||||
| -rw-r--r-- | target/riscv/Makefile.objs | 7 | ||||
| -rw-r--r-- | target/riscv/cpu.c | 19 | ||||
| -rw-r--r-- | target/riscv/cpu.h | 6 | ||||
| -rw-r--r-- | target/riscv/cpu_bits.h | 35 | ||||
| -rw-r--r-- | target/riscv/cpu_helper.c | 20 | ||||
| -rw-r--r-- | target/riscv/csr.c | 22 | ||||
| -rw-r--r-- | target/riscv/gdbstub.c | 6 | ||||
| -rw-r--r-- | target/riscv/monitor.c | 229 | ||||
| -rw-r--r-- | target/riscv/pmp.c | 35 | ||||
| -rw-r--r-- | target/riscv/trace-events | 6 | ||||
| -rw-r--r-- | target/sparc/cpu.c | 2 | ||||
| -rw-r--r-- | target/sparc/cpu.h | 8 | ||||
| -rw-r--r-- | target/sparc/ldst_helper.c | 317 | ||||
| -rw-r--r-- | target/sparc/mmu_helper.c | 57 | ||||
| -rw-r--r-- | target/xtensa/cpu.c | 24 | ||||
| -rw-r--r-- | target/xtensa/cpu.h | 3 |
22 files changed, 604 insertions, 248 deletions
diff --git a/target/hppa/translate.c b/target/hppa/translate.c index 53e17d8963..c1b2822f60 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -2214,10 +2214,11 @@ static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a) static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a) { unsigned ctl = a->t; - TCGv_reg reg = load_gpr(ctx, a->r); + TCGv_reg reg; TCGv_reg tmp; if (ctl == CR_SAR) { + reg = load_gpr(ctx, a->r); tmp = tcg_temp_new(); tcg_gen_andi_reg(tmp, reg, TARGET_REGISTER_BITS - 1); save_or_nullify(ctx, cpu_sar, tmp); @@ -2232,6 +2233,8 @@ static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a) #ifndef CONFIG_USER_ONLY nullify_over(ctx); + reg = load_gpr(ctx, a->r); + switch (ctl) { case CR_IT: gen_helper_write_interval_timer(cpu_env, reg); @@ -3401,10 +3404,6 @@ static bool do_depw_sar(DisasContext *ctx, unsigned rt, unsigned c, TCGv_reg mask, tmp, shift, dest; unsigned msb = 1U << (len - 1); - if (c) { - nullify_over(ctx); - } - dest = dest_gpr(ctx, rt); shift = tcg_temp_new(); tmp = tcg_temp_new(); @@ -3437,11 +3436,17 @@ static bool do_depw_sar(DisasContext *ctx, unsigned rt, unsigned c, static bool trans_depw_sar(DisasContext *ctx, arg_depw_sar *a) { + if (a->c) { + nullify_over(ctx); + } return do_depw_sar(ctx, a->t, a->c, a->nz, a->clen, load_gpr(ctx, a->r)); } static bool trans_depwi_sar(DisasContext *ctx, arg_depwi_sar *a) { + if (a->c) { + nullify_over(ctx); + } return do_depw_sar(ctx, a->t, a->c, a->nz, a->clen, load_const(ctx, a->i)); } diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 8023c679ea..92069099ab 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -41,6 +41,7 @@ #include "hw/i386/apic-msidef.h" #include "hw/i386/intel_iommu.h" #include "hw/i386/x86-iommu.h" +#include "hw/i386/e820_memory_layout.h" #include "hw/pci/pci.h" #include "hw/pci/msi.h" @@ -2076,7 +2077,8 @@ int kvm_arch_init(MachineState *ms, KVMState *s) if (disable_exits) { disable_exits &= (KVM_X86_DISABLE_EXITS_MWAIT | KVM_X86_DISABLE_EXITS_HLT | - KVM_X86_DISABLE_EXITS_PAUSE); + KVM_X86_DISABLE_EXITS_PAUSE | + KVM_X86_DISABLE_EXITS_CSTATE); } ret = kvm_vm_enable_cap(s, KVM_CAP_X86_DISABLE_EXITS, 0, diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 3ffa342187..bbcf7ca463 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -202,7 +202,7 @@ static void mips_cpu_class_init(ObjectClass *c, void *data) cc->gdb_read_register = mips_cpu_gdb_read_register; cc->gdb_write_register = mips_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY - cc->do_unassigned_access = mips_cpu_unassigned_access; + cc->do_transaction_failed = mips_cpu_do_transaction_failed; cc->do_unaligned_access = mips_cpu_do_unaligned_access; cc->get_phys_page_debug = mips_cpu_get_phys_page_debug; cc->vmsd = &vmstate_mips_cpu; diff --git a/target/mips/gdbstub.c b/target/mips/gdbstub.c index ebcc98bdde..bbb2544939 100644 --- a/target/mips/gdbstub.c +++ b/target/mips/gdbstub.c @@ -38,7 +38,7 @@ int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr0); default: if (env->CP0_Status & (1 << CP0St_FR)) { - return gdb_get_reg64(mem_buf, + return gdb_get_regl(mem_buf, env->active_fpu.fpr[n - 38].d); } else { return gdb_get_regl(mem_buf, @@ -99,7 +99,6 @@ int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) break; default: if (env->CP0_Status & (1 << CP0St_FR)) { - uint64_t tmp = ldq_p(mem_buf); env->active_fpu.fpr[n - 38].d = tmp; } else { env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX] = tmp; diff --git a/target/mips/internal.h b/target/mips/internal.h index ae29b578a4..685e8d67e9 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -139,9 +139,11 @@ void r4k_helper_tlbinv(CPUMIPSState *env); void r4k_helper_tlbinvf(CPUMIPSState *env); void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra); -void mips_cpu_unassigned_access(CPUState *cpu, hwaddr addr, - bool is_write, bool is_exec, int unused, - unsigned size); +void mips_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); hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, int rw); #endif diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c index 01b9e78bf3..4de64657ef 100644 --- a/target/mips/op_helper.c +++ b/target/mips/op_helper.c @@ -2668,27 +2668,19 @@ void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr, do_raise_exception_err(env, excp, error_code, retaddr); } -void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr, - bool is_write, bool is_exec, int unused, - unsigned size) +void mips_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) { MIPSCPU *cpu = MIPS_CPU(cs); CPUMIPSState *env = &cpu->env; - /* - * Raising an exception with KVM enabled will crash because it won't be from - * the main execution loop so the longjmp won't have a matching setjmp. - * Until we can trigger a bus error exception through KVM lets just ignore - * the access. - */ - if (kvm_enabled()) { - return; - } - - if (is_exec) { - raise_exception(env, EXCP_IBE); + if (access_type == MMU_INST_FETCH) { + do_raise_exception(env, EXCP_IBE, retaddr); } else { - raise_exception(env, EXCP_DBE); + do_raise_exception(env, EXCP_DBE, retaddr); } } #endif /* !CONFIG_USER_ONLY */ diff --git a/target/riscv/Makefile.objs b/target/riscv/Makefile.objs index b1c79bc1d1..ff651f69f6 100644 --- a/target/riscv/Makefile.objs +++ b/target/riscv/Makefile.objs @@ -1,4 +1,9 @@ -obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o gdbstub.o pmp.o +obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o gdbstub.o +obj-$(CONFIG_SOFTMMU) += pmp.o + +ifeq ($(CONFIG_SOFTMMU),y) +obj-y += monitor.o +endif DECODETREE = $(SRC_PATH)/scripts/decodetree.py diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 6d52f97d7c..f13e298a36 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -34,17 +34,20 @@ static const char riscv_exts[26] = "IEMAFDQCLBJTPVNSUHKORWXYZG"; const char * const riscv_int_regnames[] = { - "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", - "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", - "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", - "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6" + "x0/zero", "x1/ra", "x2/sp", "x3/gp", "x4/tp", "x5/t0", "x6/t1", + "x7/t2", "x8/s0", "x9/s1", "x10/a0", "x11/a1", "x12/a2", "x13/a3", + "x14/a4", "x15/a5", "x16/a6", "x17/a7", "x18/s2", "x19/s3", "x20/s4", + "x21/s5", "x22/s6", "x23/s7", "x24/s8", "x25/s9", "x26/s10", "x27/s11", + "x28/t3", "x29/t4", "x30/t5", "x31/t6" }; const char * const riscv_fpr_regnames[] = { - "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", - "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", - "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", - "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11" + "f0/ft0", "f1/ft1", "f2/ft2", "f3/ft3", "f4/ft4", "f5/ft5", + "f6/ft6", "f7/ft7", "f8/fs0", "f9/fs1", "f10/fa0", "f11/fa1", + "f12/fa2", "f13/fa3", "f14/fa4", "f15/fa5", "f16/fa6", "f17/fa7", + "f18/fs2", "f19/fs3", "f20/fs4", "f21/fs5", "f22/fs6", "f23/fs7", + "f24/fs8", "f25/fs9", "f26/fs10", "f27/fs11", "f28/ft8", "f29/ft9", + "f30/ft10", "f31/ft11" }; const char * const riscv_excp_names[] = { diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 18d91d0920..124ed33ee4 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -255,6 +255,7 @@ void riscv_cpu_do_interrupt(CPUState *cpu); int riscv_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request); +bool riscv_cpu_fp_enabled(CPURISCVState *env); int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch); hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, @@ -298,7 +299,10 @@ static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, #ifdef CONFIG_USER_ONLY *flags = TB_FLAGS_MSTATUS_FS; #else - *flags = cpu_mmu_index(env, 0) | (env->mstatus & MSTATUS_FS); + *flags = cpu_mmu_index(env, 0); + if (riscv_cpu_fp_enabled(env)) { + *flags |= TB_FLAGS_MSTATUS_FS; + } #endif } diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 11f971ad5d..e99834856c 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -173,6 +173,24 @@ #define CSR_SPTBR 0x180 #define CSR_SATP 0x180 +/* Hpervisor CSRs */ +#define CSR_HSTATUS 0x600 +#define CSR_HEDELEG 0x602 +#define CSR_HIDELEG 0x603 +#define CSR_HCOUNTERNEN 0x606 +#define CSR_HGATP 0x680 + +#if defined(TARGET_RISCV32) +#define HGATP_MODE SATP32_MODE +#define HGATP_VMID SATP32_ASID +#define HGATP_PPN SATP32_PPN +#endif +#if defined(TARGET_RISCV64) +#define HGATP_MODE SATP64_MODE +#define HGATP_VMID SATP64_ASID +#define HGATP_PPN SATP64_PPN +#endif + /* Physical Memory Protection */ #define CSR_PMPCFG0 0x3a0 #define CSR_PMPCFG1 0x3a1 @@ -206,23 +224,6 @@ #define CSR_DPC 0x7b1 #define CSR_DSCRATCH 0x7b2 -/* Hpervisor CSRs */ -#define CSR_HSTATUS 0xa00 -#define CSR_HEDELEG 0xa02 -#define CSR_HIDELEG 0xa03 -#define CSR_HGATP 0xa80 - -#if defined(TARGET_RISCV32) -#define HGATP_MODE SATP32_MODE -#define HGATP_ASID SATP32_ASID -#define HGATP_PPN SATP32_PPN -#endif -#if defined(TARGET_RISCV64) -#define HGATP_MODE SATP64_MODE -#define HGATP_ASID SATP64_ASID -#define HGATP_PPN SATP64_PPN -#endif - /* Performance Counters */ #define CSR_MHPMCOUNTER3 0xb03 #define CSR_MHPMCOUNTER4 0xb04 diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index e32b6126af..87dd6a6ece 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -71,6 +71,16 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request) #if !defined(CONFIG_USER_ONLY) +/* Return true is floating point support is currently enabled */ +bool riscv_cpu_fp_enabled(CPURISCVState *env) +{ + if (env->mstatus & MSTATUS_FS) { + return true; + } + + return false; +} + int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) { CPURISCVState *env = &cpu->env; @@ -176,12 +186,12 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, *prot = 0; - target_ulong base; + hwaddr base; int levels, ptidxbits, ptesize, vm, sum; int mxr = get_field(env->mstatus, MSTATUS_MXR); if (env->priv_ver >= PRIV_VERSION_1_10_0) { - base = get_field(env->satp, SATP_PPN) << PGSHIFT; + base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT; sum = get_field(env->mstatus, MSTATUS_SUM); vm = get_field(env->satp, SATP_MODE); switch (vm) { @@ -201,7 +211,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, g_assert_not_reached(); } } else { - base = env->sptbr << PGSHIFT; + base = (hwaddr)(env->sptbr) << PGSHIFT; sum = !get_field(env->mstatus, MSTATUS_PUM); vm = get_field(env->mstatus, MSTATUS_VM); switch (vm) { @@ -239,7 +249,7 @@ restart: ((1 << ptidxbits) - 1); /* check that physical address of PTE is legal */ - target_ulong pte_addr = base + idx * ptesize; + hwaddr pte_addr = base + idx * ptesize; if (riscv_feature(env, RISCV_FEATURE_PMP) && !pmp_hart_has_privs(env, pte_addr, sizeof(target_ulong), @@ -251,7 +261,7 @@ restart: #elif defined(TARGET_RISCV64) target_ulong pte = ldq_phys(cs->as, pte_addr); #endif - target_ulong ppn = pte >> PTE_PPN_SHIFT; + hwaddr ppn = pte >> PTE_PPN_SHIFT; if (!(pte & PTE_V)) { /* Invalid PTE */ diff --git a/target/riscv/csr.c b/target/riscv/csr.c index e0d4586760..f767ad24be 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -46,7 +46,7 @@ void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops) static int fs(CPURISCVState *env, int csrno) { #if !defined(CONFIG_USER_ONLY) - if (!env->debugger && !(env->mstatus & MSTATUS_FS)) { + if (!env->debugger && !riscv_cpu_fp_enabled(env)) { return -1; } #endif @@ -108,7 +108,7 @@ static int pmp(CPURISCVState *env, int csrno) static int read_fflags(CPURISCVState *env, int csrno, target_ulong *val) { #if !defined(CONFIG_USER_ONLY) - if (!env->debugger && !(env->mstatus & MSTATUS_FS)) { + if (!env->debugger && !riscv_cpu_fp_enabled(env)) { return -1; } #endif @@ -119,7 +119,7 @@ static int read_fflags(CPURISCVState *env, int csrno, target_ulong *val) static int write_fflags(CPURISCVState *env, int csrno, target_ulong val) { #if !defined(CONFIG_USER_ONLY) - if (!env->debugger && !(env->mstatus & MSTATUS_FS)) { + if (!env->debugger && !riscv_cpu_fp_enabled(env)) { return -1; } env->mstatus |= MSTATUS_FS; @@ -131,7 +131,7 @@ static int write_fflags(CPURISCVState *env, int csrno, target_ulong val) static int read_frm(CPURISCVState *env, int csrno, target_ulong *val) { #if !defined(CONFIG_USER_ONLY) - if (!env->debugger && !(env->mstatus & MSTATUS_FS)) { + if (!env->debugger && !riscv_cpu_fp_enabled(env)) { return -1; } #endif @@ -142,7 +142,7 @@ static int read_frm(CPURISCVState *env, int csrno, target_ulong *val) static int write_frm(CPURISCVState *env, int csrno, target_ulong val) { #if !defined(CONFIG_USER_ONLY) - if (!env->debugger && !(env->mstatus & MSTATUS_FS)) { + if (!env->debugger && !riscv_cpu_fp_enabled(env)) { return -1; } env->mstatus |= MSTATUS_FS; @@ -154,7 +154,7 @@ static int write_frm(CPURISCVState *env, int csrno, target_ulong val) static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val) { #if !defined(CONFIG_USER_ONLY) - if (!env->debugger && !(env->mstatus & MSTATUS_FS)) { + if (!env->debugger && !riscv_cpu_fp_enabled(env)) { return -1; } #endif @@ -166,7 +166,7 @@ static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val) static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val) { #if !defined(CONFIG_USER_ONLY) - if (!env->debugger && !(env->mstatus & MSTATUS_FS)) { + if (!env->debugger && !riscv_cpu_fp_enabled(env)) { return -1; } env->mstatus |= MSTATUS_FS; @@ -307,6 +307,7 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val) { target_ulong mstatus = env->mstatus; target_ulong mask = 0; + int dirty; /* flush tlb on mstatus fields that affect VM */ if (env->priv_ver <= PRIV_VERSION_1_09_1) { @@ -334,14 +335,15 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val) * RV32: MPV and MTL are not in mstatus. The current plan is to * add them to mstatush. For now, we just don't support it. */ - mask |= MSTATUS_MPP | MSTATUS_MPV; + mask |= MSTATUS_MTL | MSTATUS_MPV; #endif } mstatus = (mstatus & ~mask) | (val & mask); - int dirty = ((mstatus & MSTATUS_FS) == MSTATUS_FS) | - ((mstatus & MSTATUS_XS) == MSTATUS_XS); + dirty = (riscv_cpu_fp_enabled(env) && + ((mstatus & MSTATUS_FS) == MSTATUS_FS)) | + ((mstatus & MSTATUS_XS) == MSTATUS_XS); mstatus = set_field(mstatus, MSTATUS_SD, dirty); env->mstatus = mstatus; diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c index 27be93279b..ded140e8d8 100644 --- a/target/riscv/gdbstub.c +++ b/target/riscv/gdbstub.c @@ -313,7 +313,8 @@ static int riscv_gdb_get_fpu(CPURISCVState *env, uint8_t *mem_buf, int n) * register 33, so we recalculate the map index. * This also works for CSR_FRM and CSR_FCSR. */ - result = riscv_csrrw_debug(env, n - 33 + 8, &val, 0, 0); + result = riscv_csrrw_debug(env, n - 33 + csr_register_map[8], &val, + 0, 0); if (result == 0) { return gdb_get_regl(mem_buf, val); } @@ -335,7 +336,8 @@ static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n) * register 33, so we recalculate the map index. * This also works for CSR_FRM and CSR_FCSR. */ - result = riscv_csrrw_debug(env, n - 33 + 8, NULL, val, -1); + result = riscv_csrrw_debug(env, n - 33 + csr_register_map[8], NULL, + val, -1); if (result == 0) { return sizeof(target_ulong); } diff --git a/target/riscv/monitor.c b/target/riscv/monitor.c new file mode 100644 index 0000000000..d725a7a36e --- /dev/null +++ b/target/riscv/monitor.c @@ -0,0 +1,229 @@ +/* + * QEMU monitor for RISC-V + * + * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com> + * + * RISC-V specific monitor commands implementation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "cpu_bits.h" +#include "monitor/monitor.h" +#include "monitor/hmp-target.h" + +#ifdef TARGET_RISCV64 +#define PTE_HEADER_FIELDS "vaddr paddr "\ + "size attr\n" +#define PTE_HEADER_DELIMITER "---------------- ---------------- "\ + "---------------- -------\n" +#else +#define PTE_HEADER_FIELDS "vaddr paddr size attr\n" +#define PTE_HEADER_DELIMITER "-------- ---------------- -------- -------\n" +#endif + +/* Perform linear address sign extension */ +static target_ulong addr_canonical(int va_bits, target_ulong addr) +{ +#ifdef TARGET_RISCV64 + if (addr & (1UL << (va_bits - 1))) { + addr |= (hwaddr)-(1L << va_bits); + } +#endif + + return addr; +} + +static void print_pte_header(Monitor *mon) +{ + monitor_printf(mon, PTE_HEADER_FIELDS); + monitor_printf(mon, PTE_HEADER_DELIMITER); +} + +static void print_pte(Monitor *mon, int va_bits, target_ulong vaddr, + hwaddr paddr, target_ulong size, int attr) +{ + /* santity check on vaddr */ + if (vaddr >= (1UL << va_bits)) { + return; + } + + if (!size) { + return; + } + + monitor_printf(mon, TARGET_FMT_lx " " TARGET_FMT_plx " " TARGET_FMT_lx + " %c%c%c%c%c%c%c\n", + addr_canonical(va_bits, vaddr), + paddr, size, + attr & PTE_R ? 'r' : '-', + attr & PTE_W ? 'w' : '-', + attr & PTE_X ? 'x' : '-', + attr & PTE_U ? 'u' : '-', + attr & PTE_G ? 'g' : '-', + attr & PTE_A ? 'a' : '-', + attr & PTE_D ? 'd' : '-'); +} + +static void walk_pte(Monitor *mon, hwaddr base, target_ulong start, + int level, int ptidxbits, int ptesize, int va_bits, + target_ulong *vbase, hwaddr *pbase, hwaddr *last_paddr, + target_ulong *last_size, int *last_attr) +{ + hwaddr pte_addr; + hwaddr paddr; + target_ulong pgsize; + target_ulong pte; + int ptshift; + int attr; + int idx; + + if (level < 0) { + return; + } + + ptshift = level * ptidxbits; + pgsize = 1UL << (PGSHIFT + ptshift); + + for (idx = 0; idx < (1UL << ptidxbits); idx++) { + pte_addr = base + idx * ptesize; + cpu_physical_memory_read(pte_addr, &pte, ptesize); + + paddr = (hwaddr)(pte >> PTE_PPN_SHIFT) << PGSHIFT; + attr = pte & 0xff; + + /* PTE has to be valid */ + if (attr & PTE_V) { + if (attr & (PTE_R | PTE_W | PTE_X)) { + /* + * A leaf PTE has been found + * + * If current PTE's permission bits differ from the last one, + * or current PTE's ppn does not make a contiguous physical + * address block together with the last one, print out the last + * contiguous mapped block details. + */ + if ((*last_attr != attr) || + (*last_paddr + *last_size != paddr)) { + print_pte(mon, va_bits, *vbase, *pbase, + *last_paddr + *last_size - *pbase, *last_attr); + + *vbase = start; + *pbase = paddr; + *last_attr = attr; + } + + *last_paddr = paddr; + *last_size = pgsize; + } else { + /* pointer to the next level of the page table */ + walk_pte(mon, paddr, start, level - 1, ptidxbits, ptesize, + va_bits, vbase, pbase, last_paddr, + last_size, last_attr); + } + } + + start += pgsize; + } + +} + +static void mem_info_svxx(Monitor *mon, CPUArchState *env) +{ + int levels, ptidxbits, ptesize, vm, va_bits; + hwaddr base; + target_ulong vbase; + hwaddr pbase; + hwaddr last_paddr; + target_ulong last_size; + int last_attr; + + base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT; + + vm = get_field(env->satp, SATP_MODE); + switch (vm) { + case VM_1_10_SV32: + levels = 2; + ptidxbits = 10; + ptesize = 4; + break; + case VM_1_10_SV39: + levels = 3; + ptidxbits = 9; + ptesize = 8; + break; + case VM_1_10_SV48: + levels = 4; + ptidxbits = 9; + ptesize = 8; + break; + case VM_1_10_SV57: + levels = 5; + ptidxbits = 9; + ptesize = 8; + break; + default: + g_assert_not_reached(); + break; + } + + /* calculate virtual address bits */ + va_bits = PGSHIFT + levels * ptidxbits; + + /* print header */ + print_pte_header(mon); + + vbase = -1; + pbase = -1; + last_paddr = -1; + last_size = 0; + last_attr = 0; + + /* walk page tables, starting from address 0 */ + walk_pte(mon, base, 0, levels - 1, ptidxbits, ptesize, va_bits, + &vbase, &pbase, &last_paddr, &last_size, &last_attr); + + /* don't forget the last one */ + print_pte(mon, va_bits, vbase, pbase, + last_paddr + last_size - pbase, last_attr); +} + +void hmp_info_mem(Monitor *mon, const QDict *qdict) +{ + CPUArchState *env; + + env = mon_get_cpu_env(); + if (!env) { + monitor_printf(mon, "No CPU available\n"); + return; + } + + if (!riscv_feature(env, RISCV_FEATURE_MMU)) { + monitor_printf(mon, "S-mode MMU unavailable\n"); + return; + } + + if (env->priv_ver < PRIV_VERSION_1_10_0) { + monitor_printf(mon, "Privileged mode < 1.10 unsupported\n"); + return; + } + + if (!(env->satp & SATP_MODE)) { + monitor_printf(mon, "No translation or protection\n"); + return; + } + + mem_info_svxx(mon, env); +} diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index 958c7502a0..d4f1007109 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -27,16 +27,7 @@ #include "qemu/log.h" #include "qapi/error.h" #include "cpu.h" - -#ifndef CONFIG_USER_ONLY - -#define RISCV_DEBUG_PMP 0 -#define PMP_DEBUG(fmt, ...) \ - do { \ - if (RISCV_DEBUG_PMP) { \ - qemu_log_mask(LOG_TRACE, "%s: " fmt "\n", __func__, ##__VA_ARGS__);\ - } \ - } while (0) +#include "trace.h" static void pmp_write_cfg(CPURISCVState *env, uint32_t addr_index, uint8_t val); @@ -304,8 +295,7 @@ void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index, int i; uint8_t cfg_val; - PMP_DEBUG("hart " TARGET_FMT_ld ": reg%d, val: 0x" TARGET_FMT_lx, - env->mhartid, reg_index, val); + trace_pmpcfg_csr_write(env->mhartid, reg_index, val); if ((reg_index & 1) && (sizeof(target_ulong) == 8)) { qemu_log_mask(LOG_GUEST_ERROR, @@ -334,9 +324,7 @@ target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index) val = pmp_read_cfg(env, (reg_index * sizeof(target_ulong)) + i); cfg_val |= (val << (i * 8)); } - - PMP_DEBUG("hart " TARGET_FMT_ld ": reg%d, val: 0x" TARGET_FMT_lx, - env->mhartid, reg_index, cfg_val); + trace_pmpcfg_csr_read(env->mhartid, reg_index, cfg_val); return cfg_val; } @@ -348,9 +336,7 @@ target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index) void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, target_ulong val) { - PMP_DEBUG("hart " TARGET_FMT_ld ": addr%d, val: 0x" TARGET_FMT_lx, - env->mhartid, addr_index, val); - + trace_pmpaddr_csr_write(env->mhartid, addr_index, val); if (addr_index < MAX_RISCV_PMPS) { if (!pmp_is_locked(env, addr_index)) { env->pmp_state.pmp[addr_index].addr_reg = val; @@ -371,16 +357,15 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, */ target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index) { - PMP_DEBUG("hart " TARGET_FMT_ld ": addr%d, val: 0x" TARGET_FMT_lx, - env->mhartid, addr_index, - env->pmp_state.pmp[addr_index].addr_reg); + target_ulong val = 0; + if (addr_index < MAX_RISCV_PMPS) { - return env->pmp_state.pmp[addr_index].addr_reg; + val = env->pmp_state.pmp[addr_index].addr_reg; + trace_pmpaddr_csr_read(env->mhartid, addr_index, val); } else { qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpaddr read - out of bounds\n"); - return 0; } -} -#endif + return val; +} diff --git a/target/riscv/trace-events b/target/riscv/trace-events index 48af0373df..4b6c652ae9 100644 --- a/target/riscv/trace-events +++ b/target/riscv/trace-events @@ -1,2 +1,8 @@ # target/riscv/cpu_helper.c riscv_trap(uint64_t hartid, bool async, uint64_t cause, uint64_t epc, uint64_t tval, const char *desc) "hart:%"PRId64", async:%d, cause:%"PRId64", epc:0x%"PRIx64", tval:0x%"PRIx64", desc=%s" + +# pmp.c +pmpcfg_csr_read(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRIu64 ": read reg%" PRIu32", val: 0x%" PRIx64 +pmpcfg_csr_write(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRIu64 ": write reg%" PRIu32", val: 0x%" PRIx64 +pmpaddr_csr_read(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": read addr%" PRIu32", val: 0x%" PRIx64 +pmpaddr_csr_write(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": write addr%" PRIu32", val: 0x%" PRIx64 diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index ee60a5536a..bc65929552 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -877,7 +877,7 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data) cc->gdb_write_register = sparc_cpu_gdb_write_register; cc->tlb_fill = sparc_cpu_tlb_fill; #ifndef CONFIG_USER_ONLY - cc->do_unassigned_access = sparc_cpu_unassigned_access; + cc->do_transaction_failed = sparc_cpu_do_transaction_failed; cc->do_unaligned_access = sparc_cpu_do_unaligned_access; cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug; cc->vmsd = &vmstate_sparc_cpu; diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index 490e14dfcf..778aa8e073 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -614,9 +614,11 @@ static inline int tlb_compare_context(const SparcTLBEntry *tlb, /* cpu-exec.c */ #if !defined(CONFIG_USER_ONLY) -void sparc_cpu_unassigned_access(CPUState *cpu, hwaddr addr, - bool is_write, bool is_exec, int is_asi, - unsigned size); +void sparc_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); #if defined(TARGET_SPARC64) hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr, int mmu_idx); diff --git a/target/sparc/ldst_helper.c b/target/sparc/ldst_helper.c index 7f56c100c6..7345827a96 100644 --- a/target/sparc/ldst_helper.c +++ b/target/sparc/ldst_helper.c @@ -422,6 +422,99 @@ static void dump_asi(const char *txt, target_ulong addr, int asi, int size, } #endif +#ifndef CONFIG_USER_ONLY +#ifndef TARGET_SPARC64 +static void sparc_raise_mmu_fault(CPUState *cs, hwaddr addr, + bool is_write, bool is_exec, int is_asi, + unsigned size, uintptr_t retaddr) +{ + SPARCCPU *cpu = SPARC_CPU(cs); + CPUSPARCState *env = &cpu->env; + int fault_type; + +#ifdef DEBUG_UNASSIGNED + if (is_asi) { + printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx + " asi 0x%02x from " TARGET_FMT_lx "\n", + is_exec ? "exec" : is_write ? "write" : "read", size, + size == 1 ? "" : "s", addr, is_asi, env->pc); + } else { + printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx + " from " TARGET_FMT_lx "\n", + is_exec ? "exec" : is_write ? "write" : "read", size, + size == 1 ? "" : "s", addr, env->pc); + } +#endif + /* Don't overwrite translation and access faults */ + fault_type = (env->mmuregs[3] & 0x1c) >> 2; + if ((fault_type > 4) || (fault_type == 0)) { + env->mmuregs[3] = 0; /* Fault status register */ + if (is_asi) { + env->mmuregs[3] |= 1 << 16; + } + if (env->psrs) { + env->mmuregs[3] |= 1 << 5; + } + if (is_exec) { + env->mmuregs[3] |= 1 << 6; + } + if (is_write) { + env->mmuregs[3] |= 1 << 7; + } + env->mmuregs[3] |= (5 << 2) | 2; + /* SuperSPARC will never place instruction fault addresses in the FAR */ + if (!is_exec) { + env->mmuregs[4] = addr; /* Fault address register */ + } + } + /* overflow (same type fault was not read before another fault) */ + if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) { + env->mmuregs[3] |= 1; + } + + if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) { + int tt = is_exec ? TT_CODE_ACCESS : TT_DATA_ACCESS; + cpu_raise_exception_ra(env, tt, retaddr); + } + + /* + * flush neverland mappings created during no-fault mode, + * so the sequential MMU faults report proper fault types + */ + if (env->mmuregs[0] & MMU_NF) { + tlb_flush(cs); + } +} +#else +static void sparc_raise_mmu_fault(CPUState *cs, hwaddr addr, + bool is_write, bool is_exec, int is_asi, + unsigned size, uintptr_t retaddr) +{ + SPARCCPU *cpu = SPARC_CPU(cs); + CPUSPARCState *env = &cpu->env; + +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx + "\n", addr, env->pc); +#endif + + if (is_exec) { /* XXX has_hypervisor */ + if (env->lsu & (IMMU_E)) { + cpu_raise_exception_ra(env, TT_CODE_ACCESS, retaddr); + } else if (cpu_has_hypervisor(env) && !(env->hpstate & HS_PRIV)) { + cpu_raise_exception_ra(env, TT_INSN_REAL_TRANSLATION_MISS, retaddr); + } + } else { + if (env->lsu & (DMMU_E)) { + cpu_raise_exception_ra(env, TT_DATA_ACCESS, retaddr); + } else if (cpu_has_hypervisor(env) && !(env->hpstate & HS_PRIV)) { + cpu_raise_exception_ra(env, TT_DATA_REAL_TRANSLATION_MISS, retaddr); + } + } +} +#endif +#endif + #ifndef TARGET_SPARC64 #ifndef CONFIG_USER_ONLY @@ -625,26 +718,36 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, case ASI_M_DATAC_DATA: /* SparcStation 5 D-cache data */ break; case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */ + { + MemTxResult result; + hwaddr access_addr = (hwaddr)addr | ((hwaddr)(asi & 0xf) << 32); + switch (size) { case 1: - ret = ldub_phys(cs->as, (hwaddr)addr - | ((hwaddr)(asi & 0xf) << 32)); + ret = address_space_ldub(cs->as, access_addr, + MEMTXATTRS_UNSPECIFIED, &result); break; case 2: - ret = lduw_phys(cs->as, (hwaddr)addr - | ((hwaddr)(asi & 0xf) << 32)); + ret = address_space_lduw(cs->as, access_addr, + MEMTXATTRS_UNSPECIFIED, &result); break; default: case 4: - ret = ldl_phys(cs->as, (hwaddr)addr - | ((hwaddr)(asi & 0xf) << 32)); + ret = address_space_ldl(cs->as, access_addr, + MEMTXATTRS_UNSPECIFIED, &result); break; case 8: - ret = ldq_phys(cs->as, (hwaddr)addr - | ((hwaddr)(asi & 0xf) << 32)); + ret = address_space_ldq(cs->as, access_addr, + MEMTXATTRS_UNSPECIFIED, &result); break; } + + if (result != MEMTX_OK) { + sparc_raise_mmu_fault(cs, access_addr, false, false, false, + size, GETPC()); + } break; + } case 0x30: /* Turbosparc secondary cache diagnostic */ case 0x31: /* Turbosparc RAM snoop */ case 0x32: /* Turbosparc page table descriptor diagnostic */ @@ -688,7 +791,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, break; case ASI_USERTXT: /* User code access, XXX */ default: - cpu_unassigned_access(cs, addr, false, false, asi, size); + sparc_raise_mmu_fault(cs, addr, false, false, asi, size, GETPC()); ret = 0; break; @@ -777,6 +880,9 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, } break; case 0x01c00100: /* MXCC stream source */ + { + int i; + if (size == 8) { env->mxccregs[0] = val; } else { @@ -784,20 +890,27 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, "%08x: unimplemented access size: %d\n", addr, size); } - env->mxccdata[0] = ldq_phys(cs->as, - (env->mxccregs[0] & 0xffffffffULL) + - 0); - env->mxccdata[1] = ldq_phys(cs->as, - (env->mxccregs[0] & 0xffffffffULL) + - 8); - env->mxccdata[2] = ldq_phys(cs->as, - (env->mxccregs[0] & 0xffffffffULL) + - 16); - env->mxccdata[3] = ldq_phys(cs->as, - (env->mxccregs[0] & 0xffffffffULL) + - 24); + + for (i = 0; i < 4; i++) { + MemTxResult result; + hwaddr access_addr = (env->mxccregs[0] & 0xffffffffULL) + 8 * i; + + env->mxccdata[i] = address_space_ldq(cs->as, + access_addr, + MEMTXATTRS_UNSPECIFIED, + &result); + if (result != MEMTX_OK) { + /* TODO: investigate whether this is the right behaviour */ + sparc_raise_mmu_fault(cs, access_addr, false, false, + false, size, GETPC()); + } + } break; + } case 0x01c00200: /* MXCC stream destination */ + { + int i; + if (size == 8) { env->mxccregs[1] = val; } else { @@ -805,15 +918,22 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, "%08x: unimplemented access size: %d\n", addr, size); } - stq_phys(cs->as, (env->mxccregs[1] & 0xffffffffULL) + 0, - env->mxccdata[0]); - stq_phys(cs->as, (env->mxccregs[1] & 0xffffffffULL) + 8, - env->mxccdata[1]); - stq_phys(cs->as, (env->mxccregs[1] & 0xffffffffULL) + 16, - env->mxccdata[2]); - stq_phys(cs->as, (env->mxccregs[1] & 0xffffffffULL) + 24, - env->mxccdata[3]); + + for (i = 0; i < 4; i++) { + MemTxResult result; + hwaddr access_addr = (env->mxccregs[1] & 0xffffffffULL) + 8 * i; + + address_space_stq(cs->as, access_addr, env->mxccdata[i], + MEMTXATTRS_UNSPECIFIED, &result); + + if (result != MEMTX_OK) { + /* TODO: investigate whether this is the right behaviour */ + sparc_raise_mmu_fault(cs, access_addr, true, false, + false, size, GETPC()); + } + } break; + } case 0x01c00a00: /* MXCC control register */ if (size == 8) { env->mxccregs[3] = val; @@ -960,25 +1080,32 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, break; case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */ { + MemTxResult result; + hwaddr access_addr = (hwaddr)addr | ((hwaddr)(asi & 0xf) << 32); + switch (size) { case 1: - stb_phys(cs->as, (hwaddr)addr - | ((hwaddr)(asi & 0xf) << 32), val); + address_space_stb(cs->as, access_addr, val, + MEMTXATTRS_UNSPECIFIED, &result); break; case 2: - stw_phys(cs->as, (hwaddr)addr - | ((hwaddr)(asi & 0xf) << 32), val); + address_space_stw(cs->as, access_addr, val, + MEMTXATTRS_UNSPECIFIED, &result); break; case 4: default: - stl_phys(cs->as, (hwaddr)addr - | ((hwaddr)(asi & 0xf) << 32), val); + address_space_stl(cs->as, access_addr, val, + MEMTXATTRS_UNSPECIFIED, &result); break; case 8: - stq_phys(cs->as, (hwaddr)addr - | ((hwaddr)(asi & 0xf) << 32), val); + address_space_stq(cs->as, access_addr, val, + MEMTXATTRS_UNSPECIFIED, &result); break; } + if (result != MEMTX_OK) { + sparc_raise_mmu_fault(cs, access_addr, true, false, false, + size, GETPC()); + } } break; case 0x30: /* store buffer tags or Turbosparc secondary cache diagnostic */ @@ -1026,7 +1153,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, case ASI_USERTXT: /* User code access, XXX */ case ASI_KERNELTXT: /* Supervisor code access, XXX */ default: - cpu_unassigned_access(cs, addr, true, false, asi, size); + sparc_raise_mmu_fault(cs, addr, true, false, asi, size, GETPC()); break; case ASI_USERDATA: /* User data access */ @@ -1292,7 +1419,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, ret = env->immu.tag_access; break; default: - cpu_unassigned_access(cs, addr, false, false, 1, size); + sparc_raise_mmu_fault(cs, addr, false, false, 1, size, GETPC()); ret = 0; } break; @@ -1358,7 +1485,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, ret = env->dmmu.physical_watchpoint; break; default: - cpu_unassigned_access(cs, addr, false, false, 1, size); + sparc_raise_mmu_fault(cs, addr, false, false, 1, size, GETPC()); ret = 0; } break; @@ -1407,7 +1534,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, case ASI_SCRATCHPAD: /* UA2005 privileged scratchpad */ if (unlikely((addr >= 0x20) && (addr < 0x30))) { /* Hyperprivileged access only */ - cpu_unassigned_access(cs, addr, false, false, 1, size); + sparc_raise_mmu_fault(cs, addr, false, false, 1, size, GETPC()); } /* fall through */ case ASI_HYP_SCRATCHPAD: /* UA2005 hyperprivileged scratchpad */ @@ -1425,7 +1552,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, ret = env->dmmu.mmu_secondary_context; break; default: - cpu_unassigned_access(cs, addr, true, false, 1, size); + sparc_raise_mmu_fault(cs, addr, true, false, 1, size, GETPC()); } break; case ASI_DCACHE_DATA: /* D-cache data */ @@ -1448,7 +1575,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, case ASI_DMMU_DEMAP: /* D-MMU demap, WO */ case ASI_INTR_W: /* Interrupt vector, WO */ default: - cpu_unassigned_access(cs, addr, false, false, 1, size); + sparc_raise_mmu_fault(cs, addr, false, false, 1, size, GETPC()); ret = 0; break; } @@ -1622,7 +1749,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, case 8: return; default: - cpu_unassigned_access(cs, addr, true, false, 1, size); + sparc_raise_mmu_fault(cs, addr, true, false, 1, size, GETPC()); break; } @@ -1706,7 +1833,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, env->dmmu.physical_watchpoint = val; break; default: - cpu_unassigned_access(cs, addr, true, false, 1, size); + sparc_raise_mmu_fault(cs, addr, true, false, 1, size, GETPC()); break; } @@ -1750,7 +1877,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, case ASI_SCRATCHPAD: /* UA2005 privileged scratchpad */ if (unlikely((addr >= 0x20) && (addr < 0x30))) { /* Hyperprivileged access only */ - cpu_unassigned_access(cs, addr, true, false, 1, size); + sparc_raise_mmu_fault(cs, addr, true, false, 1, size, GETPC()); } /* fall through */ case ASI_HYP_SCRATCHPAD: /* UA2005 hyperprivileged scratchpad */ @@ -1776,7 +1903,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, (1 << MMU_KERNEL_SECONDARY_IDX)); break; default: - cpu_unassigned_access(cs, addr, true, false, 1, size); + sparc_raise_mmu_fault(cs, addr, true, false, 1, size, GETPC()); } } return; @@ -1808,7 +1935,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, case ASI_PNFL: /* Primary no-fault LE, RO */ case ASI_SNFL: /* Secondary no-fault LE, RO */ default: - cpu_unassigned_access(cs, addr, true, false, 1, size); + sparc_raise_mmu_fault(cs, addr, true, false, 1, size, GETPC()); return; } } @@ -1816,95 +1943,21 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, #endif /* TARGET_SPARC64 */ #if !defined(CONFIG_USER_ONLY) -#ifndef TARGET_SPARC64 -void sparc_cpu_unassigned_access(CPUState *cs, hwaddr addr, - bool is_write, bool is_exec, int is_asi, - unsigned size) -{ - SPARCCPU *cpu = SPARC_CPU(cs); - CPUSPARCState *env = &cpu->env; - int fault_type; -#ifdef DEBUG_UNASSIGNED - if (is_asi) { - printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx - " asi 0x%02x from " TARGET_FMT_lx "\n", - is_exec ? "exec" : is_write ? "write" : "read", size, - size == 1 ? "" : "s", addr, is_asi, env->pc); - } else { - printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx - " from " TARGET_FMT_lx "\n", - is_exec ? "exec" : is_write ? "write" : "read", size, - size == 1 ? "" : "s", addr, env->pc); - } -#endif - /* Don't overwrite translation and access faults */ - fault_type = (env->mmuregs[3] & 0x1c) >> 2; - if ((fault_type > 4) || (fault_type == 0)) { - env->mmuregs[3] = 0; /* Fault status register */ - if (is_asi) { - env->mmuregs[3] |= 1 << 16; - } - if (env->psrs) { - env->mmuregs[3] |= 1 << 5; - } - if (is_exec) { - env->mmuregs[3] |= 1 << 6; - } - if (is_write) { - env->mmuregs[3] |= 1 << 7; - } - env->mmuregs[3] |= (5 << 2) | 2; - /* SuperSPARC will never place instruction fault addresses in the FAR */ - if (!is_exec) { - env->mmuregs[4] = addr; /* Fault address register */ - } - } - /* overflow (same type fault was not read before another fault) */ - if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) { - env->mmuregs[3] |= 1; - } - - if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) { - int tt = is_exec ? TT_CODE_ACCESS : TT_DATA_ACCESS; - cpu_raise_exception_ra(env, tt, GETPC()); - } - - /* flush neverland mappings created during no-fault mode, - so the sequential MMU faults report proper fault types */ - if (env->mmuregs[0] & MMU_NF) { - tlb_flush(cs); - } -} -#else -void sparc_cpu_unassigned_access(CPUState *cs, hwaddr addr, - bool is_write, bool is_exec, int is_asi, - unsigned size) +void sparc_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) { - SPARCCPU *cpu = SPARC_CPU(cs); - CPUSPARCState *env = &cpu->env; - -#ifdef DEBUG_UNASSIGNED - printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx - "\n", addr, env->pc); -#endif + bool is_write = access_type == MMU_DATA_STORE; + bool is_exec = access_type == MMU_INST_FETCH; + bool is_asi = false; - if (is_exec) { /* XXX has_hypervisor */ - if (env->lsu & (IMMU_E)) { - cpu_raise_exception_ra(env, TT_CODE_ACCESS, GETPC()); - } else if (cpu_has_hypervisor(env) && !(env->hpstate & HS_PRIV)) { - cpu_raise_exception_ra(env, TT_INSN_REAL_TRANSLATION_MISS, GETPC()); - } - } else { - if (env->lsu & (DMMU_E)) { - cpu_raise_exception_ra(env, TT_DATA_ACCESS, GETPC()); - } else if (cpu_has_hypervisor(env) && !(env->hpstate & HS_PRIV)) { - cpu_raise_exception_ra(env, TT_DATA_REAL_TRANSLATION_MISS, GETPC()); - } - } + sparc_raise_mmu_fault(cs, physaddr, is_write, is_exec, + is_asi, size, retaddr); } #endif -#endif #if !defined(CONFIG_USER_ONLY) void QEMU_NORETURN sparc_cpu_do_unaligned_access(CPUState *cs, vaddr addr, diff --git a/target/sparc/mmu_helper.c b/target/sparc/mmu_helper.c index 77dc86ac5c..afbfba7b7e 100644 --- a/target/sparc/mmu_helper.c +++ b/target/sparc/mmu_helper.c @@ -98,6 +98,7 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical, int error_code = 0, is_dirty, is_user; unsigned long page_offset; CPUState *cs = env_cpu(env); + MemTxResult result; is_user = mmu_idx == MMU_USER_IDX; @@ -120,7 +121,10 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical, /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ /* Context base + context number */ pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); - pde = ldl_phys(cs->as, pde_ptr); + pde = address_space_ldl(cs->as, pde_ptr, MEMTXATTRS_UNSPECIFIED, &result); + if (result != MEMTX_OK) { + return 4 << 2; /* Translation fault, L = 0 */ + } /* Ctx pde */ switch (pde & PTE_ENTRYTYPE_MASK) { @@ -132,7 +136,11 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical, return 4 << 2; case 1: /* L0 PDE */ pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); - pde = ldl_phys(cs->as, pde_ptr); + pde = address_space_ldl(cs->as, pde_ptr, + MEMTXATTRS_UNSPECIFIED, &result); + if (result != MEMTX_OK) { + return (1 << 8) | (4 << 2); /* Translation fault, L = 1 */ + } switch (pde & PTE_ENTRYTYPE_MASK) { default: @@ -142,7 +150,11 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical, return (1 << 8) | (4 << 2); case 1: /* L1 PDE */ pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); - pde = ldl_phys(cs->as, pde_ptr); + pde = address_space_ldl(cs->as, pde_ptr, + MEMTXATTRS_UNSPECIFIED, &result); + if (result != MEMTX_OK) { + return (2 << 8) | (4 << 2); /* Translation fault, L = 2 */ + } switch (pde & PTE_ENTRYTYPE_MASK) { default: @@ -152,7 +164,11 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical, return (2 << 8) | (4 << 2); case 1: /* L2 PDE */ pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); - pde = ldl_phys(cs->as, pde_ptr); + pde = address_space_ldl(cs->as, pde_ptr, + MEMTXATTRS_UNSPECIFIED, &result); + if (result != MEMTX_OK) { + return (3 << 8) | (4 << 2); /* Translation fault, L = 3 */ + } switch (pde & PTE_ENTRYTYPE_MASK) { default: @@ -272,11 +288,20 @@ target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev) CPUState *cs = env_cpu(env); hwaddr pde_ptr; uint32_t pde; + MemTxResult result; + + /* + * TODO: MMU probe operations are supposed to set the fault + * status registers, but we don't do this. + */ /* Context base + context number */ pde_ptr = (hwaddr)(env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); - pde = ldl_phys(cs->as, pde_ptr); + pde = address_space_ldl(cs->as, pde_ptr, MEMTXATTRS_UNSPECIFIED, &result); + if (result != MEMTX_OK) { + return 0; + } switch (pde & PTE_ENTRYTYPE_MASK) { default: @@ -289,7 +314,11 @@ target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev) return pde; } pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); - pde = ldl_phys(cs->as, pde_ptr); + pde = address_space_ldl(cs->as, pde_ptr, + MEMTXATTRS_UNSPECIFIED, &result); + if (result != MEMTX_OK) { + return 0; + } switch (pde & PTE_ENTRYTYPE_MASK) { default: @@ -303,7 +332,11 @@ target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev) return pde; } pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); - pde = ldl_phys(cs->as, pde_ptr); + pde = address_space_ldl(cs->as, pde_ptr, + MEMTXATTRS_UNSPECIFIED, &result); + if (result != MEMTX_OK) { + return 0; + } switch (pde & PTE_ENTRYTYPE_MASK) { default: @@ -317,7 +350,11 @@ target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev) return pde; } pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); - pde = ldl_phys(cs->as, pde_ptr); + pde = address_space_ldl(cs->as, pde_ptr, + MEMTXATTRS_UNSPECIFIED, &result); + if (result != MEMTX_OK) { + return 0; + } switch (pde & PTE_ENTRYTYPE_MASK) { default: @@ -339,11 +376,9 @@ void dump_mmu(CPUSPARCState *env) CPUState *cs = env_cpu(env); target_ulong va, va1, va2; unsigned int n, m, o; - hwaddr pde_ptr, pa; + hwaddr pa; uint32_t pde; - pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); - pde = ldl_phys(cs->as, pde_ptr); qemu_printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n", (hwaddr)env->mmuregs[1] << 4, env->mmuregs[2]); for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 76db1741a7..c65dcf9dd7 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -53,6 +53,20 @@ static bool xtensa_cpu_has_work(CPUState *cs) #endif } +#ifdef CONFIG_USER_ONLY +static bool abi_call0; + +void xtensa_set_abi_call0(void) +{ + abi_call0 = true; +} + +bool xtensa_abi_call0(void) +{ + return abi_call0; +} +#endif + /* CPUClass::reset() */ static void xtensa_cpu_reset(CPUState *s) { @@ -70,10 +84,12 @@ static void xtensa_cpu_reset(CPUState *s) XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10; env->pending_irq_level = 0; #else - env->sregs[PS] = - (xtensa_option_enabled(env->config, - XTENSA_OPTION_WINDOWED_REGISTER) ? PS_WOE : 0) | - PS_UM | (3 << PS_RING_SHIFT); + env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT); + if (xtensa_option_enabled(env->config, + XTENSA_OPTION_WINDOWED_REGISTER) && + !xtensa_abi_call0()) { + env->sregs[PS] |= PS_WOE; + } #endif env->sregs[VECBASE] = env->config->vecbase; env->sregs[IBREAKENABLE] = 0; diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index 0459243e6b..b363ffcf10 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -673,6 +673,9 @@ static inline MemoryRegion *xtensa_get_er_region(CPUXtensaState *env) { return env->system_er; } +#else +void xtensa_set_abi_call0(void); +bool xtensa_abi_call0(void); #endif static inline uint32_t xtensa_replicate_windowstart(CPUXtensaState *env) |