[PATCH v2 28/37] target/arm: Implement TLBIP RVAE1, RVAAE1, RVALE1, RVAALE1

Richard Henderson posted 37 patches 1 month ago
Maintainers: Peter Xu <peterx@redhat.com>, Fabiano Rosas <farosas@suse.de>, Peter Maydell <peter.maydell@linaro.org>, Alexander Graf <agraf@csgraf.de>, Mads Ynddal <mads@ynddal.dk>, Paolo Bonzini <pbonzini@redhat.com>
[PATCH v2 28/37] target/arm: Implement TLBIP RVAE1, RVAAE1, RVALE1, RVAALE1
Posted by Richard Henderson 1 month ago
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/tcg/tlb-insns.c | 93 ++++++++++++++++++++++++++++++--------
 1 file changed, 74 insertions(+), 19 deletions(-)

diff --git a/target/arm/tcg/tlb-insns.c b/target/arm/tcg/tlb-insns.c
index f7510a1208..daadba7bfc 100644
--- a/target/arm/tcg/tlb-insns.c
+++ b/target/arm/tcg/tlb-insns.c
@@ -918,16 +918,43 @@ static TLBIRange tlbi_aa64_get_range(CPUARMState *env, ARMMMUIdx mmuidx,
     return ret;
 }
 
