aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2022-05-05 19:39:47 +0100
committerPeter Maydell <peter.maydell@linaro.org>2022-05-19 16:19:01 +0100
commit9f225e607f215003de1e4157255bb0199adff9aa (patch)
treef11f288961b57b95a5089505189be16412edcfe4 /target
parent78ac2eebbab9150edf5d0d00e3648f5ebb599001 (diff)
downloadqemu-9f225e607f215003de1e4157255bb0199adff9aa.zip
qemu-9f225e607f215003de1e4157255bb0199adff9aa.tar.gz
qemu-9f225e607f215003de1e4157255bb0199adff9aa.tar.bz2
target/arm: Postpone interpretation of stage 2 descriptor attribute bits
In the original Arm v8 two-stage translation, both stage 1 and stage 2 specify memory attributes (memory type, cacheability, shareability); these are then combined to produce the overall memory attributes for the whole stage 1+2 access. In QEMU we implement this by having get_phys_addr() fill in an ARMCacheAttrs struct, and we convert both the stage 1 and stage 2 attribute bit formats to the same encoding (an 8-bit attribute value matching the MAIR_EL1 fields, plus a 2-bit shareability value). The new FEAT_S2FWB feature allows the guest to enable a different interpretation of the attribute bits in the stage 2 descriptors. These bits can now be used to control details of how the stage 1 and 2 attributes should be combined (for instance they can say "always use the stage 1 attributes" or "ignore the stage 1 attributes and always be Device memory"). This means we need to pass the raw bit information for stage 2 down to the function which combines the stage 1 and stage 2 information. Add a field to ARMCacheAttrs that indicates whether the attrs field should be interpreted as MAIR format, or as the raw stage 2 attribute bits from the descriptor, and store the appropriate values when filling in cacheattrs. We only need to interpret the attrs field in a few places: * in do_ats_write(), where we know to expect a MAIR value (there is no ATS instruction to do a stage-2-only walk) * in S1_ptw_translate(), where we want to know whether the combined S1 + S2 attributes indicate Device memory that should provoke a fault * in combine_cacheattrs(), which does the S1 + S2 combining Update those places accordingly. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20220505183950.2781801-2-peter.maydell@linaro.org
Diffstat (limited to 'target')
-rw-r--r--target/arm/helper.c42
-rw-r--r--target/arm/internals.h7
2 files changed, 42 insertions, 7 deletions
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 432bd81..93c58ad 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 6ca0e95..9b354ee 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,