diff mbox series

[v3,02/15] linux-user/aarch64: Use SVE_LEN from hflags

Message ID 20220527180623.185261-3-richard.henderson@linaro.org (mailing list archive)
State New, archived
Headers show
Series target/arm: SME prep patches | expand

Commit Message

Richard Henderson May 27, 2022, 6:06 p.m. UTC
Use the digested vector length rather than the raw zcr_el[1] value.

This fixes an incorrect return from do_prctl_set_vl where we didn't
take into account the set of vector lengths supported by the cpu.
It also prepares us for Streaming SVE mode, where the vector length
comes from a different cpreg.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/aarch64/target_prctl.h | 19 +++++++++++++------
 linux-user/aarch64/signal.c       |  4 ++--
 2 files changed, 15 insertions(+), 8 deletions(-)

Comments

Peter Maydell May 31, 2022, 12:15 p.m. UTC | #1
On Fri, 27 May 2022 at 19:07, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Use the digested vector length rather than the raw zcr_el[1] value.
>
> This fixes an incorrect return from do_prctl_set_vl where we didn't
> take into account the set of vector lengths supported by the cpu.
> It also prepares us for Streaming SVE mode, where the vector length
> comes from a different cpreg.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---

> diff --git a/linux-user/aarch64/target_prctl.h b/linux-user/aarch64/target_prctl.h
> index 3f5a5d3933..fcbb90e881 100644
> --- a/linux-user/aarch64/target_prctl.h
> +++ b/linux-user/aarch64/target_prctl.h
> @@ -10,7 +10,7 @@ static abi_long do_prctl_get_vl(CPUArchState *env)
>  {
>      ARMCPU *cpu = env_archcpu(env);
>      if (cpu_isar_feature(aa64_sve, cpu)) {
> -        return ((cpu->env.vfp.zcr_el[1] & 0xf) + 1) * 16;
> +        return (EX_TBFLAG_A64(env->hflags, SVE_LEN) + 1) * 16;

I think env->hflags should be a private implementation detail
to target/arm and it's a bit odd to see linux-user fishing
around in it directly. Can we hide this behind a suitably
named function, please ?

thanks
-- PMM
diff mbox series

Patch

diff --git a/linux-user/aarch64/target_prctl.h b/linux-user/aarch64/target_prctl.h
index 3f5a5d3933..fcbb90e881 100644
--- a/linux-user/aarch64/target_prctl.h
+++ b/linux-user/aarch64/target_prctl.h
@@ -10,7 +10,7 @@  static abi_long do_prctl_get_vl(CPUArchState *env)
 {
     ARMCPU *cpu = env_archcpu(env);
     if (cpu_isar_feature(aa64_sve, cpu)) {
-        return ((cpu->env.vfp.zcr_el[1] & 0xf) + 1) * 16;
+        return (EX_TBFLAG_A64(env->hflags, SVE_LEN) + 1) * 16;
     }
     return -TARGET_EINVAL;
 }
@@ -25,18 +25,25 @@  static abi_long do_prctl_set_vl(CPUArchState *env, abi_long arg2)
      */
     if (cpu_isar_feature(aa64_sve, env_archcpu(env))
         && arg2 >= 0 && arg2 <= 512 * 16 && !(arg2 & 15)) {
-        ARMCPU *cpu = env_archcpu(env);
         uint32_t vq, old_vq;
 
-        old_vq = (env->vfp.zcr_el[1] & 0xf) + 1;
+        old_vq = EX_TBFLAG_A64(env->hflags, SVE_LEN) + 1;
+
+        /*
+         * Bound the value of vq, so that we know that it fits into
+         * the 4-bit field in ZCR_EL1.  Rely on the hflags rebuild
+         * to sort out the length supported by the cpu.
+         */
         vq = MAX(arg2 / 16, 1);
-        vq = MIN(vq, cpu->sve_max_vq);
+        vq = MIN(vq, 16);
+        env->vfp.zcr_el[1] = vq - 1;
+        arm_rebuild_hflags(env);
+
+        vq = EX_TBFLAG_A64(env->hflags, SVE_LEN) + 1;
 
         if (vq < old_vq) {
             aarch64_sve_narrow_vq(env, vq);
         }
-        env->vfp.zcr_el[1] = vq - 1;
-        arm_rebuild_hflags(env);
         return vq * 16;
     }
     return -TARGET_EINVAL;
diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c
index 7de4c96eb9..57e9360743 100644
--- a/linux-user/aarch64/signal.c
+++ b/linux-user/aarch64/signal.c
@@ -315,7 +315,7 @@  static int target_restore_sigframe(CPUARMState *env,
 
         case TARGET_SVE_MAGIC:
             if (cpu_isar_feature(aa64_sve, env_archcpu(env))) {
-                vq = (env->vfp.zcr_el[1] & 0xf) + 1;
+                vq = EX_TBFLAG_A64(env->hflags, SVE_LEN) + 1;
                 sve_size = QEMU_ALIGN_UP(TARGET_SVE_SIG_CONTEXT_SIZE(vq), 16);
                 if (!sve && size == sve_size) {
                     sve = (struct target_sve_context *)ctx;
@@ -434,7 +434,7 @@  static void target_setup_frame(int usig, struct target_sigaction *ka,
 
     /* SVE state needs saving only if it exists.  */
     if (cpu_isar_feature(aa64_sve, env_archcpu(env))) {
-        vq = (env->vfp.zcr_el[1] & 0xf) + 1;
+        vq = EX_TBFLAG_A64(env->hflags, SVE_LEN) + 1;
         sve_size = QEMU_ALIGN_UP(TARGET_SVE_SIG_CONTEXT_SIZE(vq), 16);
         sve_ofs = alloc_sigframe_space(sve_size, &layout);
     }