-static void do_rvae_write(CPUARMState *env, uint64_t value,
-                          int idxmap, bool synced)
+static TLBIRange tlbi_aa64_get_range128(CPUARMState *env, ARMMMUIdx mmuidx,
+                                        uint64_t vallo, uint64_t valhi)
 {
-    ARMMMUIdx one_idx = ARM_MMU_IDX_A | ctz32(idxmap);
-    TLBIRange range;
-    int bits;
+    uint64_t uaddr = extract64(valhi << 12, 0, 56);
+    ARMVAParameters param = aa64_va_parameters(env, uaddr, mmuidx, true, false);
+    TLBIRange ret = { };
+    unsigned page_size_granule = extract64(vallo, 46, 2);
+    ARMGranuleSize gran = tlbi_range_tg_to_gran_size(page_size_granule);
 
-    range = tlbi_aa64_get_range(env, one_idx, value);
-    bits = tlbbits_for_regime(env, one_idx, range.base);
+    /* The granule encoded in value must match the granule in use. */
+    if (gran != param.gran) {
+        qemu_log_mask(LOG_GUEST_ERROR, "Invalid tlbi page size granule %d\n",
+                      page_size_granule);
+    } else {
+        unsigned page_shift = arm_granule_bits(gran);
+        unsigned num = extract64(vallo, 39, 5);
+        unsigned scale = extract64(vallo, 44, 2);
+        unsigned exponent = (5 * scale) + 1;
+        uint64_t max = 1ull << 56;
 
+        ret.length = (num + 1) << (exponent + page_shift);
+        ret.length = MIN(ret.length, max - uaddr);
+        /*
+         * Note that TLBIPRange ignores the high bits, because the HW TLB
+         * does not use it.  But the qemu softmmu tlb does, so sign-extend
+         * if and only if the regime has two ranges.
+         */
+        ret.base = uaddr | (-(uint64_t)param.select << 56);
+    }
+
+    return ret;
+}
+
+static void do_flush_range(CPUARMState *env, ARMMMUIdx one_idx, int idxmap,
+                           bool synced, TLBIRange range)
+{
+    int bits = tlbbits_for_regime(env, one_idx, range.base);
     if (synced) {
         tlb_flush_range_by_mmuidx_all_cpus_synced(env_cpu(env),
                                                   range.base,
@@ -940,6 +967,22 @@ static void do_rvae_write(CPUARMState *env, uint64_t value,
     }
 }
 
+static void do_rvae_write(CPUARMState *env, uint64_t value,
+                          int idxmap, bool synced)
+{
+    ARMMMUIdx one_idx = ARM_MMU_IDX_A | ctz32(idxmap);
+    do_flush_range(env, one_idx, idxmap, synced,
+                   tlbi_aa64_get_range(env, one_idx, value));
+}
+
+static void do_rvae_write128(CPUARMState *env, uint64_t vallo, uint64_t valhi,
+                             int idxmap, bool synced)
+{
+    ARMMMUIdx one_idx = ARM_MMU_IDX_A | ctz32(idxmap);
+    do_flush_range(env, one_idx, idxmap, synced,
+                   tlbi_aa64_get_range128(env, one_idx, vallo, valhi));
+}
+
 static void tlbi_aa64_rvae1_write(CPUARMState *env,
                                   const ARMCPRegInfo *ri,
                                   uint64_t value)
@@ -955,6 +998,14 @@ static void tlbi_aa64_rvae1_write(CPUARMState *env,
                   tlb_force_broadcast(env));
 }
 
+static void tlbi_aa64_rvae1_write128(CPUARMState *env,
+                                     const ARMCPRegInfo *ri,
+                                     uint64_t vallo, uint64_t valhi)
+{
+    do_rvae_write128(env, vallo, valhi, vae1_tlbmask(env),
+                     tlb_force_broadcast(env));
+}
+
 static void tlbi_aa64_rvae1is_write(CPUARMState *env,
                                     const ARMCPRegInfo *ri,
                                     uint64_t value)
@@ -1095,28 +1146,32 @@ static const ARMCPRegInfo tlbirange_reginfo[] = {
       .writefn = tlbi_aa64_rvae1is_write },
     { .name = "TLBI_RVAE1", .state = ARM_CP_STATE_AA64,
       .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 1,
-      .access = PL1_W, .accessfn = access_ttlb,
-      .type = ARM_CP_NO_RAW | ARM_CP_ADD_TLBI_NXS,
+      .access = PL1_W, .accessfn = access_ttlb, .access128fn = access_ttlb,
+      .type = ARM_CP_NO_RAW | ARM_CP_ADD_TLBI_NXS | ARM_CP_128BIT,
       .fgt = FGT_TLBIRVAE1,
-      .writefn = tlbi_aa64_rvae1_write },
+      .writefn = tlbi_aa64_rvae1_write,
+      .write128fn = tlbi_aa64_rvae1_write128 },
     { .name = "TLBI_RVAAE1", .state = ARM_CP_STATE_AA64,
       .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 3,
-      .access = PL1_W, .accessfn = access_ttlb,
-      .type = ARM_CP_NO_RAW | ARM_CP_ADD_TLBI_NXS,
+      .access = PL1_W, .accessfn = access_ttlb, .access128fn = access_ttlb,
+      .type = ARM_CP_NO_RAW | ARM_CP_ADD_TLBI_NXS | ARM_CP_128BIT,
       .fgt = FGT_TLBIRVAAE1,
-      .writefn = tlbi_aa64_rvae1_write },
+      .writefn = tlbi_aa64_rvae1_write,
+      .write128fn = tlbi_aa64_rvae1_write128 },
    { .name = "TLBI_RVALE1", .state = ARM_CP_STATE_AA64,
       .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 5,
-      .access = PL1_W, .accessfn = access_ttlb,
-      .type = ARM_CP_NO_RAW | ARM_CP_ADD_TLBI_NXS,
+      .access = PL1_W, .accessfn = access_ttlb, .access128fn = access_ttlb,
+      .type = ARM_CP_NO_RAW | ARM_CP_ADD_TLBI_NXS | ARM_CP_128BIT,
       .fgt = FGT_TLBIRVALE1,
-      .writefn = tlbi_aa64_rvae1_write },
+      .writefn = tlbi_aa64_rvae1_write,
+      .write128fn = tlbi_aa64_rvae1_write128 },
     { .name = "TLBI_RVAALE1", .state = ARM_CP_STATE_AA64,
       .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 7,
-      .access = PL1_W, .accessfn = access_ttlb,
-      .type = ARM_CP_NO_RAW | ARM_CP_ADD_TLBI_NXS,
+      .access = PL1_W, .accessfn = access_ttlb, .access128fn = access_ttlb,
+      .type = ARM_CP_NO_RAW | ARM_CP_ADD_TLBI_NXS | ARM_CP_128BIT,
       .fgt = FGT_TLBIRVAALE1,
-      .writefn = tlbi_aa64_rvae1_write },
+      .writefn = tlbi_aa64_rvae1_write,
+      .write128fn = tlbi_aa64_rvae1_write128 },
     { .name = "TLBI_RIPAS2E1IS", .state = ARM_CP_STATE_AA64,
       .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 2,
       .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_ADD_TLBI_NXS,
-- 
2.43.0
Re: [PATCH v2 28/37] target/arm: Implement TLBIP RVAE1, RVAAE1, RVALE1, RVAALE1
Posted by Peter Maydell 3 weeks, 4 days ago
On Tue, 14 Oct 2025 at 21:09, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/arm/tcg/tlb-insns.c | 93 ++++++++++++++++++++++++++++++--------
>  1 file changed, 74 insertions(+), 19 deletions(-)
>
> diff --git a/target/arm/tcg/tlb-insns.c b/target/arm/tcg/tlb-insns.c
> index f7510a1208..daadba7bfc 100644
> --- a/target/arm/tcg/tlb-insns.c
> +++ b/target/arm/tcg/tlb-insns.c
> @@ -918,16 +918,43 @@ static TLBIRange tlbi_aa64_get_range(CPUARMState *env, ARMMMUIdx mmuidx,
>      return ret;
>  }
>
> -static void do_rvae_write(CPUARMState *env, uint64_t value,
> -                          int idxmap, bool synced)
> +static TLBIRange tlbi_aa64_get_range128(CPUARMState *env, ARMMMUIdx mmuidx,
> +                                        uint64_t vallo, uint64_t valhi)
>  {
> -    ARMMMUIdx one_idx = ARM_MMU_IDX_A | ctz32(idxmap);
> -    TLBIRange range;
> -    int bits;
> +    uint64_t uaddr = extract64(valhi << 12, 0, 56);
> +    ARMVAParameters param = aa64_va_parameters(env, uaddr, mmuidx, true, false);
> +    TLBIRange ret = { };
> +    unsigned page_size_granule = extract64(vallo, 46, 2);
> +    ARMGranuleSize gran = tlbi_range_tg_to_gran_size(page_size_granule);
>
> -    range = tlbi_aa64_get_range(env, one_idx, value);
> -    bits = tlbbits_for_regime(env, one_idx, range.base);
> +    /* The granule encoded in value must match the granule in use. */
> +    if (gran != param.gran) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "Invalid tlbi page size granule %d\n",
> +                      page_size_granule);

Having an early-return here would make this code more obviously
parallel with tlbi_aa64_get_range().

> +    } else {
> +        unsigned page_shift = arm_granule_bits(gran);
> +        unsigned num = extract64(vallo, 39, 5);
> +        unsigned scale = extract64(vallo, 44, 2);
> +        unsigned exponent = (5 * scale) + 1;
> +        uint64_t max = 1ull << 56;
>
> +        ret.length = (num + 1) << (exponent + page_shift);
> +        ret.length = MIN(ret.length, max - uaddr);
> +        /*
> +         * Note that TLBIPRange ignores the high bits, because the HW TLB
> +         * does not use it.  But the qemu softmmu tlb does, so sign-extend
> +         * if and only if the regime has two ranges.
> +         */
> +        ret.base = uaddr | (-(uint64_t)param.select << 56);

I think it would be clearer if we wrote this "sign extend
based on param.select" the same way that tlbi_aa64_get_range()
does".

Otherwise
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM