diff mbox series

[v2,4/4] target/arm: Add support for DC CVAP & DC CVADP ins

Message ID 20191105234100.22052-5-beata.michalska@linaro.org
State Superseded
Headers show
Series target/arm: Support for Data Cache Clean up to PoP | expand

Commit Message

Beata Michalska Nov. 5, 2019, 11:41 p.m. UTC
ARMv8.2 introduced support for Data Cache Clean instructions
to PoP (point-of-persistence) - DC CVAP and PoDP (point-of-deep-persistence)
- DV CVADP. Both specify conceptual points in a memory system where all writes
that are to reach them are considered persistent.
The support provided considers both to be actually the same so there is no
distinction between the two. If none is available (there is no backing store
for given memory) both will result in Data Cache Clean up to the point of
coherency. Otherwise sync for the specified range shall be performed.

Signed-off-by: Beata Michalska <beata.michalska@linaro.org>

---
 linux-user/elfload.c |  2 ++
 target/arm/cpu.h     | 10 ++++++++++
 target/arm/cpu64.c   |  1 +
 target/arm/helper.c  | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 69 insertions(+)

-- 
2.7.4

Comments

Richard Henderson Nov. 6, 2019, 12:37 p.m. UTC | #1
On 11/6/19 12:41 AM, Beata Michalska wrote:
> ARMv8.2 introduced support for Data Cache Clean instructions

> to PoP (point-of-persistence) - DC CVAP and PoDP (point-of-deep-persistence)

> - DV CVADP. Both specify conceptual points in a memory system where all writes

> that are to reach them are considered persistent.

> The support provided considers both to be actually the same so there is no

> distinction between the two. If none is available (there is no backing store

> for given memory) both will result in Data Cache Clean up to the point of

> coherency. Otherwise sync for the specified range shall be performed.

> 

> Signed-off-by: Beata Michalska <beata.michalska@linaro.org>

> ---

>  linux-user/elfload.c |  2 ++

>  target/arm/cpu.h     | 10 ++++++++++

>  target/arm/cpu64.c   |  1 +

>  target/arm/helper.c  | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++

>  4 files changed, 69 insertions(+)


Reviewed-by: Richard Henderson <richard.henderson@linaro.org>



r~
Philippe Mathieu-Daudé Nov. 28, 2023, 11:24 a.m. UTC | #2
Hi,

On 6/11/19 00:41, Beata Michalska wrote:
> ARMv8.2 introduced support for Data Cache Clean instructions
> to PoP (point-of-persistence) - DC CVAP and PoDP (point-of-deep-persistence)
> - DV CVADP. Both specify conceptual points in a memory system where all writes
> that are to reach them are considered persistent.
> The support provided considers both to be actually the same so there is no
> distinction between the two. If none is available (there is no backing store
> for given memory) both will result in Data Cache Clean up to the point of
> coherency. Otherwise sync for the specified range shall be performed.
> 
> Signed-off-by: Beata Michalska <beata.michalska@linaro.org>
> ---
>   linux-user/elfload.c |  2 ++
>   target/arm/cpu.h     | 10 ++++++++++
>   target/arm/cpu64.c   |  1 +
>   target/arm/helper.c  | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>   4 files changed, 69 insertions(+)


> +#ifndef CONFIG_USER_ONLY
> +static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *opaque,
> +                          uint64_t value)
> +{
> +    ARMCPU *cpu = env_archcpu(env);
> +    /* CTR_EL0 System register -> DminLine, bits [19:16] */
> +    uint64_t dline_size = 4 << ((cpu->ctr >> 16) & 0xF);
> +    uint64_t vaddr_in = (uint64_t) value;
> +    uint64_t vaddr = vaddr_in & ~(dline_size - 1);
> +    void *haddr;
> +    int mem_idx = cpu_mmu_index(env, false);
> +
> +    /* This won't be crossing page boundaries */
> +    haddr = probe_read(env, vaddr, dline_size, mem_idx, GETPC());
> +    if (haddr) {
> +
> +        ram_addr_t offset;
> +        MemoryRegion *mr;
> +
> +        /* RCU lock is already being held */
> +        mr = memory_region_from_host(haddr, &offset);
> +
> +        if (mr) {
> +            memory_region_do_writeback(mr, offset, dline_size);
> +        }
> +    }
> +}


> +#ifndef CONFIG_USER_ONLY
> +    /* Data Cache clean instructions up to PoP */
> +    if (cpu_isar_feature(aa64_dcpop, cpu)) {

Am I correct understanding this is a TCG-only feature?


> +        define_one_arm_cp_reg(cpu, dcpop_reg);
> +
> +        if (cpu_isar_feature(aa64_dcpodp, cpu)) {
> +            define_one_arm_cp_reg(cpu, dcpodp_reg);
> +        }
> +    }
> +#endif /*CONFIG_USER_ONLY*/
>   #endif
>   
>       /*
Peter Maydell Nov. 28, 2023, 11:34 a.m. UTC | #3
On Tue, 28 Nov 2023 at 11:24, Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
>
> Hi,
>
> On 6/11/19 00:41, Beata Michalska wrote:
> > ARMv8.2 introduced support for Data Cache Clean instructions
> > to PoP (point-of-persistence) - DC CVAP and PoDP (point-of-deep-persistence)
> > - DV CVADP. Both specify conceptual points in a memory system where all writes
> > that are to reach them are considered persistent.
> > The support provided considers both to be actually the same so there is no
> > distinction between the two. If none is available (there is no backing store
> > for given memory) both will result in Data Cache Clean up to the point of
> > coherency. Otherwise sync for the specified range shall be performed.
> >
> > Signed-off-by: Beata Michalska <beata.michalska@linaro.org>
> > ---
> >   linux-user/elfload.c |  2 ++
> >   target/arm/cpu.h     | 10 ++++++++++
> >   target/arm/cpu64.c   |  1 +
> >   target/arm/helper.c  | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> >   4 files changed, 69 insertions(+)
>
>
> > +#ifndef CONFIG_USER_ONLY
> > +static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *opaque,
> > +                          uint64_t value)
> > +{
> > +    ARMCPU *cpu = env_archcpu(env);
> > +    /* CTR_EL0 System register -> DminLine, bits [19:16] */
> > +    uint64_t dline_size = 4 << ((cpu->ctr >> 16) & 0xF);
> > +    uint64_t vaddr_in = (uint64_t) value;
> > +    uint64_t vaddr = vaddr_in & ~(dline_size - 1);
> > +    void *haddr;
> > +    int mem_idx = cpu_mmu_index(env, false);
> > +
> > +    /* This won't be crossing page boundaries */
> > +    haddr = probe_read(env, vaddr, dline_size, mem_idx, GETPC());
> > +    if (haddr) {
> > +
> > +        ram_addr_t offset;
> > +        MemoryRegion *mr;
> > +
> > +        /* RCU lock is already being held */
> > +        mr = memory_region_from_host(haddr, &offset);
> > +
> > +        if (mr) {
> > +            memory_region_do_writeback(mr, offset, dline_size);
> > +        }
> > +    }
> > +}
>
>
> > +#ifndef CONFIG_USER_ONLY
> > +    /* Data Cache clean instructions up to PoP */
> > +    if (cpu_isar_feature(aa64_dcpop, cpu)) {
>
> Am I correct understanding this is a TCG-only feature?

For KVM, whether the vCPU implements these cache
maintenance instructions is up to it -- like all insns,
QEMU doesn't ever see if the guest executes them or not
(either the host CPU just implements them, or the host
kernel traps and handles them). The code in this patch is
specifically for the QEMU TCG emulation of them.

thanks
-- PMM
Philippe Mathieu-Daudé Nov. 28, 2023, 11:44 a.m. UTC | #4
On 28/11/23 12:34, Peter Maydell wrote:
> On Tue, 28 Nov 2023 at 11:24, Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
>>
>> Hi,
>>
>> On 6/11/19 00:41, Beata Michalska wrote:
>>> ARMv8.2 introduced support for Data Cache Clean instructions
>>> to PoP (point-of-persistence) - DC CVAP and PoDP (point-of-deep-persistence)
>>> - DV CVADP. Both specify conceptual points in a memory system where all writes
>>> that are to reach them are considered persistent.
>>> The support provided considers both to be actually the same so there is no
>>> distinction between the two. If none is available (there is no backing store
>>> for given memory) both will result in Data Cache Clean up to the point of
>>> coherency. Otherwise sync for the specified range shall be performed.
>>>
>>> Signed-off-by: Beata Michalska <beata.michalska@linaro.org>
>>> ---
>>>    linux-user/elfload.c |  2 ++
>>>    target/arm/cpu.h     | 10 ++++++++++
>>>    target/arm/cpu64.c   |  1 +
>>>    target/arm/helper.c  | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>    4 files changed, 69 insertions(+)
>>
>>
>>> +#ifndef CONFIG_USER_ONLY
>>> +static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *opaque,
>>> +                          uint64_t value)
>>> +{
>>> +    ARMCPU *cpu = env_archcpu(env);
>>> +    /* CTR_EL0 System register -> DminLine, bits [19:16] */
>>> +    uint64_t dline_size = 4 << ((cpu->ctr >> 16) & 0xF);
>>> +    uint64_t vaddr_in = (uint64_t) value;
>>> +    uint64_t vaddr = vaddr_in & ~(dline_size - 1);
>>> +    void *haddr;
>>> +    int mem_idx = cpu_mmu_index(env, false);
>>> +
>>> +    /* This won't be crossing page boundaries */
>>> +    haddr = probe_read(env, vaddr, dline_size, mem_idx, GETPC());
>>> +    if (haddr) {
>>> +
>>> +        ram_addr_t offset;
>>> +        MemoryRegion *mr;
>>> +
>>> +        /* RCU lock is already being held */
>>> +        mr = memory_region_from_host(haddr, &offset);
>>> +
>>> +        if (mr) {
>>> +            memory_region_do_writeback(mr, offset, dline_size);
>>> +        }
>>> +    }
>>> +}
>>
>>
>>> +#ifndef CONFIG_USER_ONLY
>>> +    /* Data Cache clean instructions up to PoP */
>>> +    if (cpu_isar_feature(aa64_dcpop, cpu)) {
>>
>> Am I correct understanding this is a TCG-only feature?
> 
> For KVM, whether the vCPU implements these cache
> maintenance instructions is up to it -- like all insns,
> QEMU doesn't ever see if the guest executes them or not
> (either the host CPU just implements them, or the host
> kernel traps and handles them). The code in this patch is
> specifically for the QEMU TCG emulation of them.

Thank you Peter. In this case I'm compiling HVF, but this is the
same reasoning. I'll add #ifdef'ry similar to ats_write() (commit
9fb005b02d "target/arm: Restrict the Address Translate write operation
to TCG accel"):

-- >8 --
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 99c7da9ca4..a05e613e10 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7629,6 +7629,7 @@ static const ARMCPRegInfo rndr_reginfo[] = {
  static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *opaque,
                            uint64_t value)
  {
+#ifdef CONFIG_TCG
      ARMCPU *cpu = env_archcpu(env);
      /* CTR_EL0 System register -> DminLine, bits [19:16] */
      uint64_t dline_size = 4 << ((cpu->ctr >> 16) & 0xF);
@@ -7653,6 +7654,10 @@ static void dccvap_writefn(CPUARMState *env, 
const ARMCPRegInfo *opaque,
          }
  #endif /*CONFIG_USER_ONLY*/
      }
+#else
+    /* Handled by hardware accelerator. */
+    g_assert_not_reached();
+#endif /* CONFIG_TCG */
  }
---

Regards,

Phil.
Richard Henderson Nov. 28, 2023, 6:07 p.m. UTC | #5
On 11/28/23 05:44, Philippe Mathieu-Daudé wrote:
> Thank you Peter. In this case I'm compiling HVF, but this is the
> same reasoning. I'll add #ifdef'ry similar to ats_write() (commit
> 9fb005b02d "target/arm: Restrict the Address Translate write operation
> to TCG accel"):
> 
> -- >8 --
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 99c7da9ca4..a05e613e10 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -7629,6 +7629,7 @@ static const ARMCPRegInfo rndr_reginfo[] = {
>   static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *opaque,
>                             uint64_t value)
>   {
> +#ifdef CONFIG_TCG
>       ARMCPU *cpu = env_archcpu(env);
>       /* CTR_EL0 System register -> DminLine, bits [19:16] */
>       uint64_t dline_size = 4 << ((cpu->ctr >> 16) & 0xF);
> @@ -7653,6 +7654,10 @@ static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo 
> *opaque,
>           }
>   #endif /*CONFIG_USER_ONLY*/
>       }
> +#else
> +    /* Handled by hardware accelerator. */
> +    g_assert_not_reached();
> +#endif /* CONFIG_TCG */
>   }

