diff options
Diffstat (limited to 'target/arm/helper.c')
-rw-r--r-- | target/arm/helper.c | 338 |
1 files changed, 235 insertions, 103 deletions
diff --git a/target/arm/helper.c b/target/arm/helper.c index 8a3e4480aa..2594faa9b8 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -485,7 +485,7 @@ static void contextidr_write(CPUARMState *env, const ARMCPRegInfo *ri, { ARMCPU *cpu = arm_env_get_cpu(env); - if (raw_read(env, ri) != value && !arm_feature(env, ARM_FEATURE_MPU) + if (raw_read(env, ri) != value && !arm_feature(env, ARM_FEATURE_PMSA) && !extended_addresses_enabled(env)) { /* For VMSA (when not using the LPAE long descriptor page table * format) this register includes the ASID, so do a TLB flush. @@ -571,9 +571,9 @@ static void tlbiall_nsnh_write(CPUARMState *env, const ARMCPRegInfo *ri, CPUState *cs = ENV_GET_CPU(env); tlb_flush_by_mmuidx(cs, - (1 << ARMMMUIdx_S12NSE1) | - (1 << ARMMMUIdx_S12NSE0) | - (1 << ARMMMUIdx_S2NS)); + ARMMMUIdxBit_S12NSE1 | + ARMMMUIdxBit_S12NSE0 | + ARMMMUIdxBit_S2NS); } static void tlbiall_nsnh_is_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -582,9 +582,9 @@ static void tlbiall_nsnh_is_write(CPUARMState *env, const ARMCPRegInfo *ri, CPUState *cs = ENV_GET_CPU(env); tlb_flush_by_mmuidx_all_cpus_synced(cs, - (1 << ARMMMUIdx_S12NSE1) | - (1 << ARMMMUIdx_S12NSE0) | - (1 << ARMMMUIdx_S2NS)); + ARMMMUIdxBit_S12NSE1 | + ARMMMUIdxBit_S12NSE0 | + ARMMMUIdxBit_S2NS); } static void tlbiipas2_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -605,7 +605,7 @@ static void tlbiipas2_write(CPUARMState *env, const ARMCPRegInfo *ri, pageaddr = sextract64(value << 12, 0, 40); - tlb_flush_page_by_mmuidx(cs, pageaddr, (1 << ARMMMUIdx_S2NS)); + tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_S2NS); } static void tlbiipas2_is_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -621,7 +621,7 @@ static void tlbiipas2_is_write(CPUARMState *env, const ARMCPRegInfo *ri, pageaddr = sextract64(value << 12, 0, 40); tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, - (1 << ARMMMUIdx_S2NS)); + ARMMMUIdxBit_S2NS); } static void tlbiall_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -629,7 +629,7 @@ static void tlbiall_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri, { CPUState *cs = ENV_GET_CPU(env); - tlb_flush_by_mmuidx(cs, (1 << ARMMMUIdx_S1E2)); + tlb_flush_by_mmuidx(cs, ARMMMUIdxBit_S1E2); } static void tlbiall_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -637,7 +637,7 @@ static void tlbiall_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri, { CPUState *cs = ENV_GET_CPU(env); - tlb_flush_by_mmuidx_all_cpus_synced(cs, (1 << ARMMMUIdx_S1E2)); + tlb_flush_by_mmuidx_all_cpus_synced(cs, ARMMMUIdxBit_S1E2); } static void tlbimva_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -646,7 +646,7 @@ static void tlbimva_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri, CPUState *cs = ENV_GET_CPU(env); uint64_t pageaddr = value & ~MAKE_64BIT_MASK(0, 12); - tlb_flush_page_by_mmuidx(cs, pageaddr, (1 << ARMMMUIdx_S1E2)); + tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_S1E2); } static void tlbimva_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -656,7 +656,7 @@ static void tlbimva_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t pageaddr = value & ~MAKE_64BIT_MASK(0, 12); tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, - (1 << ARMMMUIdx_S1E2)); + ARMMMUIdxBit_S1E2); } static const ARMCPRegInfo cp_reginfo[] = { @@ -2596,9 +2596,9 @@ static void vttbr_write(CPUARMState *env, const ARMCPRegInfo *ri, /* Accesses to VTTBR may change the VMID so we must flush the TLB. */ if (raw_read(env, ri) != value) { tlb_flush_by_mmuidx(cs, - (1 << ARMMMUIdx_S12NSE1) | - (1 << ARMMMUIdx_S12NSE0) | - (1 << ARMMMUIdx_S2NS)); + ARMMMUIdxBit_S12NSE1 | + ARMMMUIdxBit_S12NSE0 | + ARMMMUIdxBit_S2NS); raw_write(env, ri, value); } } @@ -2957,12 +2957,12 @@ static void tlbi_aa64_vmalle1_write(CPUARMState *env, const ARMCPRegInfo *ri, if (arm_is_secure_below_el3(env)) { tlb_flush_by_mmuidx(cs, - (1 << ARMMMUIdx_S1SE1) | - (1 << ARMMMUIdx_S1SE0)); + ARMMMUIdxBit_S1SE1 | + ARMMMUIdxBit_S1SE0); } else { tlb_flush_by_mmuidx(cs, - (1 << ARMMMUIdx_S12NSE1) | - (1 << ARMMMUIdx_S12NSE0)); + ARMMMUIdxBit_S12NSE1 | + ARMMMUIdxBit_S12NSE0); } } @@ -2974,12 +2974,12 @@ static void tlbi_aa64_vmalle1is_write(CPUARMState *env, const ARMCPRegInfo *ri, if (sec) { tlb_flush_by_mmuidx_all_cpus_synced(cs, - (1 << ARMMMUIdx_S1SE1) | - (1 << ARMMMUIdx_S1SE0)); + ARMMMUIdxBit_S1SE1 | + ARMMMUIdxBit_S1SE0); } else { tlb_flush_by_mmuidx_all_cpus_synced(cs, - (1 << ARMMMUIdx_S12NSE1) | - (1 << ARMMMUIdx_S12NSE0)); + ARMMMUIdxBit_S12NSE1 | + ARMMMUIdxBit_S12NSE0); } } @@ -2995,18 +2995,18 @@ static void tlbi_aa64_alle1_write(CPUARMState *env, const ARMCPRegInfo *ri, if (arm_is_secure_below_el3(env)) { tlb_flush_by_mmuidx(cs, - (1 << ARMMMUIdx_S1SE1) | - (1 << ARMMMUIdx_S1SE0)); + ARMMMUIdxBit_S1SE1 | + ARMMMUIdxBit_S1SE0); } else { if (arm_feature(env, ARM_FEATURE_EL2)) { tlb_flush_by_mmuidx(cs, - (1 << ARMMMUIdx_S12NSE1) | - (1 << ARMMMUIdx_S12NSE0) | - (1 << ARMMMUIdx_S2NS)); + ARMMMUIdxBit_S12NSE1 | + ARMMMUIdxBit_S12NSE0 | + ARMMMUIdxBit_S2NS); } else { tlb_flush_by_mmuidx(cs, - (1 << ARMMMUIdx_S12NSE1) | - (1 << ARMMMUIdx_S12NSE0)); + ARMMMUIdxBit_S12NSE1 | + ARMMMUIdxBit_S12NSE0); } } } @@ -3017,7 +3017,7 @@ static void tlbi_aa64_alle2_write(CPUARMState *env, const ARMCPRegInfo *ri, ARMCPU *cpu = arm_env_get_cpu(env); CPUState *cs = CPU(cpu); - tlb_flush_by_mmuidx(cs, (1 << ARMMMUIdx_S1E2)); + tlb_flush_by_mmuidx(cs, ARMMMUIdxBit_S1E2); } static void tlbi_aa64_alle3_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3026,7 +3026,7 @@ static void tlbi_aa64_alle3_write(CPUARMState *env, const ARMCPRegInfo *ri, ARMCPU *cpu = arm_env_get_cpu(env); CPUState *cs = CPU(cpu); - tlb_flush_by_mmuidx(cs, (1 << ARMMMUIdx_S1E3)); + tlb_flush_by_mmuidx(cs, ARMMMUIdxBit_S1E3); } static void tlbi_aa64_alle1is_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3042,17 +3042,17 @@ static void tlbi_aa64_alle1is_write(CPUARMState *env, const ARMCPRegInfo *ri, if (sec) { tlb_flush_by_mmuidx_all_cpus_synced(cs, - (1 << ARMMMUIdx_S1SE1) | - (1 << ARMMMUIdx_S1SE0)); + ARMMMUIdxBit_S1SE1 | + ARMMMUIdxBit_S1SE0); } else if (has_el2) { tlb_flush_by_mmuidx_all_cpus_synced(cs, - (1 << ARMMMUIdx_S12NSE1) | - (1 << ARMMMUIdx_S12NSE0) | - (1 << ARMMMUIdx_S2NS)); + ARMMMUIdxBit_S12NSE1 | + ARMMMUIdxBit_S12NSE0 | + ARMMMUIdxBit_S2NS); } else { tlb_flush_by_mmuidx_all_cpus_synced(cs, - (1 << ARMMMUIdx_S12NSE1) | - (1 << ARMMMUIdx_S12NSE0)); + ARMMMUIdxBit_S12NSE1 | + ARMMMUIdxBit_S12NSE0); } } @@ -3061,7 +3061,7 @@ static void tlbi_aa64_alle2is_write(CPUARMState *env, const ARMCPRegInfo *ri, { CPUState *cs = ENV_GET_CPU(env); - tlb_flush_by_mmuidx_all_cpus_synced(cs, (1 << ARMMMUIdx_S1E2)); + tlb_flush_by_mmuidx_all_cpus_synced(cs, ARMMMUIdxBit_S1E2); } static void tlbi_aa64_alle3is_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3069,7 +3069,7 @@ static void tlbi_aa64_alle3is_write(CPUARMState *env, const ARMCPRegInfo *ri, { CPUState *cs = ENV_GET_CPU(env); - tlb_flush_by_mmuidx_all_cpus_synced(cs, (1 << ARMMMUIdx_S1E3)); + tlb_flush_by_mmuidx_all_cpus_synced(cs, ARMMMUIdxBit_S1E3); } static void tlbi_aa64_vae1_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3086,12 +3086,12 @@ static void tlbi_aa64_vae1_write(CPUARMState *env, const ARMCPRegInfo *ri, if (arm_is_secure_below_el3(env)) { tlb_flush_page_by_mmuidx(cs, pageaddr, - (1 << ARMMMUIdx_S1SE1) | - (1 << ARMMMUIdx_S1SE0)); + ARMMMUIdxBit_S1SE1 | + ARMMMUIdxBit_S1SE0); } else { tlb_flush_page_by_mmuidx(cs, pageaddr, - (1 << ARMMMUIdx_S12NSE1) | - (1 << ARMMMUIdx_S12NSE0)); + ARMMMUIdxBit_S12NSE1 | + ARMMMUIdxBit_S12NSE0); } } @@ -3106,7 +3106,7 @@ static void tlbi_aa64_vae2_write(CPUARMState *env, const ARMCPRegInfo *ri, CPUState *cs = CPU(cpu); uint64_t pageaddr = sextract64(value << 12, 0, 56); - tlb_flush_page_by_mmuidx(cs, pageaddr, (1 << ARMMMUIdx_S1E2)); + tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_S1E2); } static void tlbi_aa64_vae3_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3120,7 +3120,7 @@ static void tlbi_aa64_vae3_write(CPUARMState *env, const ARMCPRegInfo *ri, CPUState *cs = CPU(cpu); uint64_t pageaddr = sextract64(value << 12, 0, 56); - tlb_flush_page_by_mmuidx(cs, pageaddr, (1 << ARMMMUIdx_S1E3)); + tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_S1E3); } static void tlbi_aa64_vae1is_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3133,12 +3133,12 @@ static void tlbi_aa64_vae1is_write(CPUARMState *env, const ARMCPRegInfo *ri, if (sec) { tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, - (1 << ARMMMUIdx_S1SE1) | - (1 << ARMMMUIdx_S1SE0)); + ARMMMUIdxBit_S1SE1 | + ARMMMUIdxBit_S1SE0); } else { tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, - (1 << ARMMMUIdx_S12NSE1) | - (1 << ARMMMUIdx_S12NSE0)); + ARMMMUIdxBit_S12NSE1 | + ARMMMUIdxBit_S12NSE0); } } @@ -3149,7 +3149,7 @@ static void tlbi_aa64_vae2is_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t pageaddr = sextract64(value << 12, 0, 56); tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, - (1 << ARMMMUIdx_S1E2)); + ARMMMUIdxBit_S1E2); } static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3159,7 +3159,7 @@ static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t pageaddr = sextract64(value << 12, 0, 56); tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, - (1 << ARMMMUIdx_S1E3)); + ARMMMUIdxBit_S1E3); } static void tlbi_aa64_ipas2e1_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3181,7 +3181,7 @@ static void tlbi_aa64_ipas2e1_write(CPUARMState *env, const ARMCPRegInfo *ri, pageaddr = sextract64(value << 12, 0, 48); - tlb_flush_page_by_mmuidx(cs, pageaddr, (1 << ARMMMUIdx_S2NS)); + tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_S2NS); } static void tlbi_aa64_ipas2e1is_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3197,7 +3197,7 @@ static void tlbi_aa64_ipas2e1is_write(CPUARMState *env, const ARMCPRegInfo *ri, pageaddr = sextract64(value << 12, 0, 48); tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr, - (1 << ARMMMUIdx_S2NS)); + ARMMMUIdxBit_S2NS); } static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri, @@ -3258,6 +3258,11 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, return; } + if (arm_feature(env, ARM_FEATURE_PMSA) && !cpu->has_mpu) { + /* M bit is RAZ/WI for PMSA with no MPU implemented */ + value &= ~SCTLR_M; + } + raw_write(env, ri, value); /* ??? Lots of these bits are not implemented. */ /* This may enable/disable the MMU, so do a TLB flush. */ @@ -4615,7 +4620,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, v6k_cp_reginfo); } if (arm_feature(env, ARM_FEATURE_V7MP) && - !arm_feature(env, ARM_FEATURE_MPU)) { + !arm_feature(env, ARM_FEATURE_PMSA)) { define_arm_cp_regs(cpu, v7mp_cp_reginfo); } if (arm_feature(env, ARM_FEATURE_V7)) { @@ -4969,7 +4974,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) } } - if (arm_feature(env, ARM_FEATURE_MPU)) { + if (arm_feature(env, ARM_FEATURE_PMSA)) { if (arm_feature(env, ARM_FEATURE_V6)) { /* PMSAv6 not implemented */ assert(arm_feature(env, ARM_FEATURE_V7)); @@ -5131,7 +5136,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, id_pre_v8_midr_cp_reginfo); } define_arm_cp_regs(cpu, id_cp_reginfo); - if (!arm_feature(env, ARM_FEATURE_MPU)) { + if (!arm_feature(env, ARM_FEATURE_PMSA)) { define_one_arm_cp_reg(cpu, &id_tlbtr_reginfo); } else if (arm_feature(env, ARM_FEATURE_V7)) { define_one_arm_cp_reg(cpu, &id_mpuir_reginfo); @@ -6337,10 +6342,49 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) break; case EXCP_PREFETCH_ABORT: case EXCP_DATA_ABORT: - /* TODO: if we implemented the MPU registers, this is where we - * should set the MMFAR, etc from exception.fsr and exception.vaddress. + /* Note that for M profile we don't have a guest facing FSR, but + * the env->exception.fsr will be populated by the code that + * raises the fault, in the A profile short-descriptor format. */ - armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM); + switch (env->exception.fsr & 0xf) { + case 0x8: /* External Abort */ + switch (cs->exception_index) { + case EXCP_PREFETCH_ABORT: + env->v7m.cfsr |= R_V7M_CFSR_PRECISERR_MASK; + qemu_log_mask(CPU_LOG_INT, "...with CFSR.PRECISERR\n"); + break; + case EXCP_DATA_ABORT: + env->v7m.cfsr |= + (R_V7M_CFSR_IBUSERR_MASK | R_V7M_CFSR_BFARVALID_MASK); + env->v7m.bfar = env->exception.vaddress; + qemu_log_mask(CPU_LOG_INT, + "...with CFSR.IBUSERR and BFAR 0x%x\n", + env->v7m.bfar); + break; + } + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS); + break; + default: + /* All other FSR values are either MPU faults or "can't happen + * for M profile" cases. + */ + switch (cs->exception_index) { + case EXCP_PREFETCH_ABORT: + env->v7m.cfsr |= R_V7M_CFSR_IACCVIOL_MASK; + qemu_log_mask(CPU_LOG_INT, "...with CFSR.IACCVIOL\n"); + break; + case EXCP_DATA_ABORT: + env->v7m.cfsr |= + (R_V7M_CFSR_DACCVIOL_MASK | R_V7M_CFSR_MMARVALID_MASK); + env->v7m.mmfar = env->exception.vaddress; + qemu_log_mask(CPU_LOG_INT, + "...with CFSR.DACCVIOL and MMFAR 0x%x\n", + env->v7m.mmfar); + break; + } + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM); + break; + } break; case EXCP_BKPT: if (semihosting_enabled()) { @@ -6992,6 +7036,9 @@ static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx) case ARMMMUIdx_S1SE1: case ARMMMUIdx_S1NSE0: case ARMMMUIdx_S1NSE1: + case ARMMMUIdx_MPriv: + case ARMMMUIdx_MNegPri: + case ARMMMUIdx_MUser: return 1; default: g_assert_not_reached(); @@ -7008,6 +7055,9 @@ static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx) case ARMMMUIdx_S1NSE1: case ARMMMUIdx_S1E2: case ARMMMUIdx_S2NS: + case ARMMMUIdx_MPriv: + case ARMMMUIdx_MNegPri: + case ARMMMUIdx_MUser: return false; case ARMMMUIdx_S1E3: case ARMMMUIdx_S1SE0: @@ -7028,6 +7078,24 @@ static inline uint32_t regime_sctlr(CPUARMState *env, ARMMMUIdx mmu_idx) static inline bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx) { + if (arm_feature(env, ARM_FEATURE_M)) { + switch (env->v7m.mpu_ctrl & + (R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK)) { + case R_V7M_MPU_CTRL_ENABLE_MASK: + /* Enabled, but not for HardFault and NMI */ + return mmu_idx == ARMMMUIdx_MNegPri; + case R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK: + /* Enabled for all cases */ + return false; + case 0: + default: + /* HFNMIENA set and ENABLE clear is UNPREDICTABLE, but + * we warned about that in armv7m_nvic.c when the guest set it. + */ + return true; + } + } + if (mmu_idx == ARMMMUIdx_S2NS) { return (env->cp15.hcr_el2 & HCR_VM) == 0; } @@ -7049,6 +7117,17 @@ static inline TCR *regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx) return &env->cp15.tcr_el[regime_el(env, mmu_idx)]; } +/* Convert a possible stage1+2 MMU index into the appropriate + * stage 1 MMU index + */ +static inline ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx) +{ + if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { + mmu_idx += (ARMMMUIdx_S1NSE0 - ARMMMUIdx_S12NSE0); + } + return mmu_idx; +} + /* Returns TBI0 value for current regime el */ uint32_t arm_regime_tbi0(CPUARMState *env, ARMMMUIdx mmu_idx) { @@ -7056,11 +7135,9 @@ uint32_t arm_regime_tbi0(CPUARMState *env, ARMMMUIdx mmu_idx) uint32_t el; /* For EL0 and EL1, TBI is controlled by stage 1's TCR, so convert - * a stage 1+2 mmu index into the appropriate stage 1 mmu index. - */ - if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { - mmu_idx += ARMMMUIdx_S1NSE0; - } + * a stage 1+2 mmu index into the appropriate stage 1 mmu index. + */ + mmu_idx = stage_1_mmu_idx(mmu_idx); tcr = regime_tcr(env, mmu_idx); el = regime_el(env, mmu_idx); @@ -7079,11 +7156,9 @@ uint32_t arm_regime_tbi1(CPUARMState *env, ARMMMUIdx mmu_idx) uint32_t el; /* For EL0 and EL1, TBI is controlled by stage 1's TCR, so convert - * a stage 1+2 mmu index into the appropriate stage 1 mmu index. - */ - if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { - mmu_idx += ARMMMUIdx_S1NSE0; - } + * a stage 1+2 mmu index into the appropriate stage 1 mmu index. + */ + mmu_idx = stage_1_mmu_idx(mmu_idx); tcr = regime_tcr(env, mmu_idx); el = regime_el(env, mmu_idx); @@ -7129,9 +7204,7 @@ static inline bool regime_using_lpae_format(CPUARMState *env, * on whether the long or short descriptor format is in use. */ bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx) { - if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { - mmu_idx += ARMMMUIdx_S1NSE0; - } + mmu_idx = stage_1_mmu_idx(mmu_idx); return regime_using_lpae_format(env, mmu_idx); } @@ -7141,6 +7214,7 @@ static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) switch (mmu_idx) { case ARMMMUIdx_S1SE0: case ARMMMUIdx_S1NSE0: + case ARMMMUIdx_MUser: return true; default: return false; @@ -8114,18 +8188,60 @@ static inline void get_phys_addr_pmsav7_default(CPUARMState *env, ARMMMUIdx mmu_idx, int32_t address, int *prot) { - *prot = PAGE_READ | PAGE_WRITE; - switch (address) { - case 0xF0000000 ... 0xFFFFFFFF: - if (regime_sctlr(env, mmu_idx) & SCTLR_V) { /* hivecs execing is ok */ + if (!arm_feature(env, ARM_FEATURE_M)) { + *prot = PAGE_READ | PAGE_WRITE; + switch (address) { + case 0xF0000000 ... 0xFFFFFFFF: + if (regime_sctlr(env, mmu_idx) & SCTLR_V) { + /* hivecs execing is ok */ + *prot |= PAGE_EXEC; + } + break; + case 0x00000000 ... 0x7FFFFFFF: *prot |= PAGE_EXEC; + break; + } + } else { + /* Default system address map for M profile cores. + * The architecture specifies which regions are execute-never; + * at the MPU level no other checks are defined. + */ + switch (address) { + case 0x00000000 ... 0x1fffffff: /* ROM */ + case 0x20000000 ... 0x3fffffff: /* SRAM */ + case 0x60000000 ... 0x7fffffff: /* RAM */ + case 0x80000000 ... 0x9fffffff: /* RAM */ + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + break; + case 0x40000000 ... 0x5fffffff: /* Peripheral */ + case 0xa0000000 ... 0xbfffffff: /* Device */ + case 0xc0000000 ... 0xdfffffff: /* Device */ + case 0xe0000000 ... 0xffffffff: /* System */ + *prot = PAGE_READ | PAGE_WRITE; + break; + default: + g_assert_not_reached(); } - break; - case 0x00000000 ... 0x7FFFFFFF: - *prot |= PAGE_EXEC; - break; + } +} + +static bool pmsav7_use_background_region(ARMCPU *cpu, + ARMMMUIdx mmu_idx, bool is_user) +{ + /* Return true if we should use the default memory map as a + * "background" region if there are no hits against any MPU regions. + */ + CPUARMState *env = &cpu->env; + + if (is_user) { + return false; } + if (arm_feature(env, ARM_FEATURE_M)) { + return env->v7m.mpu_ctrl & R_V7M_MPU_CTRL_PRIVDEFENA_MASK; + } else { + return regime_sctlr(env, mmu_idx) & SCTLR_BR; + } } static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, @@ -8154,16 +8270,18 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, } if (!rsize) { - qemu_log_mask(LOG_GUEST_ERROR, "DRSR.Rsize field can not be 0"); + qemu_log_mask(LOG_GUEST_ERROR, + "DRSR[%d]: Rsize field cannot be 0\n", n); continue; } rsize++; rmask = (1ull << rsize) - 1; if (base & rmask) { - qemu_log_mask(LOG_GUEST_ERROR, "DRBAR %" PRIx32 " misaligned " - "to DRSR region size, mask = %" PRIx32, - base, rmask); + qemu_log_mask(LOG_GUEST_ERROR, + "DRBAR[%d]: 0x%" PRIx32 " misaligned " + "to DRSR region size, mask = 0x%" PRIx32 "\n", + n, base, rmask); continue; } @@ -8200,9 +8318,10 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, } } if (rsize < TARGET_PAGE_BITS) { - qemu_log_mask(LOG_UNIMP, "No support for MPU (sub)region" + qemu_log_mask(LOG_UNIMP, + "DRSR[%d]: No support for MPU (sub)region " "alignment of %" PRIu32 " bits. Minimum is %d\n", - rsize, TARGET_PAGE_BITS); + n, rsize, TARGET_PAGE_BITS); continue; } if (srdis) { @@ -8212,8 +8331,7 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, } if (n == -1) { /* no hits */ - if (cpu->pmsav7_dregion && - (is_user || !(regime_sctlr(env, mmu_idx) & SCTLR_BR))) { + if (!pmsav7_use_background_region(cpu, mmu_idx, is_user)) { /* background fault */ *fsr = 0; return true; @@ -8237,8 +8355,8 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, break; default: qemu_log_mask(LOG_GUEST_ERROR, - "Bad value for AP bits in DRACR %" - PRIx32 "\n", ap); + "DRACR[%d]: Bad value for AP bits: 0x%" + PRIx32 "\n", n, ap); } } else { /* Priv. mode AP bits decoding */ switch (ap) { @@ -8255,8 +8373,8 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, break; default: qemu_log_mask(LOG_GUEST_ERROR, - "Bad value for AP bits in DRACR %" - PRIx32 "\n", ap); + "DRACR[%d]: Bad value for AP bits: 0x%" + PRIx32 "\n", n, ap); } } @@ -8385,7 +8503,7 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, int ret; ret = get_phys_addr(env, address, access_type, - mmu_idx + ARMMMUIdx_S1NSE0, &ipa, attrs, + stage_1_mmu_idx(mmu_idx), &ipa, attrs, prot, page_size, fsr, fi); /* If S1 fails or S2 is disabled, return early. */ @@ -8406,7 +8524,7 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, /* * For non-EL2 CPUs a stage1+stage2 translation is just stage 1. */ - mmu_idx += ARMMMUIdx_S1NSE0; + mmu_idx = stage_1_mmu_idx(mmu_idx); } } @@ -8432,11 +8550,23 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, /* pmsav7 has special handling for when MPU is disabled so call it before * the common MMU/MPU disabled check below. */ - if (arm_feature(env, ARM_FEATURE_MPU) && + if (arm_feature(env, ARM_FEATURE_PMSA) && arm_feature(env, ARM_FEATURE_V7)) { + bool ret; *page_size = TARGET_PAGE_SIZE; - return get_phys_addr_pmsav7(env, address, access_type, mmu_idx, - phys_ptr, prot, fsr); + ret = get_phys_addr_pmsav7(env, address, access_type, mmu_idx, + phys_ptr, prot, fsr); + qemu_log_mask(CPU_LOG_MMU, "PMSAv7 MPU lookup for %s at 0x%08" PRIx32 + " mmu_idx %u -> %s (prot %c%c%c)\n", + access_type == 1 ? "reading" : + (access_type == 2 ? "writing" : "execute"), + (uint32_t)address, mmu_idx, + ret ? "Miss" : "Hit", + *prot & PAGE_READ ? 'r' : '-', + *prot & PAGE_WRITE ? 'w' : '-', + *prot & PAGE_EXEC ? 'x' : '-'); + + return ret; } if (regime_translation_disabled(env, mmu_idx)) { @@ -8447,7 +8577,7 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, return 0; } - if (arm_feature(env, ARM_FEATURE_MPU)) { + if (arm_feature(env, ARM_FEATURE_PMSA)) { /* Pre-v7 MPU */ *page_size = TARGET_PAGE_SIZE; return get_phys_addr_pmsav5(env, address, access_type, mmu_idx, @@ -8482,7 +8612,8 @@ bool arm_tlb_fill(CPUState *cs, vaddr address, int ret; MemTxAttrs attrs = {}; - ret = get_phys_addr(env, address, access_type, mmu_idx, &phys_addr, + ret = get_phys_addr(env, address, access_type, + core_to_arm_mmu_idx(env, mmu_idx), &phys_addr, &attrs, &prot, &page_size, fsr, fi); if (!ret) { /* Map a single [sub]page. */ @@ -8507,10 +8638,11 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, bool ret; uint32_t fsr; ARMMMUFaultInfo fi = {}; + ARMMMUIdx mmu_idx = core_to_arm_mmu_idx(env, cpu_mmu_index(env, false)); *attrs = (MemTxAttrs) {}; - ret = get_phys_addr(env, addr, 0, cpu_mmu_index(env, false), &phys_addr, + ret = get_phys_addr(env, addr, 0, mmu_idx, &phys_addr, attrs, &prot, &page_size, &fsr, &fi); if (ret) { |