@samitouri / QOSamiQemu / commits / f6bfcaaa50

target/arm/ptw.c: Add Granule Bypass Windows

Signed-off-by: Jim MacArthur <jim.macarthur@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260618-jmac-gpc3b-v3-3-353e546067e7@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Jim MacArthur committed Jun 18, 2026 at 17:33 UTC f6bfcaaa506d6ac8ed4ab4a36539899ddbbc3d46
1 file changed +77
target/arm/ptw.c
+77
@@ -343,11 +343,21 @@ bool arm_granule_protection_check(ARMGranuleProtectionConfig config,
343 .space = ARMSS_Root,
344 };
345 const uint64_t gpccr = config.gpccr;
346 + const uint64_t gpcbw = config.gpcbw;
347 unsigned pps, pgs, l0gptsz, level = 0;
348 uint64_t tableaddr, pps_mask, align, entry, index;
349 MemTxResult result;
350 int gpi;
351
352 + const uint64_t BW_ADDR_SHIFT = 30;
353 + const uint64_t BW_SIZE_SHIFT = 30;
354 + const uint64_t BW_STRIDE_SHIFT = 40;
355 +
356 + uint64_t bw_size_field = FIELD_EX64(gpcbw, GPCBW, BWSIZE);
357 + uint64_t bw_stride_field = FIELD_EX64(gpcbw, GPCBW, BWSTRIDE);
358 + uint64_t bw_addr = FIELD_EX64(gpcbw, GPCBW, BWADDR) << BW_ADDR_SHIFT;
359 + uint64_t bw_mask = 0;
360 +
361 /*
362 * We assume Granule Protection Check is enabled when
363 * calling this function (GPCCR.GPC == 1).
@@ -399,6 +409,58 @@ bool arm_granule_protection_check(ARMGranuleProtectionConfig config,
409 goto fault_walk;
410 }
411
412 + /* At this point, GPCCR_EL3 is valid */
413 +
414 + /*
415 + * GPC Priority 1 (R_GMGRR):
416 + * If GPCCR_EL3.GPCBW is 1 and the configuration GPCBW
417 + * is invalid, the access fails as GPT walk fault at level 0.
418 + */
419 + if (FIELD_EX64(gpccr, GPCCR, GPCBW)) {
420 + uint64_t bw_size = 0;
421 + uint64_t bw_stride = 0;
422 +
423 + /* BWSIZE, BWSTRIDE have a limited number of acceptable values. */
424 + switch (bw_size_field) {
425 + case 0b000:
426 + case 0b001:
427 + case 0b010:
428 + case 0b100:
429 + case 0b110:
430 + bw_size = 1ULL << (bw_size_field + BW_SIZE_SHIFT);
431 + break;
432 + default: /* Reserved value */
433 + goto fault_walk;
434 + }
435 + switch (bw_stride_field) {
436 + case 0b00000:
437 + case 0b00010:
438 + case 0b00100:
439 + case 0b00110:
440 + case 0b00111:
441 + case 0b01000:
442 + case 0b01001:
443 + case 0b01010:
444 + case 0b10000:
445 + bw_stride = 1ULL << (bw_stride_field + BW_STRIDE_SHIFT);
446 + break;
447 + default: /* Reserved value */
448 + goto fault_walk;
449 + }
450 + /*
451 + * GPCBW is invalid if the base address is:
452 + * not aligned to the size programmed in BWSIZE, or
453 + * greater than or equal to the stride value configured by BWSTRIDE.
454 + * We can make bw_mask which marks exactly which bits in bw_addr may
455 + * be set (gpcbwu:gpcbwl).
456 + */
457 + bw_mask = bw_stride - bw_size;
458 +
459 + if (bw_addr & ~bw_mask) {
460 + goto fault_walk;
461 + }
462 + }
463 +
464 /* Note this field is read-only and fixed at reset. */
465 l0gptsz = 30 + FIELD_EX64(gpccr, GPCCR, L0GPTSZ);
466
@@ -433,6 +495,20 @@ bool arm_granule_protection_check(ARMGranuleProtectionConfig config,
495 goto fault_fail;
496 }
497
498 + /*
499 + * Bypass window check.
500 + * I_JJLRM: Granule Protection Table (GPT) lookups can be skipped
501 + * in portions of the memory map by using GPC bypass windows.
502 + * I_XNHTX: The GPC bypass window check (...) is performed
503 + * immediately after priority 3.
504 + * bw_mask from earlier makes this check for us.
505 + */
506 + if (FIELD_EX64(gpccr, GPCCR, GPCBW)) {
507 + if ((paddress & bw_mask) == bw_addr) {
508 + return true;
509 + }
510 + }
511 +
512 /* GPC Priority 4: the base address of GPTBR_EL3 exceeds PPS. */
513 tableaddr = config.gptbr << 12;
514 if (tableaddr & ~pps_mask) {
@@ -3879,6 +3955,7 @@ static bool get_phys_addr_gpc(CPUARMState *env, S1Translate *ptw,
3955 };
3956 struct ARMGranuleProtectionConfig config = {
3957 .gpccr = env->cp15.gpccr_el3,
3958 + .gpcbw = env->cp15.gpcbw_el3,
3959 .gptbr = env->cp15.gptbr_el3,
3960 .parange = FIELD_EX64_IDREG(&cpu->isar, ID_AA64MMFR0, PARANGE),
3961 .support_sel2 = cpu_isar_feature(aa64_sel2, cpu),