Yep.

r~
diff mbox series

Patch

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index f6693e5..07b16cc 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -656,6 +656,7 @@  static uint32_t get_elf_hwcap(void)
     GET_FEATURE_ID(aa64_jscvt, ARM_HWCAP_A64_JSCVT);
     GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB);
     GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM);
+    GET_FEATURE_ID(aa64_dcpop, ARM_HWCAP_A64_DCPOP);
 
     return hwcaps;
 }
@@ -665,6 +666,7 @@  static uint32_t get_elf_hwcap2(void)
     ARMCPU *cpu = ARM_CPU(thread_cpu);
     uint32_t hwcaps = 0;
 
+    GET_FEATURE_ID(aa64_dcpodp, ARM_HWCAP2_A64_DCPODP);
     GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2);
     GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT);
 
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index e1a66a2..0dc22c6 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3617,6 +3617,16 @@  static inline bool isar_feature_aa64_frint(const ARMISARegisters *id)
     return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FRINTTS) != 0;
 }
 
+static inline bool isar_feature_aa64_dcpop(const ARMISARegisters *id)
+{
+    return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, DPB) != 0;
+}
+
+static inline bool isar_feature_aa64_dcpodp(const ARMISARegisters *id)
+{
+    return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, DPB) >= 2;
+}
+
 static inline bool isar_feature_aa64_fp16(const ARMISARegisters *id)
 {
     /* We always set the AdvSIMD and FP fields identically wrt FP16.  */
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 68baf04..e6a033e 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -661,6 +661,7 @@  static void aarch64_max_initfn(Object *obj)
         cpu->isar.id_aa64isar0 = t;
 
         t = cpu->isar.id_aa64isar1;
+        t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2);
         t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1);
         t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1);
         t = FIELD_DP64(t, ID_AA64ISAR1, APA, 1); /* PAuth, architected only */
