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~

Reply via email to