diff options
Diffstat (limited to 'target/arm')
-rw-r--r-- | target/arm/cpu.c | 13 | ||||
-rw-r--r-- | target/arm/cpu.h | 73 | ||||
-rw-r--r-- | target/arm/helper-a64.c | 7 | ||||
-rw-r--r-- | target/arm/helper.c | 489 | ||||
-rw-r--r-- | target/arm/helper.h | 2 | ||||
-rw-r--r-- | target/arm/internals.h | 193 | ||||
-rw-r--r-- | target/arm/op_helper.c | 100 | ||||
-rw-r--r-- | target/arm/translate-a64.c | 37 | ||||
-rw-r--r-- | target/arm/translate.c | 86 | ||||
-rw-r--r-- | target/arm/translate.h | 10 |
10 files changed, 686 insertions, 324 deletions
diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 7f7a3d1e32..cc1856c32b 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -705,9 +705,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) CPUARMState *env = &cpu->env; int pagebits; Error *local_err = NULL; -#ifndef CONFIG_USER_ONLY - AddressSpace *as; -#endif cpu_exec_realizefn(cs, &local_err); if (local_err != NULL) { @@ -912,21 +909,17 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) #ifndef CONFIG_USER_ONLY if (cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY)) { - as = g_new0(AddressSpace, 1); - cs->num_ases = 2; if (!cpu->secure_memory) { cpu->secure_memory = cs->memory; } - address_space_init(as, cpu->secure_memory, "cpu-secure-memory"); - cpu_address_space_init(cs, as, ARMASIdx_S); + cpu_address_space_init(cs, ARMASIdx_S, "cpu-secure-memory", + cpu->secure_memory); } else { cs->num_ases = 1; } - as = g_new0(AddressSpace, 1); - address_space_init(as, cs->memory, "cpu-memory"); - cpu_address_space_init(cs, as, ARMASIdx_NS); + cpu_address_space_init(cs, ARMASIdx_NS, "cpu-memory", cs->memory); #endif qemu_init_vcpu(cs); diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 89d49cdcb2..96316700dd 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -112,7 +112,7 @@ enum { #define ARM_CPU_VIRQ 2 #define ARM_CPU_VFIQ 3 -#define NB_MMU_MODES 7 +#define NB_MMU_MODES 8 /* ARM-specific extra insn start words: * 1: Conditional execution bits * 2: Partial exception syndrome for data aborts @@ -2226,13 +2226,13 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, * They have the following different MMU indexes: * User * Privileged - * Execution priority negative (this is like privileged, but the - * MPU HFNMIENA bit means that it may have different access permission - * check results to normal privileged code, so can't share a TLB). + * User, execution priority negative (ie the MPU HFNMIENA bit may apply) + * Privileged, execution priority negative (ditto) * If the CPU supports the v8M Security Extension then there are also: * Secure User * Secure Privileged - * Secure, execution priority negative + * Secure User, execution priority negative + * Secure Privileged, execution priority negative * * The ARMMMUIdx and the mmu index value used by the core QEMU TLB code * are not quite the same -- different CPU types (most notably M profile @@ -2251,11 +2251,18 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, * The constant names here are patterned after the general style of the names * of the AT/ATS operations. * The values used are carefully arranged to make mmu_idx => EL lookup easy. + * For M profile we arrange them to have a bit for priv, a bit for negpri + * and a bit for secure. */ #define ARM_MMU_IDX_A 0x10 /* A profile */ #define ARM_MMU_IDX_NOTLB 0x20 /* does not have a TLB */ #define ARM_MMU_IDX_M 0x40 /* M profile */ +/* meanings of the bits for M profile mmu idx values */ +#define ARM_MMU_IDX_M_PRIV 0x1 +#define ARM_MMU_IDX_M_NEGPRI 0x2 +#define ARM_MMU_IDX_M_S 0x4 + #define ARM_MMU_IDX_TYPE_MASK (~0x7) #define ARM_MMU_IDX_COREIDX_MASK 0x7 @@ -2269,10 +2276,12 @@ typedef enum ARMMMUIdx { ARMMMUIdx_S2NS = 6 | ARM_MMU_IDX_A, ARMMMUIdx_MUser = 0 | ARM_MMU_IDX_M, ARMMMUIdx_MPriv = 1 | ARM_MMU_IDX_M, - ARMMMUIdx_MNegPri = 2 | ARM_MMU_IDX_M, - ARMMMUIdx_MSUser = 3 | ARM_MMU_IDX_M, - ARMMMUIdx_MSPriv = 4 | ARM_MMU_IDX_M, - ARMMMUIdx_MSNegPri = 5 | ARM_MMU_IDX_M, + ARMMMUIdx_MUserNegPri = 2 | ARM_MMU_IDX_M, + ARMMMUIdx_MPrivNegPri = 3 | ARM_MMU_IDX_M, + ARMMMUIdx_MSUser = 4 | ARM_MMU_IDX_M, + ARMMMUIdx_MSPriv = 5 | ARM_MMU_IDX_M, + ARMMMUIdx_MSUserNegPri = 6 | ARM_MMU_IDX_M, + ARMMMUIdx_MSPrivNegPri = 7 | ARM_MMU_IDX_M, /* Indexes below here don't have TLBs and are used only for AT system * instructions or for the first stage of an S12 page table walk. */ @@ -2293,10 +2302,12 @@ typedef enum ARMMMUIdxBit { ARMMMUIdxBit_S2NS = 1 << 6, ARMMMUIdxBit_MUser = 1 << 0, ARMMMUIdxBit_MPriv = 1 << 1, - ARMMMUIdxBit_MNegPri = 1 << 2, - ARMMMUIdxBit_MSUser = 1 << 3, - ARMMMUIdxBit_MSPriv = 1 << 4, - ARMMMUIdxBit_MSNegPri = 1 << 5, + ARMMMUIdxBit_MUserNegPri = 1 << 2, + ARMMMUIdxBit_MPrivNegPri = 1 << 3, + ARMMMUIdxBit_MSUser = 1 << 4, + ARMMMUIdxBit_MSPriv = 1 << 5, + ARMMMUIdxBit_MSUserNegPri = 1 << 6, + ARMMMUIdxBit_MSPrivNegPri = 1 << 7, } ARMMMUIdxBit; #define MMU_USER_IDX 0 @@ -2322,33 +2333,45 @@ static inline int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx) case ARM_MMU_IDX_A: return mmu_idx & 3; case ARM_MMU_IDX_M: - return (mmu_idx == ARMMMUIdx_MUser || mmu_idx == ARMMMUIdx_MSUser) - ? 0 : 1; + return mmu_idx & ARM_MMU_IDX_M_PRIV; default: g_assert_not_reached(); } } -/* Return the MMU index for a v7M CPU in the specified security state */ -static inline ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, - bool secstate) +/* Return the MMU index for a v7M CPU in the specified security and + * privilege state + */ +static inline ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env, + bool secstate, + bool priv) { - int el = arm_current_el(env); - ARMMMUIdx mmu_idx; + ARMMMUIdx mmu_idx = ARM_MMU_IDX_M; - if (el == 0) { - mmu_idx = secstate ? ARMMMUIdx_MSUser : ARMMMUIdx_MUser; - } else { - mmu_idx = secstate ? ARMMMUIdx_MSPriv : ARMMMUIdx_MPriv; + if (priv) { + mmu_idx |= ARM_MMU_IDX_M_PRIV; } if (armv7m_nvic_neg_prio_requested(env->nvic, secstate)) { - mmu_idx = secstate ? ARMMMUIdx_MSNegPri : ARMMMUIdx_MNegPri; + mmu_idx |= ARM_MMU_IDX_M_NEGPRI; + } + + if (secstate) { + mmu_idx |= ARM_MMU_IDX_M_S; } return mmu_idx; } +/* Return the MMU index for a v7M CPU in the specified security state */ +static inline ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, + bool secstate) +{ + bool priv = arm_current_el(env) != 0; + + return arm_v7m_mmu_idx_for_secstate_and_priv(env, secstate, priv); +} + /* Determine the current mmu_idx to use for normal loads/stores */ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch) { diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c index b84ebcae6e..3e00a9ead1 100644 --- a/target/arm/helper-a64.c +++ b/target/arm/helper-a64.c @@ -506,8 +506,11 @@ static uint64_t do_paired_cmpxchg64_be(CPUARMState *env, uint64_t addr, Int128 oldv, cmpv, newv; bool success; - cmpv = int128_make128(env->exclusive_val, env->exclusive_high); - newv = int128_make128(new_lo, new_hi); + /* high and low need to be switched here because this is not actually a + * 128bit store but two doublewords stored consecutively + */ + cmpv = int128_make128(env->exclusive_high, env->exclusive_val); + newv = int128_make128(new_hi, new_lo); if (parallel) { #ifndef CONFIG_ATOMIC128 diff --git a/target/arm/helper.c b/target/arm/helper.c index 91a9300f11..d1395f9b73 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -28,13 +28,13 @@ typedef struct ARMCacheAttrs { static bool get_phys_addr(CPUARMState *env, target_ulong address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, uint32_t *fsr, + target_ulong *page_size, ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs); static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, - target_ulong *page_size_ptr, uint32_t *fsr, + target_ulong *page_size_ptr, ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs); /* Security attributes for an address, as returned by v8m_security_lookup. */ @@ -2160,20 +2160,44 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, hwaddr phys_addr; target_ulong page_size; int prot; - uint32_t fsr; bool ret; uint64_t par64; + bool format64 = false; MemTxAttrs attrs = {}; ARMMMUFaultInfo fi = {}; ARMCacheAttrs cacheattrs = {}; ret = get_phys_addr(env, value, access_type, mmu_idx, &phys_addr, &attrs, - &prot, &page_size, &fsr, &fi, &cacheattrs); - if (arm_s1_regime_using_lpae_format(env, mmu_idx)) { - /* fsr is a DFSR/IFSR value for the long descriptor - * translation table format, but with WnR always clear. - * Convert it to a 64-bit PAR. + &prot, &page_size, &fi, &cacheattrs); + + if (is_a64(env)) { + format64 = true; + } else if (arm_feature(env, ARM_FEATURE_LPAE)) { + /* + * ATS1Cxx: + * * TTBCR.EAE determines whether the result is returned using the + * 32-bit or the 64-bit PAR format + * * Instructions executed in Hyp mode always use the 64bit format + * + * ATS1S2NSOxx uses the 64bit format if any of the following is true: + * * The Non-secure TTBCR.EAE bit is set to 1 + * * The implementation includes EL2, and the value of HCR.VM is 1 + * + * ATS1Hx always uses the 64bit format (not supported yet). */ + format64 = arm_s1_regime_using_lpae_format(env, mmu_idx); + + if (arm_feature(env, ARM_FEATURE_EL2)) { + if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { + format64 |= env->cp15.hcr_el2 & HCR_VM; + } else { + format64 |= arm_current_el(env) == 2; + } + } + } + + if (format64) { + /* Create a 64-bit PAR */ par64 = (1 << 11); /* LPAE bit always set */ if (!ret) { par64 |= phys_addr & ~0xfffULL; @@ -2183,6 +2207,8 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, par64 |= (uint64_t)cacheattrs.attrs << 56; /* ATTR */ par64 |= cacheattrs.shareability << 7; /* SH */ } else { + uint32_t fsr = arm_fi_to_lfsc(&fi); + par64 |= 1; /* F */ par64 |= (fsr & 0x3f) << 1; /* FS */ /* Note that S2WLK and FSTAGE are always zero, because we don't @@ -2207,6 +2233,8 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, par64 |= (1 << 9); /* NS */ } } else { + uint32_t fsr = arm_fi_to_sfsc(&fi); + par64 = ((fsr & (1 << 10)) >> 5) | ((fsr & (1 << 12)) >> 6) | ((fsr & 0xf) << 1) | 1; } @@ -5947,6 +5975,28 @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest) g_assert_not_reached(); } +uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op) +{ + /* The TT instructions can be used by unprivileged code, but in + * user-only emulation we don't have the MPU. + * Luckily since we know we are NonSecure unprivileged (and that in + * turn means that the A flag wasn't specified), all the bits in the + * register must be zero: + * IREGION: 0 because IRVALID is 0 + * IRVALID: 0 because NS + * S: 0 because NS + * NSRW: 0 because NS + * NSR: 0 because NS + * RW: 0 because unpriv and A flag not set + * R: 0 because unpriv and A flag not set + * SRVALID: 0 because NS + * MRVALID: 0 because unpriv and A flag not set + * SREGION: 0 becaus SRVALID is 0 + * MREGION: 0 because MRVALID is 0 + */ + return 0; +} + void switch_mode(CPUARMState *env, int mode) { ARMCPU *cpu = arm_env_get_cpu(env); @@ -6955,7 +7005,6 @@ static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx, target_ulong page_size; hwaddr physaddr; int prot; - uint32_t fsr; v8m_security_lookup(env, addr, MMU_INST_FETCH, mmu_idx, &sattrs); if (!sattrs.nsc || sattrs.ns) { @@ -6969,7 +7018,7 @@ static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx, return false; } if (get_phys_addr(env, addr, MMU_INST_FETCH, mmu_idx, - &physaddr, &attrs, &prot, &page_size, &fsr, &fi, NULL)) { + &physaddr, &attrs, &prot, &page_size, &fi, NULL)) { /* the MPU lookup failed */ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_IACCVIOL_MASK; armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, env->v7m.secure); @@ -7856,11 +7905,13 @@ static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx) case ARMMMUIdx_S1SE1: case ARMMMUIdx_S1NSE0: case ARMMMUIdx_S1NSE1: + case ARMMMUIdx_MPrivNegPri: + case ARMMMUIdx_MUserNegPri: case ARMMMUIdx_MPriv: - case ARMMMUIdx_MNegPri: case ARMMMUIdx_MUser: + case ARMMMUIdx_MSPrivNegPri: + case ARMMMUIdx_MSUserNegPri: case ARMMMUIdx_MSPriv: - case ARMMMUIdx_MSNegPri: case ARMMMUIdx_MSUser: return 1; default: @@ -7883,8 +7934,7 @@ static inline bool regime_translation_disabled(CPUARMState *env, (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 || - mmu_idx == ARMMMUIdx_MSNegPri; + return mmu_idx & ARM_MMU_IDX_M_NEGPRI; case R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK: /* Enabled for all cases */ return false; @@ -8016,6 +8066,9 @@ static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) case ARMMMUIdx_S1SE0: case ARMMMUIdx_S1NSE0: case ARMMMUIdx_MUser: + case ARMMMUIdx_MSUser: + case ARMMMUIdx_MUserNegPri: + case ARMMMUIdx_MSUserNegPri: return true; default: return false; @@ -8240,7 +8293,6 @@ static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, /* Translate a S1 pagetable walk through S2 if needed. */ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, hwaddr addr, MemTxAttrs txattrs, - uint32_t *fsr, ARMMMUFaultInfo *fi) { if ((mmu_idx == ARMMMUIdx_S1NSE0 || mmu_idx == ARMMMUIdx_S1NSE1) && @@ -8251,7 +8303,7 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, int ret; ret = get_phys_addr_lpae(env, addr, 0, ARMMMUIdx_S2NS, &s2pa, - &txattrs, &s2prot, &s2size, fsr, fi, NULL); + &txattrs, &s2prot, &s2size, fi, NULL); if (ret) { fi->s2addr = addr; fi->stage2 = true; @@ -8271,8 +8323,7 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, * (but not if it was for a debug access). */ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, - ARMMMUIdx mmu_idx, uint32_t *fsr, - ARMMMUFaultInfo *fi) + ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; @@ -8281,7 +8332,7 @@ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, attrs.secure = is_secure; as = arm_addressspace(cs, attrs); - addr = S1_ptw_translate(env, mmu_idx, addr, attrs, fsr, fi); + addr = S1_ptw_translate(env, mmu_idx, addr, attrs, fi); if (fi->s1ptw) { return 0; } @@ -8293,8 +8344,7 @@ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, } static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, - ARMMMUIdx mmu_idx, uint32_t *fsr, - ARMMMUFaultInfo *fi) + ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; @@ -8303,7 +8353,7 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, attrs.secure = is_secure; as = arm_addressspace(cs, attrs); - addr = S1_ptw_translate(env, mmu_idx, addr, attrs, fsr, fi); + addr = S1_ptw_translate(env, mmu_idx, addr, attrs, fi); if (fi->s1ptw) { return 0; } @@ -8317,11 +8367,11 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, int *prot, - target_ulong *page_size, uint32_t *fsr, + target_ulong *page_size, ARMMMUFaultInfo *fi) { CPUState *cs = CPU(arm_env_get_cpu(env)); - int code; + int level = 1; uint32_t table; uint32_t desc; int type; @@ -8335,11 +8385,11 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, /* Lookup l1 descriptor. */ if (!get_level1_table_address(env, mmu_idx, &table, address)) { /* Section translation fault if page walk is disabled by PD0 or PD1 */ - code = 5; + fi->type = ARMFault_Translation; goto do_fault; } desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), - mmu_idx, fsr, fi); + mmu_idx, fi); type = (desc & 3); domain = (desc >> 5) & 0x0f; if (regime_el(env, mmu_idx) == 1) { @@ -8350,21 +8400,20 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, domain_prot = (dacr >> (domain * 2)) & 3; if (type == 0) { /* Section translation fault. */ - code = 5; + fi->type = ARMFault_Translation; goto do_fault; } + if (type != 2) { + level = 2; + } if (domain_prot == 0 || domain_prot == 2) { - if (type == 2) - code = 9; /* Section domain fault. */ - else - code = 11; /* Page domain fault. */ + fi->type = ARMFault_Domain; goto do_fault; } if (type == 2) { /* 1Mb section. */ phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); ap = (desc >> 10) & 3; - code = 13; *page_size = 1024 * 1024; } else { /* Lookup l2 entry. */ @@ -8376,10 +8425,10 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, table = (desc & 0xfffff000) | ((address >> 8) & 0xffc); } desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), - mmu_idx, fsr, fi); + mmu_idx, fi); switch (desc & 3) { case 0: /* Page translation fault. */ - code = 7; + fi->type = ARMFault_Translation; goto do_fault; case 1: /* 64k page. */ phys_addr = (desc & 0xffff0000) | (address & 0xffff); @@ -8402,7 +8451,7 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, /* UNPREDICTABLE in ARMv5; we choose to take a * page translation fault. */ - code = 7; + fi->type = ARMFault_Translation; goto do_fault; } } else { @@ -8415,29 +8464,29 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, /* Never happens, but compiler isn't smart enough to tell. */ abort(); } - code = 15; } *prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot); *prot |= *prot ? PAGE_EXEC : 0; if (!(*prot & (1 << access_type))) { /* Access permission fault. */ + fi->type = ARMFault_Permission; goto do_fault; } *phys_ptr = phys_addr; return false; do_fault: - *fsr = code | (domain << 4); + fi->domain = domain; + fi->level = level; return true; } static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, uint32_t *fsr, - ARMMMUFaultInfo *fi) + target_ulong *page_size, ARMMMUFaultInfo *fi) { CPUState *cs = CPU(arm_env_get_cpu(env)); - int code; + int level = 1; uint32_t table; uint32_t desc; uint32_t xn; @@ -8454,17 +8503,17 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, /* Lookup l1 descriptor. */ if (!get_level1_table_address(env, mmu_idx, &table, address)) { /* Section translation fault if page walk is disabled by PD0 or PD1 */ - code = 5; + fi->type = ARMFault_Translation; goto do_fault; } desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), - mmu_idx, fsr, fi); + mmu_idx, fi); type = (desc & 3); if (type == 0 || (type == 3 && !arm_feature(env, ARM_FEATURE_PXN))) { /* Section translation fault, or attempt to use the encoding * which is Reserved on implementations without PXN. */ - code = 5; + fi->type = ARMFault_Translation; goto do_fault; } if ((type == 1) || !(desc & (1 << 18))) { @@ -8476,13 +8525,13 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, } else { dacr = env->cp15.dacr_s; } + if (type == 1) { + level = 2; + } domain_prot = (dacr >> (domain * 2)) & 3; if (domain_prot == 0 || domain_prot == 2) { - if (type != 1) { - code = 9; /* Section domain fault. */ - } else { - code = 11; /* Page domain fault. */ - } + /* Section or Page domain fault */ + fi->type = ARMFault_Domain; goto do_fault; } if (type != 1) { @@ -8500,7 +8549,6 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, ap = ((desc >> 10) & 3) | ((desc >> 13) & 4); xn = desc & (1 << 4); pxn = desc & 1; - code = 13; ns = extract32(desc, 19, 1); } else { if (arm_feature(env, ARM_FEATURE_PXN)) { @@ -8510,11 +8558,11 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, /* Lookup l2 entry. */ table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), - mmu_idx, fsr, fi); + mmu_idx, fi); ap = ((desc >> 4) & 3) | ((desc >> 7) & 4); switch (desc & 3) { case 0: /* Page translation fault. */ - code = 7; + fi->type = ARMFault_Translation; goto do_fault; case 1: /* 64k page. */ phys_addr = (desc & 0xffff0000) | (address & 0xffff); @@ -8530,7 +8578,6 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, /* Never happens, but compiler isn't smart enough to tell. */ abort(); } - code = 15; } if (domain_prot == 3) { *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; @@ -8538,15 +8585,17 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, if (pxn && !regime_is_user(env, mmu_idx)) { xn = 1; } - if (xn && access_type == MMU_INST_FETCH) + if (xn && access_type == MMU_INST_FETCH) { + fi->type = ARMFault_Permission; goto do_fault; + } if (arm_feature(env, ARM_FEATURE_V6K) && (regime_sctlr(env, mmu_idx) & SCTLR_AFE)) { /* The simplified model uses AP[0] as an access control bit. */ if ((ap & 1) == 0) { /* Access flag fault. */ - code = (code == 15) ? 6 : 3; + fi->type = ARMFault_AccessFlag; goto do_fault; } *prot = simple_ap_to_rw_prot(env, mmu_idx, ap >> 1); @@ -8558,6 +8607,7 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, } if (!(*prot & (1 << access_type))) { /* Access permission fault. */ + fi->type = ARMFault_Permission; goto do_fault; } } @@ -8571,19 +8621,11 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, *phys_ptr = phys_addr; return false; do_fault: - *fsr = code | (domain << 4); + fi->domain = domain; + fi->level = level; return true; } -/* Fault type for long-descriptor MMU fault reporting; this corresponds - * to bits [5..2] in the STATUS field in long-format DFSR/IFSR. - */ -typedef enum { - translation_fault = 1, - access_fault = 2, - permission_fault = 3, -} MMUFaultType; - /* * check_s2_mmu_setup * @cpu: ARMCPU @@ -8685,13 +8727,13 @@ static uint8_t convert_stage2_attrs(CPUARMState *env, uint8_t s2attrs) static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, - target_ulong *page_size_ptr, uint32_t *fsr, + target_ulong *page_size_ptr, ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) { ARMCPU *cpu = arm_env_get_cpu(env); CPUState *cs = CPU(cpu); /* Read an LPAE long-descriptor translation table. */ - MMUFaultType fault_type = translation_fault; + ARMFaultType fault_type = ARMFault_Translation; uint32_t level; uint32_t epd = 0; int32_t t0sz, t1sz; @@ -8801,7 +8843,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, ttbr_select = 1; } else { /* in the gap between the two regions, this is a Translation fault */ - fault_type = translation_fault; + fault_type = ARMFault_Translation; goto do_fault; } @@ -8887,7 +8929,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, ok = check_s2_mmu_setup(cpu, aarch64, startlevel, inputsize, stride); if (!ok) { - fault_type = translation_fault; + fault_type = ARMFault_Translation; goto do_fault; } level = startlevel; @@ -8921,7 +8963,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, descaddr |= (address >> (stride * (4 - level))) & indexmask; descaddr &= ~7ULL; nstable = extract32(tableattrs, 4, 1); - descriptor = arm_ldq_ptw(cs, descaddr, !nstable, mmu_idx, fsr, fi); + descriptor = arm_ldq_ptw(cs, descaddr, !nstable, mmu_idx, fi); if (fi->s1ptw) { goto do_fault; } @@ -8973,7 +9015,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, /* Here descaddr is the final physical address, and attributes * are all in attrs. */ - fault_type = access_fault; + fault_type = ARMFault_AccessFlag; if ((attrs & (1 << 8)) == 0) { /* Access flag */ goto do_fault; @@ -8991,7 +9033,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, *prot = get_S1prot(env, mmu_idx, aarch64, ap, ns, xn, pxn); } - fault_type = permission_fault; + fault_type = ARMFault_Permission; if (!(*prot & (1 << access_type))) { goto do_fault; } @@ -9023,8 +9065,8 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, return false; do_fault: - /* Long-descriptor format IFSR/DFSR value */ - *fsr = (1 << 9) | (fault_type << 2) | level; + fi->type = fault_type; + fi->level = level; /* Tag the error as S2 for failed S1 PTW at S2 or ordinary S2. */ fi->stage2 = fi->s1ptw || (mmu_idx == ARMMMUIdx_S2NS); return true; @@ -9108,7 +9150,8 @@ static inline bool m_is_system_region(CPUARMState *env, uint32_t address) static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, uint32_t *fsr) + hwaddr *phys_ptr, int *prot, + ARMMMUFaultInfo *fi) { ARMCPU *cpu = arm_env_get_cpu(env); int n; @@ -9203,7 +9246,7 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, if (n == -1) { /* no hits */ if (!pmsav7_use_background_region(cpu, mmu_idx, is_user)) { /* background fault */ - *fsr = 0; + fi->type = ARMFault_Background; return true; } get_phys_addr_pmsav7_default(env, mmu_idx, address, prot); @@ -9261,7 +9304,8 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, } } - *fsr = 0x00d; /* Permission fault */ + fi->type = ARMFault_Permission; + fi->level = 1; return !(*prot & (1 << access_type)); } @@ -9344,67 +9388,28 @@ static void v8m_security_lookup(CPUARMState *env, uint32_t address, } } -static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *txattrs, - int *prot, uint32_t *fsr) +static bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *txattrs, + int *prot, ARMMMUFaultInfo *fi, uint32_t *mregion) { + /* Perform a PMSAv8 MPU lookup (without also doing the SAU check + * that a full phys-to-virt translation does). + * mregion is (if not NULL) set to the region number which matched, + * or -1 if no region number is returned (MPU off, address did not + * hit a region, address hit in multiple regions). + */ ARMCPU *cpu = arm_env_get_cpu(env); bool is_user = regime_is_user(env, mmu_idx); uint32_t secure = regime_is_secure(env, mmu_idx); int n; int matchregion = -1; bool hit = false; - V8M_SAttributes sattrs = {}; *phys_ptr = address; *prot = 0; - - if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { - v8m_security_lookup(env, address, access_type, mmu_idx, &sattrs); - if (access_type == MMU_INST_FETCH) { - /* Instruction fetches always use the MMU bank and the - * transaction attribute determined by the fetch address, - * regardless of CPU state. This is painful for QEMU - * to handle, because it would mean we need to encode - * into the mmu_idx not just the (user, negpri) information - * for the current security state but also that for the - * other security state, which would balloon the number - * of mmu_idx values needed alarmingly. - * Fortunately we can avoid this because it's not actually - * possible to arbitrarily execute code from memory with - * the wrong security attribute: it will always generate - * an exception of some kind or another, apart from the - * special case of an NS CPU executing an SG instruction - * in S&NSC memory. So we always just fail the translation - * here and sort things out in the exception handler - * (including possibly emulating an SG instruction). - */ - if (sattrs.ns != !secure) { - *fsr = sattrs.nsc ? M_FAKE_FSR_NSC_EXEC : M_FAKE_FSR_SFAULT; - return true; - } - } else { - /* For data accesses we always use the MMU bank indicated - * by the current CPU state, but the security attributes - * might downgrade a secure access to nonsecure. - */ - if (sattrs.ns) { - txattrs->secure = false; - } else if (!secure) { - /* NS access to S memory must fault. - * Architecturally we should first check whether the - * MPU information for this address indicates that we - * are doing an unaligned access to Device memory, which - * should generate a UsageFault instead. QEMU does not - * currently check for that kind of unaligned access though. - * If we added it we would need to do so as a special case - * for M_FAKE_FSR_SFAULT in arm_v7m_cpu_do_interrupt(). - */ - *fsr = M_FAKE_FSR_SFAULT; - return true; - } - } + if (mregion) { + *mregion = -1; } /* Unlike the ARM ARM pseudocode, we don't need to check whether this @@ -9442,7 +9447,8 @@ static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, /* Multiple regions match -- always a failure (unlike * PMSAv7 where highest-numbered-region wins) */ - *fsr = 0x00d; /* permission fault */ + fi->type = ARMFault_Permission; + fi->level = 1; return true; } @@ -9470,7 +9476,7 @@ static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, if (!hit) { /* background fault */ - *fsr = 0; + fi->type = ARMFault_Background; return true; } @@ -9493,15 +9499,88 @@ static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, /* We don't need to look the attribute up in the MAIR0/MAIR1 * registers because that only tells us about cacheability. */ + if (mregion) { + *mregion = matchregion; + } } - *fsr = 0x00d; /* Permission fault */ + fi->type = ARMFault_Permission; + fi->level = 1; return !(*prot & (1 << access_type)); } + +static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *txattrs, + int *prot, ARMMMUFaultInfo *fi) +{ + uint32_t secure = regime_is_secure(env, mmu_idx); + V8M_SAttributes sattrs = {}; + + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + v8m_security_lookup(env, address, access_type, mmu_idx, &sattrs); + if (access_type == MMU_INST_FETCH) { + /* Instruction fetches always use the MMU bank and the + * transaction attribute determined by the fetch address, + * regardless of CPU state. This is painful for QEMU + * to handle, because it would mean we need to encode + * into the mmu_idx not just the (user, negpri) information + * for the current security state but also that for the + * other security state, which would balloon the number + * of mmu_idx values needed alarmingly. + * Fortunately we can avoid this because it's not actually + * possible to arbitrarily execute code from memory with + * the wrong security attribute: it will always generate + * an exception of some kind or another, apart from the + * special case of an NS CPU executing an SG instruction + * in S&NSC memory. So we always just fail the translation + * here and sort things out in the exception handler + * (including possibly emulating an SG instruction). + */ + if (sattrs.ns != !secure) { + if (sattrs.nsc) { + fi->type = ARMFault_QEMU_NSCExec; + } else { + fi->type = ARMFault_QEMU_SFault; + } + *phys_ptr = address; + *prot = 0; + return true; + } + } else { + /* For data accesses we always use the MMU bank indicated + * by the current CPU state, but the security attributes + * might downgrade a secure access to nonsecure. + */ + if (sattrs.ns) { + txattrs->secure = false; + } else if (!secure) { + /* NS access to S memory must fault. + * Architecturally we should first check whether the + * MPU information for this address indicates that we + * are doing an unaligned access to Device memory, which + * should generate a UsageFault instead. QEMU does not + * currently check for that kind of unaligned access though. + * If we added it we would need to do so as a special case + * for M_FAKE_FSR_SFAULT in arm_v7m_cpu_do_interrupt(). + */ + fi->type = ARMFault_QEMU_SFault; + *phys_ptr = address; + *prot = 0; + return true; + } + } + } + + return pmsav8_mpu_lookup(env, address, access_type, mmu_idx, phys_ptr, + txattrs, prot, fi, NULL); +} + static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, uint32_t *fsr) + hwaddr *phys_ptr, int *prot, + ARMMMUFaultInfo *fi) { int n; uint32_t mask; @@ -9530,7 +9609,7 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, } } if (n < 0) { - *fsr = 2; + fi->type = ARMFault_Background; return true; } @@ -9542,11 +9621,13 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, mask = (mask >> (n * 4)) & 0xf; switch (mask) { case 0: - *fsr = 1; + fi->type = ARMFault_Permission; + fi->level = 1; return true; case 1: if (is_user) { - *fsr = 1; + fi->type = ARMFault_Permission; + fi->level = 1; return true; } *prot = PAGE_READ | PAGE_WRITE; @@ -9562,7 +9643,8 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, break; case 5: if (is_user) { - *fsr = 1; + fi->type = ARMFault_Permission; + fi->level = 1; return true; } *prot = PAGE_READ; @@ -9572,7 +9654,8 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, break; default: /* Bad permission. */ - *fsr = 1; + fi->type = ARMFault_Permission; + fi->level = 1; return true; } *prot |= PAGE_EXEC; @@ -9689,14 +9772,13 @@ static ARMCacheAttrs combine_cacheattrs(ARMCacheAttrs s1, ARMCacheAttrs s2) * @attrs: set to the memory transaction attributes to use * @prot: set to the permissions for the page containing phys_ptr * @page_size: set to the size of the page containing phys_ptr - * @fsr: set to the DFSR/IFSR value on failure * @fi: set to fault info if the translation fails * @cacheattrs: (if non-NULL) set to the cacheability/shareability attributes */ static bool get_phys_addr(CPUARMState *env, target_ulong address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, uint32_t *fsr, + target_ulong *page_size, ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) { if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { @@ -9711,7 +9793,7 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, ret = get_phys_addr(env, address, access_type, stage_1_mmu_idx(mmu_idx), &ipa, attrs, - prot, page_size, fsr, fi, cacheattrs); + prot, page_size, fi, cacheattrs); /* If S1 fails or S2 is disabled, return early. */ if (ret || regime_translation_disabled(env, ARMMMUIdx_S2NS)) { @@ -9722,7 +9804,7 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, /* S1 is done. Now do S2 translation. */ ret = get_phys_addr_lpae(env, ipa, access_type, ARMMMUIdx_S2NS, phys_ptr, attrs, &s2_prot, - page_size, fsr, fi, + page_size, fi, cacheattrs != NULL ? &cacheattrs2 : NULL); fi->s2addr = ipa; /* Combine the S1 and S2 perms. */ @@ -9768,15 +9850,15 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, if (arm_feature(env, ARM_FEATURE_V8)) { /* PMSAv8 */ ret = get_phys_addr_pmsav8(env, address, access_type, mmu_idx, - phys_ptr, attrs, prot, fsr); + phys_ptr, attrs, prot, fi); } else if (arm_feature(env, ARM_FEATURE_V7)) { /* PMSAv7 */ ret = get_phys_addr_pmsav7(env, address, access_type, mmu_idx, - phys_ptr, prot, fsr); + phys_ptr, prot, fi); } else { /* Pre-v7 MPU */ ret = get_phys_addr_pmsav5(env, address, access_type, mmu_idx, - phys_ptr, prot, fsr); + phys_ptr, prot, fi); } qemu_log_mask(CPU_LOG_MMU, "PMSA MPU lookup for %s at 0x%08" PRIx32 " mmu_idx %u -> %s (prot %c%c%c)\n", @@ -9802,14 +9884,15 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, } if (regime_using_lpae_format(env, mmu_idx)) { - return get_phys_addr_lpae(env, address, access_type, mmu_idx, phys_ptr, - attrs, prot, page_size, fsr, fi, cacheattrs); + return get_phys_addr_lpae(env, address, access_type, mmu_idx, + phys_ptr, attrs, prot, page_size, + fi, cacheattrs); } else if (regime_sctlr(env, mmu_idx) & SCTLR_XP) { - return get_phys_addr_v6(env, address, access_type, mmu_idx, phys_ptr, - attrs, prot, page_size, fsr, fi); + return get_phys_addr_v6(env, address, access_type, mmu_idx, + phys_ptr, attrs, prot, page_size, fi); } else { - return get_phys_addr_v5(env, address, access_type, mmu_idx, phys_ptr, - prot, page_size, fsr, fi); + return get_phys_addr_v5(env, address, access_type, mmu_idx, + phys_ptr, prot, page_size, fi); } } @@ -9818,7 +9901,7 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, * fsr with ARM DFSR/IFSR fault register format value on failure. */ bool arm_tlb_fill(CPUState *cs, vaddr address, - MMUAccessType access_type, int mmu_idx, uint32_t *fsr, + MMUAccessType access_type, int mmu_idx, ARMMMUFaultInfo *fi) { ARMCPU *cpu = ARM_CPU(cs); @@ -9831,7 +9914,7 @@ bool arm_tlb_fill(CPUState *cs, vaddr address, ret = get_phys_addr(env, address, access_type, core_to_arm_mmu_idx(env, mmu_idx), &phys_addr, - &attrs, &prot, &page_size, fsr, fi, NULL); + &attrs, &prot, &page_size, fi, NULL); if (!ret) { /* Map a single [sub]page. */ phys_addr &= TARGET_PAGE_MASK; @@ -9853,14 +9936,13 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, target_ulong page_size; int prot; 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, mmu_idx, &phys_addr, - attrs, &prot, &page_size, &fsr, &fi, NULL); + attrs, &prot, &page_size, &fi, NULL); if (ret) { return -1; @@ -9953,11 +10035,9 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) switch (reg) { case 8: /* MSP */ - return (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) ? - env->v7m.other_sp : env->regs[13]; + return v7m_using_psp(env) ? env->v7m.other_sp : env->regs[13]; case 9: /* PSP */ - return (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) ? - env->regs[13] : env->v7m.other_sp; + return v7m_using_psp(env) ? env->regs[13] : env->v7m.other_sp; case 16: /* PRIMASK */ return env->v7m.primask[env->v7m.secure]; case 17: /* BASEPRI */ @@ -10059,14 +10139,14 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) } break; case 8: /* MSP */ - if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) { + if (v7m_using_psp(env)) { env->v7m.other_sp = val; } else { env->regs[13] = val; } break; case 9: /* PSP */ - if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) { + if (v7m_using_psp(env)) { env->regs[13] = val; } else { env->v7m.other_sp = val; @@ -10093,8 +10173,11 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) * thread mode; other bits can be updated by any privileged code. * write_v7m_control_spsel() deals with updating the SPSEL bit in * env->v7m.control, so we only need update the others. + * For v7M, we must just ignore explicit writes to SPSEL in handler + * mode; for v8M the write is permitted but will have no effect. */ - if (!arm_v7m_is_handler_mode(env)) { + if (arm_feature(env, ARM_FEATURE_V8) || + !arm_v7m_is_handler_mode(env)) { write_v7m_control_spsel(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0); } env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK; @@ -10107,6 +10190,92 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) } } +uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op) +{ + /* Implement the TT instruction. op is bits [7:6] of the insn. */ + bool forceunpriv = op & 1; + bool alt = op & 2; + V8M_SAttributes sattrs = {}; + uint32_t tt_resp; + bool r, rw, nsr, nsrw, mrvalid; + int prot; + ARMMMUFaultInfo fi = {}; + MemTxAttrs attrs = {}; + hwaddr phys_addr; + ARMMMUIdx mmu_idx; + uint32_t mregion; + bool targetpriv; + bool targetsec = env->v7m.secure; + + /* Work out what the security state and privilege level we're + * interested in is... + */ + if (alt) { + targetsec = !targetsec; + } + + if (forceunpriv) { + targetpriv = false; + } else { + targetpriv = arm_v7m_is_handler_mode(env) || + !(env->v7m.control[targetsec] & R_V7M_CONTROL_NPRIV_MASK); + } + + /* ...and then figure out which MMU index this is */ + mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, targetsec, targetpriv); + + /* We know that the MPU and SAU don't care about the access type + * for our purposes beyond that we don't want to claim to be + * an insn fetch, so we arbitrarily call this a read. + */ + + /* MPU region info only available for privileged or if + * inspecting the other MPU state. + */ + if (arm_current_el(env) != 0 || alt) { + /* We can ignore the return value as prot is always set */ + pmsav8_mpu_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, + &phys_addr, &attrs, &prot, &fi, &mregion); + if (mregion == -1) { + mrvalid = false; + mregion = 0; + } else { + mrvalid = true; + } + r = prot & PAGE_READ; + rw = prot & PAGE_WRITE; + } else { + r = false; + rw = false; + mrvalid = false; + mregion = 0; + } + + if (env->v7m.secure) { + v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs); + nsr = sattrs.ns && r; + nsrw = sattrs.ns && rw; + } else { + sattrs.ns = true; + nsr = false; + nsrw = false; + } + + tt_resp = (sattrs.iregion << 24) | + (sattrs.irvalid << 23) | + ((!sattrs.ns) << 22) | + (nsrw << 21) | + (nsr << 20) | + (rw << 19) | + (r << 18) | + (sattrs.srvalid << 17) | + (mrvalid << 16) | + (sattrs.sregion << 8) | + mregion; + + return tt_resp; +} + #endif void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in) diff --git a/target/arm/helper.h b/target/arm/helper.h index 439d228420..066729e8ad 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -66,6 +66,8 @@ DEF_HELPER_2(v7m_mrs, i32, env, i32) DEF_HELPER_2(v7m_bxns, void, env, i32) DEF_HELPER_2(v7m_blxns, void, env, i32) +DEF_HELPER_3(v7m_tt, i32, env, i32, i32) + DEF_HELPER_4(access_check_cp_reg, void, env, ptr, i32, i32) DEF_HELPER_3(set_cp_reg, void, env, ptr, i32) DEF_HELPER_2(get_cp_reg, i32, env, ptr) diff --git a/target/arm/internals.h b/target/arm/internals.h index d9cc75e4c5..876854d876 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -488,7 +488,39 @@ static inline void arm_clear_exclusive(CPUARMState *env) } /** + * ARMFaultType: type of an ARM MMU fault + * This corresponds to the v8A pseudocode's Fault enumeration, + * with extensions for QEMU internal conditions. + */ +typedef enum ARMFaultType { + ARMFault_None, + ARMFault_AccessFlag, + ARMFault_Alignment, + ARMFault_Background, + ARMFault_Domain, + ARMFault_Permission, + ARMFault_Translation, + ARMFault_AddressSize, + ARMFault_SyncExternal, + ARMFault_SyncExternalOnWalk, + ARMFault_SyncParity, + ARMFault_SyncParityOnWalk, + ARMFault_AsyncParity, + ARMFault_AsyncExternal, + ARMFault_Debug, + ARMFault_TLBConflict, + ARMFault_Lockdown, + ARMFault_Exclusive, + ARMFault_ICacheMaint, + ARMFault_QEMU_NSCExec, /* v8M: NS executing in S&NSC memory */ + ARMFault_QEMU_SFault, /* v8M: SecureFault INVTRAN, INVEP or AUVIOL */ +} ARMFaultType; + +/** * ARMMMUFaultInfo: Information describing an ARM MMU Fault + * @type: Type of fault + * @level: Table walk level (for translation, access flag and permission faults) + * @domain: Domain of the fault address (for non-LPAE CPUs only) * @s2addr: Address that caused a fault at stage 2 * @stage2: True if we faulted at stage 2 * @s1ptw: True if we faulted at stage 2 while doing a stage 1 page-table walk @@ -496,16 +528,169 @@ static inline void arm_clear_exclusive(CPUARMState *env) */ typedef struct ARMMMUFaultInfo ARMMMUFaultInfo; struct ARMMMUFaultInfo { + ARMFaultType type; target_ulong s2addr; + int level; + int domain; bool stage2; bool s1ptw; bool ea; }; +/** + * arm_fi_to_sfsc: Convert fault info struct to short-format FSC + * Compare pseudocode EncodeSDFSC(), though unlike that function + * we set up a whole FSR-format code including domain field and + * putting the high bit of the FSC into bit 10. + */ +static inline uint32_t arm_fi_to_sfsc(ARMMMUFaultInfo *fi) +{ + uint32_t fsc; + + switch (fi->type) { + case ARMFault_None: + return 0; + case ARMFault_AccessFlag: + fsc = fi->level == 1 ? 0x3 : 0x6; + break; + case ARMFault_Alignment: + fsc = 0x1; + break; + case ARMFault_Permission: + fsc = fi->level == 1 ? 0xd : 0xf; + break; + case ARMFault_Domain: + fsc = fi->level == 1 ? 0x9 : 0xb; + break; + case ARMFault_Translation: + fsc = fi->level == 1 ? 0x5 : 0x7; + break; + case ARMFault_SyncExternal: + fsc = 0x8 | (fi->ea << 12); + break; + case ARMFault_SyncExternalOnWalk: + fsc = fi->level == 1 ? 0xc : 0xe; + fsc |= (fi->ea << 12); + break; + case ARMFault_SyncParity: + fsc = 0x409; + break; + case ARMFault_SyncParityOnWalk: + fsc = fi->level == 1 ? 0x40c : 0x40e; + break; + case ARMFault_AsyncParity: + fsc = 0x408; + break; + case ARMFault_AsyncExternal: + fsc = 0x406 | (fi->ea << 12); + break; + case ARMFault_Debug: + fsc = 0x2; + break; + case ARMFault_TLBConflict: + fsc = 0x400; + break; + case ARMFault_Lockdown: + fsc = 0x404; + break; + case ARMFault_Exclusive: + fsc = 0x405; + break; + case ARMFault_ICacheMaint: + fsc = 0x4; + break; + case ARMFault_Background: + fsc = 0x0; + break; + case ARMFault_QEMU_NSCExec: + fsc = M_FAKE_FSR_NSC_EXEC; + break; + case ARMFault_QEMU_SFault: + fsc = M_FAKE_FSR_SFAULT; + break; + default: + /* Other faults can't occur in a context that requires a + * short-format status code. + */ + g_assert_not_reached(); + } + + fsc |= (fi->domain << 4); + return fsc; +} + +/** + * arm_fi_to_lfsc: Convert fault info struct to long-format FSC + * Compare pseudocode EncodeLDFSC(), though unlike that function + * we fill in also the LPAE bit 9 of a DFSR format. + */ +static inline uint32_t arm_fi_to_lfsc(ARMMMUFaultInfo *fi) +{ + uint32_t fsc; + + switch (fi->type) { + case ARMFault_None: + return 0; + case ARMFault_AddressSize: + fsc = fi->level & 3; + break; + case ARMFault_AccessFlag: + fsc = (fi->level & 3) | (0x2 << 2); + break; + case ARMFault_Permission: + fsc = (fi->level & 3) | (0x3 << 2); + break; + case ARMFault_Translation: + fsc = (fi->level & 3) | (0x1 << 2); + break; + case ARMFault_SyncExternal: + fsc = 0x10 | (fi->ea << 12); + break; + case ARMFault_SyncExternalOnWalk: + fsc = (fi->level & 3) | (0x5 << 2) | (fi->ea << 12); + break; + case ARMFault_SyncParity: + fsc = 0x18; + break; + case ARMFault_SyncParityOnWalk: + fsc = (fi->level & 3) | (0x7 << 2); + break; + case ARMFault_AsyncParity: + fsc = 0x19; + break; + case ARMFault_AsyncExternal: + fsc = 0x11 | (fi->ea << 12); + break; + case ARMFault_Alignment: + fsc = 0x21; + break; + case ARMFault_Debug: + fsc = 0x22; + break; + case ARMFault_TLBConflict: + fsc = 0x30; + break; + case ARMFault_Lockdown: + fsc = 0x34; + break; + case ARMFault_Exclusive: + fsc = 0x35; + break; + default: + /* Other faults can't occur in a context that requires a + * long-format status code. + */ + g_assert_not_reached(); + } + + fsc |= 1 << 9; + return fsc; +} + /* Do a page table walk and add page to TLB if possible */ bool arm_tlb_fill(CPUState *cpu, vaddr address, MMUAccessType access_type, int mmu_idx, - uint32_t *fsr, ARMMMUFaultInfo *fi); + ARMMMUFaultInfo *fi); /* Return true if the stage 1 translation regime is using LPAE format page * tables */ @@ -544,15 +729,17 @@ static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx) case ARMMMUIdx_S1NSE1: case ARMMMUIdx_S1E2: case ARMMMUIdx_S2NS: + case ARMMMUIdx_MPrivNegPri: + case ARMMMUIdx_MUserNegPri: case ARMMMUIdx_MPriv: - case ARMMMUIdx_MNegPri: case ARMMMUIdx_MUser: return false; case ARMMMUIdx_S1E3: case ARMMMUIdx_S1SE0: case ARMMMUIdx_S1SE1: + case ARMMMUIdx_MSPrivNegPri: + case ARMMMUIdx_MSUserNegPri: case ARMMMUIdx_MSPriv: - case ARMMMUIdx_MSNegPri: case ARMMMUIdx_MSUser: return true; default: diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index a40a84ac24..b36206343d 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -116,12 +116,13 @@ static inline uint32_t merge_syn_data_abort(uint32_t template_syn, } static void deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type, - uint32_t fsr, uint32_t fsc, ARMMMUFaultInfo *fi) + int mmu_idx, ARMMMUFaultInfo *fi) { CPUARMState *env = &cpu->env; int target_el; bool same_el; - uint32_t syn, exc; + uint32_t syn, exc, fsr, fsc; + ARMMMUIdx arm_mmu_idx = core_to_arm_mmu_idx(env, mmu_idx); target_el = exception_target_el(env); if (fi->stage2) { @@ -130,14 +131,21 @@ static void deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type, } same_el = (arm_current_el(env) == target_el); - if (fsc == 0x3f) { - /* Caller doesn't have a long-format fault status code. This - * should only happen if this fault will never actually be reported - * to an EL that uses a syndrome register. Check that here. - * 0x3f is a (currently) reserved FSC code, in case the constructed - * syndrome does leak into the guest somehow. + if (target_el == 2 || arm_el_is_aa64(env, target_el) || + arm_s1_regime_using_lpae_format(env, arm_mmu_idx)) { + /* LPAE format fault status register : bottom 6 bits are + * status code in the same form as needed for syndrome + */ + fsr = arm_fi_to_lfsc(fi); + fsc = extract32(fsr, 0, 6); + } else { + fsr = arm_fi_to_sfsc(fi); + /* Short format FSR : this fault will never actually be reported + * to an EL that uses a syndrome register. Use a (currently) + * reserved FSR code in case the constructed syndrome does leak + * into the guest somehow. */ - assert(target_el != 2 && !arm_el_is_aa64(env, target_el)); + fsc = 0x3f; } if (access_type == MMU_INST_FETCH) { @@ -168,35 +176,16 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) { bool ret; - uint32_t fsr = 0; ARMMMUFaultInfo fi = {}; - ret = arm_tlb_fill(cs, addr, access_type, mmu_idx, &fsr, &fi); + ret = arm_tlb_fill(cs, addr, access_type, mmu_idx, &fi); if (unlikely(ret)) { ARMCPU *cpu = ARM_CPU(cs); - uint32_t fsc; - - if (retaddr) { - /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr); - } - if (fsr & (1 << 9)) { - /* LPAE format fault status register : bottom 6 bits are - * status code in the same form as needed for syndrome - */ - fsc = extract32(fsr, 0, 6); - } else { - /* Short format FSR : this fault will never actually be reported - * to an EL that uses a syndrome register. Use a (currently) - * reserved FSR code in case the constructed syndrome does leak - * into the guest somehow. deliver_fault will assert that - * we don't target an EL using the syndrome. - */ - fsc = 0x3f; - } + /* now we have a real cpu fault */ + cpu_restore_state(cs, retaddr); - deliver_fault(cpu, addr, access_type, fsr, fsc, &fi); + deliver_fault(cpu, addr, access_type, mmu_idx, &fi); } } @@ -206,27 +195,13 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, int mmu_idx, uintptr_t retaddr) { ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; - uint32_t fsr, fsc; ARMMMUFaultInfo fi = {}; - ARMMMUIdx arm_mmu_idx = core_to_arm_mmu_idx(env, mmu_idx); - - if (retaddr) { - /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr); - } - /* the DFSR for an alignment fault depends on whether we're using - * the LPAE long descriptor format, or the short descriptor format - */ - if (arm_s1_regime_using_lpae_format(env, arm_mmu_idx)) { - fsr = (1 << 9) | 0x21; - } else { - fsr = 0x1; - } - fsc = 0x21; + /* now we have a real cpu fault */ + cpu_restore_state(cs, retaddr); - deliver_fault(cpu, vaddr, access_type, fsr, fsc, &fi); + fi.type = ARMFault_Alignment; + deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi); } /* arm_cpu_do_transaction_failed: handle a memory system error response @@ -240,15 +215,10 @@ void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, MemTxResult response, uintptr_t retaddr) { ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; - uint32_t fsr, fsc; ARMMMUFaultInfo fi = {}; - ARMMMUIdx arm_mmu_idx = core_to_arm_mmu_idx(env, mmu_idx); - if (retaddr) { - /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr); - } + /* now we have a real cpu fault */ + cpu_restore_state(cs, retaddr); /* The EA bit in syndromes and fault status registers is an * IMPDEF classification of external aborts. ARM implementations @@ -256,20 +226,8 @@ void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, * Slave error (1); in QEMU we follow that. */ fi.ea = (response != MEMTX_DECODE_ERROR); - - /* The fault status register format depends on whether we're using - * the LPAE long descriptor format, or the short descriptor format. - */ - if (arm_s1_regime_using_lpae_format(env, arm_mmu_idx)) { - /* long descriptor form, STATUS 0b010000: synchronous ext abort */ - fsr = (fi.ea << 12) | (1 << 9) | 0x10; - } else { - /* short descriptor form, FSR 0b01000 : synchronous ext abort */ - fsr = (fi.ea << 12) | 0x8; - } - fsc = 0x10; - - deliver_fault(cpu, addr, access_type, fsr, fsc, &fi); + fi.type = ARMFault_SyncExternal; + deliver_fault(cpu, addr, access_type, mmu_idx, &fi); } #endif /* !defined(CONFIG_USER_ONLY) */ diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 625ef2dfd2..ba94f7d045 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -405,10 +405,7 @@ static void unallocated_encoding(DisasContext *s) static void init_tmp_a64_array(DisasContext *s) { #ifdef CONFIG_DEBUG_TCG - int i; - for (i = 0; i < ARRAY_SIZE(s->tmp_a64); i++) { - TCGV_UNUSED_I64(s->tmp_a64[i]); - } + memset(s->tmp_a64, 0, sizeof(s->tmp_a64)); #endif s->tmp_a64_count = 0; } @@ -6276,7 +6273,7 @@ static void disas_simd_scalar_pairwise(DisasContext *s, uint32_t insn) return; } - TCGV_UNUSED_PTR(fpst); + fpst = NULL; break; case 0xc: /* FMAXNMP */ case 0xd: /* FADDP */ @@ -6371,7 +6368,7 @@ static void disas_simd_scalar_pairwise(DisasContext *s, uint32_t insn) tcg_temp_free_i32(tcg_res); } - if (!TCGV_IS_UNUSED_PTR(fpst)) { + if (fpst) { tcg_temp_free_ptr(fpst); } } @@ -6387,7 +6384,7 @@ static void handle_shri_with_rndacc(TCGv_i64 tcg_res, TCGv_i64 tcg_src, bool is_u, int size, int shift) { bool extended_result = false; - bool round = !TCGV_IS_UNUSED_I64(tcg_rnd); + bool round = tcg_rnd != NULL; int ext_lshift = 0; TCGv_i64 tcg_src_hi; @@ -6533,7 +6530,7 @@ static void handle_scalar_simd_shri(DisasContext *s, uint64_t round_const = 1ULL << (shift - 1); tcg_round = tcg_const_i64(round_const); } else { - TCGV_UNUSED_I64(tcg_round); + tcg_round = NULL; } tcg_rn = read_fp_dreg(s, rn); @@ -6649,7 +6646,7 @@ static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q, uint64_t round_const = 1ULL << (shift - 1); tcg_round = tcg_const_i64(round_const); } else { - TCGV_UNUSED_I64(tcg_round); + tcg_round = NULL; } for (i = 0; i < elements; i++) { @@ -8239,8 +8236,8 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env); tcg_fpstatus = get_fpstatus_ptr(); } else { - TCGV_UNUSED_I32(tcg_rmode); - TCGV_UNUSED_PTR(tcg_fpstatus); + tcg_rmode = NULL; + tcg_fpstatus = NULL; } if (size == 3) { @@ -8360,7 +8357,7 @@ static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u, uint64_t round_const = 1ULL << (shift - 1); tcg_round = tcg_const_i64(round_const); } else { - TCGV_UNUSED_I64(tcg_round); + tcg_round = NULL; } for (i = 0; i < elements; i++) { @@ -8502,7 +8499,7 @@ static void handle_vec_simd_shrn(DisasContext *s, bool is_q, uint64_t round_const = 1ULL << (shift - 1); tcg_round = tcg_const_i64(round_const); } else { - TCGV_UNUSED_I64(tcg_round); + tcg_round = NULL; } for (i = 0; i < elements; i++) { @@ -9168,7 +9165,7 @@ static void handle_simd_3same_pair(DisasContext *s, int is_q, int u, int opcode, if (opcode >= 0x58) { fpst = get_fpstatus_ptr(); } else { - TCGV_UNUSED_PTR(fpst); + fpst = NULL; } if (!fp_access_check(s)) { @@ -9305,7 +9302,7 @@ static void handle_simd_3same_pair(DisasContext *s, int is_q, int u, int opcode, } } - if (!TCGV_IS_UNUSED_PTR(fpst)) { + if (fpst) { tcg_temp_free_ptr(fpst); } } @@ -10226,13 +10223,13 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) if (need_fpstatus) { tcg_fpstatus = get_fpstatus_ptr(); } else { - TCGV_UNUSED_PTR(tcg_fpstatus); + tcg_fpstatus = NULL; } if (need_rmode) { tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode)); gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env); } else { - TCGV_UNUSED_I32(tcg_rmode); + tcg_rmode = NULL; } if (size == 3) { @@ -10593,7 +10590,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) if (is_fp) { fpst = get_fpstatus_ptr(); } else { - TCGV_UNUSED_PTR(fpst); + fpst = NULL; } if (size == 3) { @@ -10917,7 +10914,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) } } - if (!TCGV_IS_UNUSED_PTR(fpst)) { + if (fpst) { tcg_temp_free_ptr(fpst); } } @@ -11293,8 +11290,8 @@ static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); - dc->insn_start_idx = tcg_op_buf_count(); tcg_gen_insn_start(dc->pc, 0, 0); + dc->insn_start = tcg_last_op(); } static bool aarch64_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, diff --git a/target/arm/translate.c b/target/arm/translate.c index 4afb0c86ec..781be1e219 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -159,12 +159,16 @@ static inline int get_a32_user_mem_index(DisasContext *s) return arm_to_core_mmu_idx(ARMMMUIdx_S1SE0); case ARMMMUIdx_MUser: case ARMMMUIdx_MPriv: - case ARMMMUIdx_MNegPri: return arm_to_core_mmu_idx(ARMMMUIdx_MUser); + case ARMMMUIdx_MUserNegPri: + case ARMMMUIdx_MPrivNegPri: + return arm_to_core_mmu_idx(ARMMMUIdx_MUserNegPri); case ARMMMUIdx_MSUser: case ARMMMUIdx_MSPriv: - case ARMMMUIdx_MSNegPri: return arm_to_core_mmu_idx(ARMMMUIdx_MSUser); + case ARMMMUIdx_MSUserNegPri: + case ARMMMUIdx_MSPrivNegPri: + return arm_to_core_mmu_idx(ARMMMUIdx_MSUserNegPri); case ARMMMUIdx_S2NS: default: g_assert_not_reached(); @@ -2165,8 +2169,8 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn) tmp3 = tcg_const_i32((insn & 1) << 5); break; default: - TCGV_UNUSED_I32(tmp2); - TCGV_UNUSED_I32(tmp3); + tmp2 = NULL; + tmp3 = NULL; } gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, tmp, tmp2, tmp3); tcg_temp_free_i32(tmp3); @@ -4935,7 +4939,7 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn) } } else /* size == 0 */ { if (load) { - TCGV_UNUSED_I32(tmp2); + tmp2 = NULL; for (n = 0; n < 4; n++) { tmp = tcg_temp_new_i32(); gen_aa32_ld8u(s, tmp, addr, get_mem_index(s)); @@ -6639,11 +6643,11 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tmp = neon_load_reg(rn, 1); neon_store_scratch(2, tmp); } - TCGV_UNUSED_I32(tmp3); + tmp3 = NULL; for (pass = 0; pass < 2; pass++) { if (src1_wide) { neon_load_reg64(cpu_V0, rn + pass); - TCGV_UNUSED_I32(tmp); + tmp = NULL; } else { if (pass == 1 && rd == rn) { tmp = neon_load_scratch(2); @@ -6656,7 +6660,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } if (src2_wide) { neon_load_reg64(cpu_V1, rm + pass); - TCGV_UNUSED_I32(tmp2); + tmp2 = NULL; } else { if (pass == 1 && rd == rm) { tmp2 = neon_load_scratch(2); @@ -7074,7 +7078,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) if (rm & 1) { return 1; } - TCGV_UNUSED_I32(tmp2); + tmp2 = NULL; for (pass = 0; pass < 2; pass++) { neon_load_reg64(cpu_V0, rm + pass); tmp = tcg_temp_new_i32(); @@ -7213,7 +7217,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) if (neon_2rm_is_float_op(op)) { tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass)); - TCGV_UNUSED_I32(tmp); + tmp = NULL; } else { tmp = neon_load_reg(rm, pass); } @@ -8662,7 +8666,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) rn = (insn >> 16) & 0xf; tmp = load_reg(s, rn); } else { - TCGV_UNUSED_I32(tmp); + tmp = NULL; } rd = (insn >> 12) & 0xf; switch(op1) { @@ -9501,7 +9505,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) /* compute total size */ loaded_base = 0; - TCGV_UNUSED_I32(loaded_var); + loaded_var = NULL; n = 0; for(i=0;i<16;i++) { if (insn & (1 << i)) @@ -9771,9 +9775,8 @@ gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, return 0; } -/* Translate a 32-bit thumb instruction. Returns nonzero if the instruction - is not legal. */ -static int disas_thumb2_insn(DisasContext *s, uint32_t insn) +/* Translate a 32-bit thumb instruction. */ +static void disas_thumb2_insn(DisasContext *s, uint32_t insn) { uint32_t imm, shift, offset; uint32_t rd, rn, rm, rs; @@ -9806,7 +9809,7 @@ static int disas_thumb2_insn(DisasContext *s, uint32_t insn) if (insn & (1 << 22)) { /* 0b1110_100x_x1xx_xxxx_xxxx_xxxx_xxxx_xxxx * - load/store doubleword, load/store exclusive, ldacq/strel, - * table branch. + * table branch, TT. */ if (insn == 0xe97fe97f && arm_dc_feature(s, ARM_FEATURE_M) && arm_dc_feature(s, ARM_FEATURE_V8)) { @@ -9883,8 +9886,35 @@ static int disas_thumb2_insn(DisasContext *s, uint32_t insn) } else if ((insn & (1 << 23)) == 0) { /* 0b1110_1000_010x_xxxx_xxxx_xxxx_xxxx_xxxx * - load/store exclusive word + * - TT (v8M only) */ if (rs == 15) { + if (!(insn & (1 << 20)) && + arm_dc_feature(s, ARM_FEATURE_M) && + arm_dc_feature(s, ARM_FEATURE_V8)) { + /* 0b1110_1000_0100_xxxx_1111_xxxx_xxxx_xxxx + * - TT (v8M only) + */ + bool alt = insn & (1 << 7); + TCGv_i32 addr, op, ttresp; + + if ((insn & 0x3f) || rd == 13 || rd == 15 || rn == 15) { + /* we UNDEF for these UNPREDICTABLE cases */ + goto illegal_op; + } + + if (alt && !s->v8m_secure) { + goto illegal_op; + } + + addr = load_reg(s, rn); + op = tcg_const_i32(extract32(insn, 6, 2)); + ttresp = tcg_temp_new_i32(); + gen_helper_v7m_tt(ttresp, cpu_env, addr, op); + tcg_temp_free_i32(addr); + tcg_temp_free_i32(op); + store_reg(s, rd, ttresp); + } goto illegal_op; } addr = tcg_temp_local_new_i32(); @@ -10043,7 +10073,7 @@ static int disas_thumb2_insn(DisasContext *s, uint32_t insn) tcg_gen_addi_i32(addr, addr, -offset); } - TCGV_UNUSED_I32(loaded_var); + loaded_var = NULL; for (i = 0; i < 16; i++) { if ((insn & (1 << i)) == 0) continue; @@ -10985,16 +11015,16 @@ static int disas_thumb2_insn(DisasContext *s, uint32_t insn) /* UNPREDICTABLE, unallocated hint or * PLD/PLDW/PLI (literal) */ - return 0; + return; } if (op1 & 1) { - return 0; /* PLD/PLDW/PLI or unallocated hint */ + return; /* PLD/PLDW/PLI or unallocated hint */ } if ((op2 == 0) || ((op2 & 0x3c) == 0x30)) { - return 0; /* PLD/PLDW/PLI or unallocated hint */ + return; /* PLD/PLDW/PLI or unallocated hint */ } /* UNDEF space, or an UNPREDICTABLE */ - return 1; + goto illegal_op; } } memidx = get_mem_index(s); @@ -11120,9 +11150,10 @@ static int disas_thumb2_insn(DisasContext *s, uint32_t insn) default: goto illegal_op; } - return 0; + return; illegal_op: - return 1; + gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(), + default_exception_el(s)); } static void disas_thumb_insn(DisasContext *s, uint32_t insn) @@ -11324,7 +11355,7 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn) } else if (op != 0xf) { /* mvn doesn't read its first operand */ tmp = load_reg(s, rd); } else { - TCGV_UNUSED_I32(tmp); + tmp = NULL; } tmp2 = load_reg(s, rm); @@ -11655,7 +11686,7 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn) tcg_gen_addi_i32(addr, addr, 4); } } - TCGV_UNUSED_I32(tmp); + tmp = NULL; if (insn & (1 << 8)) { if (insn & (1 << 11)) { /* pop pc */ @@ -11800,8 +11831,7 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn) case 12: { /* load/store multiple */ - TCGv_i32 loaded_var; - TCGV_UNUSED_I32(loaded_var); + TCGv_i32 loaded_var = NULL; rn = (insn >> 8) & 0x7; addr = load_reg(s, rn); for (i = 0; i < 8; i++) { @@ -12066,10 +12096,10 @@ static void arm_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); - dc->insn_start_idx = tcg_op_buf_count(); tcg_gen_insn_start(dc->pc, (dc->condexec_cond << 4) | (dc->condexec_mask >> 1), 0); + dc->insn_start = tcg_last_op(); } static bool arm_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, diff --git a/target/arm/translate.h b/target/arm/translate.h index 410ba79c0d..cd7313ace7 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -66,8 +66,8 @@ typedef struct DisasContext { bool ss_same_el; /* Bottom two bits of XScale c15_cpar coprocessor access control reg */ int c15_cpar; - /* TCG op index of the current insn_start. */ - int insn_start_idx; + /* TCG op of the current insn_start. */ + TCGOp *insn_start; #define TMP_A64_MAX 16 int tmp_a64_count; TCGv_i64 tmp_a64[TMP_A64_MAX]; @@ -117,9 +117,9 @@ static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn) syn >>= ARM_INSN_START_WORD2_SHIFT; /* We check and clear insn_start_idx to catch multiple updates. */ - assert(s->insn_start_idx != 0); - tcg_set_insn_param(s->insn_start_idx, 2, syn); - s->insn_start_idx = 0; + assert(s->insn_start != NULL); + tcg_set_insn_param(s->insn_start, 2, syn); + s->insn_start = NULL; } /* is_jmp field values */ |