diff --git a/target/arm/helper.c b/target/arm/helper.c
index be67e2c..00c72e4 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -5924,6 +5924,52 @@  static const ARMCPRegInfo rndr_reginfo[] = {
       .access = PL0_R, .readfn = rndr_readfn },
     REGINFO_SENTINEL
 };
+
+#ifndef CONFIG_USER_ONLY
+static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *opaque,
+                          uint64_t value)
+{
+    ARMCPU *cpu = env_archcpu(env);
+    /* CTR_EL0 System register -> DminLine, bits [19:16] */
+    uint64_t dline_size = 4 << ((cpu->ctr >> 16) & 0xF);
+    uint64_t vaddr_in = (uint64_t) value;
+    uint64_t vaddr = vaddr_in & ~(dline_size - 1);
+    void *haddr;
+    int mem_idx = cpu_mmu_index(env, false);
+
+    /* This won't be crossing page boundaries */
+    haddr = probe_read(env, vaddr, dline_size, mem_idx, GETPC());
+    if (haddr) {
+
+        ram_addr_t offset;
+        MemoryRegion *mr;
+
+        /* RCU lock is already being held */
+        mr = memory_region_from_host(haddr, &offset);
+
+        if (mr) {
+            memory_region_do_writeback(mr, offset, dline_size);
+        }
+    }
+}
+
+static const ARMCPRegInfo dcpop_reg[] = {
+    { .name = "DC_CVAP", .state = ARM_CP_STATE_AA64,
+      .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 12, .opc2 = 1,
+      .access = PL0_W, .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END,
+      .accessfn = aa64_cacheop_access, .writefn = dccvap_writefn },
+    REGINFO_SENTINEL
+};
+
+static const ARMCPRegInfo dcpodp_reg[] = {
+    { .name = "DC_CVADP", .state = ARM_CP_STATE_AA64,
+      .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 13, .opc2 = 1,
+      .access = PL0_W, .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END,
+      .accessfn = aa64_cacheop_access, .writefn = dccvap_writefn },
+    REGINFO_SENTINEL
+};
+#endif /*CONFIG_USER_ONLY*/
+
 #endif
 
 static CPAccessResult access_predinv(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -6884,6 +6930,16 @@  void register_cp_regs_for_features(ARMCPU *cpu)
     if (cpu_isar_feature(aa64_rndr, cpu)) {
         define_arm_cp_regs(cpu, rndr_reginfo);
     }
+#ifndef CONFIG_USER_ONLY
+    /* Data Cache clean instructions up to PoP */
+    if (cpu_isar_feature(aa64_dcpop, cpu)) {
+        define_one_arm_cp_reg(cpu, dcpop_reg);
+
+        if (cpu_isar_feature(aa64_dcpodp, cpu)) {
+            define_one_arm_cp_reg(cpu, dcpodp_reg);
+        }
+    }
+#endif /*CONFIG_USER_ONLY*/
 #endif
 
     /*