On 5/28/26 08:34, Jim MacArthur wrote:
Signed-off-by: Jim MacArthur <[email protected]>
---
target/arm/ptw.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index 0a5201763a..46568cc5cb 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -341,11 +341,21 @@ bool
arm_granule_protection_check(ARMGranuleProtectionConfig config,
.space = ARMSS_Root,
};
const uint64_t gpccr = config.gpccr;
+ const uint64_t gpcbw = config.gpcbw;
unsigned pps, pgs, l0gptsz, level = 0;
uint64_t tableaddr, pps_mask, align, entry, index;
MemTxResult result;
int gpi;
+ const uint64_t BW_ADDR_SHIFT = 30;
+ const uint64_t BW_SIZE_SHIFT = 30;
+ const uint64_t BW_STRIDE_SHIFT = 40;
+
+ uint64_t bw_start = FIELD_EX64(gpcbw, GPCBW, BWADDR) << BW_ADDR_SHIFT;
+ uint64_t bw_size_field = FIELD_EX64(gpcbw, GPCBW, BWSIZE);
+ uint64_t bw_stride_mask = -1L << (FIELD_EX64(gpcbw, GPCBW, BWSTRIDE) +
+ BW_STRIDE_SHIFT + 1);
This appears to be the inverse of what you wanted, setting high bits instead of setting
low bits.
Never "L", always LL or ULL; but here you certainly want MAKE_64BIT_MASK.
+
/*
* We assume Granule Protection Check is enabled when
* calling this function (GPCCR.GPC == 1).
@@ -383,6 +393,28 @@ bool
arm_granule_protection_check(ARMGranuleProtectionConfig config,
goto fault_walk;
}
+ /* At this point, GPCCR_EL3 is valid */
Not true, because you added the new block before validating PGS...
+
+ /*
+ * GPC Priority 1 (R_GMGRR):
+ * If GPCCR_EL3.GPCBW is 1 and the configuration GPCBW
+ * is invalid, the access fails as GPT walk fault at level 0.
+ */
+ if (FIELD_EX64(gpccr, GPCCR, GPCBW)) {
+ /*
+ * GPCBW is invalid if the base address is:
+ * not aligned to the size programmed in BWSIZE, or
+ * greater than or equal to the stride value configured by BWSTRIDE.
+ */
+ uint64_t bw_size_mask = -1L << (bw_size_field + 31);
+ if (bw_start & bw_size_mask) {
+ goto fault_walk;
+ }
+ if (bw_start & bw_stride_mask) {
+ goto fault_walk;
+ }
+ }
+
switch (FIELD_EX64(gpccr, GPCCR, PGS)) {
... here.
None of the checks you're adding are correct:
- Missing size and stride validation,
- Alignment check vs size is incorrect; you wanted
bw_start & MAKE_64BIT_MASK(0, bw_size + BW_ADDR_SHIFT)
- Check vs stride is incorrect; you wanted bw_stride <= bw_addr.
See GPCRegistersConsistent().
@@ -431,6 +463,23 @@ bool
arm_granule_protection_check(ARMGranuleProtectionConfig config,
goto fault_fail;
}
+ /*
+ * Bypass window check.
+ * I_JJLRM: Granule Protection Table (GPT) lookups can be skipped
+ * in portions of the memory map by using GPC bypass windows.
+ * I_XNHTX: The GPC bypass window check (...) is performed
+ * immediately after priority 3.
+ */
+ if (FIELD_EX64(gpccr, GPCCR, GPCBW)) {
+ uint64_t bw_size = 1 << (bw_size_field + BW_SIZE_SHIFT);
+ uint64_t effective_address = paddress & bw_stride_mask;
+
+ if (effective_address >= bw_start &&
+ effective_address < (bw_start + bw_size)) {
No need for extra ().
r~