diff --git a/target/arm/helper.c b/target/arm/helper.c index 432bd81919..93c58ad29a 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -3187,6 +3187,12 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, ret = get_phys_addr(env, value, access_type, mmu_idx, &phys_addr, &attrs, &prot, &page_size, &fi, &cacheattrs); + /* + * ATS operations only do S1 or S1+S2 translations, so we never + * have to deal with the ARMCacheAttrs format for S2 only. + */ + assert(!cacheattrs.is_s2_format); + if (ret) { /* * Some kinds of translation fault must cause exceptions rather @@ -10717,6 +10723,19 @@ static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, return true; } +static bool ptw_attrs_are_device(CPUARMState *env, ARMCacheAttrs cacheattrs) +{ + /* + * For an S1 page table walk, the stage 1 attributes are always + * some form of "this is Normal memory". The combined S1+S2 + * attributes are therefore only Device if stage 2 specifies Device. + * With HCR_EL2.FWB == 0 this is when descriptor bits [5:4] are 0b00, + * ie when cacheattrs.attrs bits [3:2] are 0b00. + */ + assert(cacheattrs.is_s2_format); + return (cacheattrs.attrs & 0xc) == 0; +} + /* Translate a S1 pagetable walk through S2 if needed. */ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, hwaddr addr, bool *is_secure, @@ -10745,7 +10764,7 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, return ~0; } if ((arm_hcr_el2_eff(env) & HCR_PTW) && - (cacheattrs.attrs & 0xf0) == 0) { + ptw_attrs_are_device(env, cacheattrs)) { /* * PTW set and S1 walk touched S2 Device memory: * generate Permission fault. @@ -11817,12 +11836,14 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address, } if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) { - cacheattrs->attrs = convert_stage2_attrs(env, extract32(attrs, 0, 4)); + cacheattrs->is_s2_format = true; + cacheattrs->attrs = extract32(attrs, 0, 4); } else { /* Index into MAIR registers for cache attributes */ uint8_t attrindx = extract32(attrs, 0, 3); uint64_t mair = env->cp15.mair_el[regime_el(env, mmu_idx)]; assert(attrindx <= 7); + cacheattrs->is_s2_format = false; cacheattrs->attrs = extract64(mair, attrindx * 8, 8); } @@ -12560,14 +12581,22 @@ static uint8_t combine_cacheattr_nibble(uint8_t s1, uint8_t s2) /* Combine S1 and S2 cacheability/shareability attributes, per D4.5.4 * and CombineS1S2Desc() * + * @env: CPUARMState * @s1: Attributes from stage 1 walk * @s2: Attributes from stage 2 walk */ -static ARMCacheAttrs combine_cacheattrs(ARMCacheAttrs s1, ARMCacheAttrs s2) +static ARMCacheAttrs combine_cacheattrs(CPUARMState *env, + ARMCacheAttrs s1, ARMCacheAttrs s2) { uint8_t s1lo, s2lo, s1hi, s2hi; ARMCacheAttrs ret; bool tagged = false; + uint8_t s2_mair_attrs; + + assert(s2.is_s2_format && !s1.is_s2_format); + ret.is_s2_format = false; + + s2_mair_attrs = convert_stage2_attrs(env, s2.attrs); if (s1.attrs == 0xf0) { tagged = true; @@ -12575,9 +12604,9 @@ static ARMCacheAttrs combine_cacheattrs(ARMCacheAttrs s1, ARMCacheAttrs s2) } s1lo = extract32(s1.attrs, 0, 4); - s2lo = extract32(s2.attrs, 0, 4); + s2lo = extract32(s2_mair_attrs, 0, 4); s1hi = extract32(s1.attrs, 4, 4); - s2hi = extract32(s2.attrs, 4, 4); + s2hi = extract32(s2_mair_attrs, 4, 4); /* Combine shareability attributes (table D4-43) */ if (s1.shareability == 2 || s2.shareability == 2) { @@ -12731,7 +12760,7 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, } cacheattrs->shareability = 0; } - *cacheattrs = combine_cacheattrs(*cacheattrs, cacheattrs2); + *cacheattrs = combine_cacheattrs(env, *cacheattrs, cacheattrs2); /* Check if IPA translates to secure or non-secure PA space. */ if (arm_is_secure_below_el3(env)) { @@ -12849,6 +12878,7 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, /* Fill in cacheattr a-la AArch64.TranslateAddressS1Off. */ hcr = arm_hcr_el2_eff(env); cacheattrs->shareability = 0; + cacheattrs->is_s2_format = false; if (hcr & HCR_DC) { if (hcr & HCR_DCT) { memattr = 0xf0; /* Tagged, Normal, WB, RWA */ diff --git a/target/arm/internals.h b/target/arm/internals.h index 6ca0e95746..9b354eea7e 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1149,8 +1149,13 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, /* Cacheability and shareability attributes for a memory access */ typedef struct ARMCacheAttrs { - unsigned int attrs:8; /* as in the MAIR register encoding */ + /* + * If is_s2_format is true, attrs is the S2 descriptor bits [5:2] + * Otherwise, attrs is the same as the MAIR_EL1 8-bit format + */ + unsigned int attrs:8; unsigned int shareability:2; /* as in the SH field of the VMSAv8-64 PTEs */ + bool is_s2_format:1; } ARMCacheAttrs; bool get_phys_addr(CPUARMState *env, target_ulong address,