Message ID | 20180809034033.10579-12-richard.henderson@linaro.org |
---|---|
State | New |
Headers | show |
Series | target/arm: sve linux-user patches | expand |
Richard Henderson <richard.henderson@linaro.org> writes: > This allows the default (and maximum) vector length to be set > from the command-line. Which is extraordinarily helpful in > debuging problems depending on vector length without having to > bake knowledge of PR_SET_SVE_VL into every guest binary. > > Cc: qemu-stable@nongnu.org (3.0.1) > Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Tested-by: Alex Bennée <alex.bennee@linaro.org> > --- > target/arm/cpu.h | 3 +++ > linux-user/syscall.c | 19 +++++++++++++------ > target/arm/cpu.c | 6 +++--- > target/arm/cpu64.c | 29 +++++++++++++++++++++++++++++ > target/arm/helper.c | 7 +++++-- > 5 files changed, 53 insertions(+), 11 deletions(-) > > diff --git a/target/arm/cpu.h b/target/arm/cpu.h > index e310ffc29d..9526ed27cb 100644 > --- a/target/arm/cpu.h > +++ b/target/arm/cpu.h > @@ -857,6 +857,9 @@ struct ARMCPU { > > /* Used to synchronize KVM and QEMU in-kernel device levels */ > uint8_t device_irq_level; > + > + /* Used to set the maximum vector length the cpu will support. */ > + uint32_t sve_max_vq; > }; > > static inline ARMCPU *arm_env_get_cpu(CPUARMState *env) > diff --git a/linux-user/syscall.c b/linux-user/syscall.c > index dfc851cc35..5a4af76c03 100644 > --- a/linux-user/syscall.c > +++ b/linux-user/syscall.c > @@ -10848,15 +10848,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, > #endif > #ifdef TARGET_AARCH64 > case TARGET_PR_SVE_SET_VL: > - /* We cannot support either PR_SVE_SET_VL_ONEXEC > - or PR_SVE_VL_INHERIT. Therefore, anything above > - ARM_MAX_VQ results in EINVAL. */ > + /* > + * We cannot support either PR_SVE_SET_VL_ONEXEC or > + * PR_SVE_VL_INHERIT. Note the kernel definition > + * of sve_vl_valid allows for VQ=512, i.e. VL=8192, > + * even though the current architectural maximum is VQ=16. > + */ > ret = -TARGET_EINVAL; > if (arm_feature(cpu_env, ARM_FEATURE_SVE) > - && arg2 >= 0 && arg2 <= ARM_MAX_VQ * 16 && !(arg2 & 15)) { > + && arg2 >= 0 && arg2 <= 512 * 16 && !(arg2 & 15)) { > CPUARMState *env = cpu_env; > - int old_vq = (env->vfp.zcr_el[1] & 0xf) + 1; > - int vq = MAX(arg2 / 16, 1); > + ARMCPU *cpu = arm_env_get_cpu(env); > + uint32_t vq, old_vq; > + > + old_vq = (env->vfp.zcr_el[1] & 0xf) + 1; > + vq = MAX(arg2 / 16, 1); > + vq = MIN(vq, cpu->sve_max_vq); > > if (vq < old_vq) { > aarch64_sve_narrow_vq(env, vq); > diff --git a/target/arm/cpu.c b/target/arm/cpu.c > index 64a8005a4b..b25898ed4c 100644 > --- a/target/arm/cpu.c > +++ b/target/arm/cpu.c > @@ -168,9 +168,9 @@ static void arm_cpu_reset(CPUState *s) > env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 16, 2, 3); > env->cp15.cptr_el[3] |= CPTR_EZ; > /* with maximum vector length */ > - env->vfp.zcr_el[1] = ARM_MAX_VQ - 1; > - env->vfp.zcr_el[2] = ARM_MAX_VQ - 1; > - env->vfp.zcr_el[3] = ARM_MAX_VQ - 1; > + env->vfp.zcr_el[1] = cpu->sve_max_vq - 1; > + env->vfp.zcr_el[2] = env->vfp.zcr_el[1]; > + env->vfp.zcr_el[3] = env->vfp.zcr_el[1]; > #else > /* Reset into the highest available EL */ > if (arm_feature(env, ARM_FEATURE_EL3)) { > diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c > index d0581d59d8..800bff780e 100644 > --- a/target/arm/cpu64.c > +++ b/target/arm/cpu64.c > @@ -29,6 +29,7 @@ > #include "sysemu/sysemu.h" > #include "sysemu/kvm.h" > #include "kvm_arm.h" > +#include "qapi/visitor.h" > > static inline void set_feature(CPUARMState *env, int feature) > { > @@ -217,6 +218,29 @@ static void aarch64_a53_initfn(Object *obj) > define_arm_cp_regs(cpu, cortex_a57_a53_cp_reginfo); > } > > +static void cpu_max_get_sve_vq(Object *obj, Visitor *v, const char *name, > + void *opaque, Error **errp) > +{ > + ARMCPU *cpu = ARM_CPU(obj); > + visit_type_uint32(v, name, &cpu->sve_max_vq, errp); > +} > + > +static void cpu_max_set_sve_vq(Object *obj, Visitor *v, const char *name, > + void *opaque, Error **errp) > +{ > + ARMCPU *cpu = ARM_CPU(obj); > + Error *err = NULL; > + > + visit_type_uint32(v, name, &cpu->sve_max_vq, &err); > + > + if (!err && (cpu->sve_max_vq == 0 || cpu->sve_max_vq > ARM_MAX_VQ)) { > + error_setg(&err, "unsupported SVE vector length"); > + error_append_hint(&err, "Valid sve-max-vq in range [1-%d]\n", > + ARM_MAX_VQ); > + } > + error_propagate(errp, err); > +} > + > /* -cpu max: if KVM is enabled, like -cpu host (best possible with this host); > * otherwise, a CPU with as many features enabled as our emulation supports. > * The version of '-cpu max' for qemu-system-arm is defined in cpu.c; > @@ -253,6 +277,10 @@ static void aarch64_max_initfn(Object *obj) > cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */ > cpu->dcz_blocksize = 7; /* 512 bytes */ > #endif > + > + cpu->sve_max_vq = ARM_MAX_VQ; > + object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_vq, > + cpu_max_set_sve_vq, NULL, NULL, &error_fatal); > } > } > > @@ -405,6 +433,7 @@ void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq) > uint64_t pmask; > > assert(vq >= 1 && vq <= ARM_MAX_VQ); > + assert(vq <= arm_env_get_cpu(env)->sve_max_vq); > > /* Zap the high bits of the zregs. */ > for (i = 0; i < 32; i++) { > diff --git a/target/arm/helper.c b/target/arm/helper.c > index 66afb08ee0..c24c66d43e 100644 > --- a/target/arm/helper.c > +++ b/target/arm/helper.c > @@ -12408,9 +12408,12 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, > zcr_len = 0; > } else { > int current_el = arm_current_el(env); > + ARMCPU *cpu = arm_env_get_cpu(env); > > - zcr_len = env->vfp.zcr_el[current_el <= 1 ? 1 : current_el]; > - zcr_len &= 0xf; > + zcr_len = cpu->sve_max_vq - 1; > + if (current_el <= 1) { > + zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[1]); > + } > if (current_el < 2 && arm_feature(env, ARM_FEATURE_EL2)) { > zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[2]); > } -- Alex Bennée
diff --git a/target/arm/cpu.h b/target/arm/cpu.h index e310ffc29d..9526ed27cb 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -857,6 +857,9 @@ struct ARMCPU { /* Used to synchronize KVM and QEMU in-kernel device levels */ uint8_t device_irq_level; + + /* Used to set the maximum vector length the cpu will support. */ + uint32_t sve_max_vq; }; static inline ARMCPU *arm_env_get_cpu(CPUARMState *env) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index dfc851cc35..5a4af76c03 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -10848,15 +10848,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_AARCH64 case TARGET_PR_SVE_SET_VL: - /* We cannot support either PR_SVE_SET_VL_ONEXEC - or PR_SVE_VL_INHERIT. Therefore, anything above - ARM_MAX_VQ results in EINVAL. */ + /* + * We cannot support either PR_SVE_SET_VL_ONEXEC or + * PR_SVE_VL_INHERIT. Note the kernel definition + * of sve_vl_valid allows for VQ=512, i.e. VL=8192, + * even though the current architectural maximum is VQ=16. + */ ret = -TARGET_EINVAL; if (arm_feature(cpu_env, ARM_FEATURE_SVE) - && arg2 >= 0 && arg2 <= ARM_MAX_VQ * 16 && !(arg2 & 15)) { + && arg2 >= 0 && arg2 <= 512 * 16 && !(arg2 & 15)) { CPUARMState *env = cpu_env; - int old_vq = (env->vfp.zcr_el[1] & 0xf) + 1; - int vq = MAX(arg2 / 16, 1); + ARMCPU *cpu = arm_env_get_cpu(env); + uint32_t vq, old_vq; + + old_vq = (env->vfp.zcr_el[1] & 0xf) + 1; + vq = MAX(arg2 / 16, 1); + vq = MIN(vq, cpu->sve_max_vq); if (vq < old_vq) { aarch64_sve_narrow_vq(env, vq); diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 64a8005a4b..b25898ed4c 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -168,9 +168,9 @@ static void arm_cpu_reset(CPUState *s) env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 16, 2, 3); env->cp15.cptr_el[3] |= CPTR_EZ; /* with maximum vector length */ - env->vfp.zcr_el[1] = ARM_MAX_VQ - 1; - env->vfp.zcr_el[2] = ARM_MAX_VQ - 1; - env->vfp.zcr_el[3] = ARM_MAX_VQ - 1; + env->vfp.zcr_el[1] = cpu->sve_max_vq - 1; + env->vfp.zcr_el[2] = env->vfp.zcr_el[1]; + env->vfp.zcr_el[3] = env->vfp.zcr_el[1]; #else /* Reset into the highest available EL */ if (arm_feature(env, ARM_FEATURE_EL3)) { diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index d0581d59d8..800bff780e 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -29,6 +29,7 @@ #include "sysemu/sysemu.h" #include "sysemu/kvm.h" #include "kvm_arm.h" +#include "qapi/visitor.h" static inline void set_feature(CPUARMState *env, int feature) { @@ -217,6 +218,29 @@ static void aarch64_a53_initfn(Object *obj) define_arm_cp_regs(cpu, cortex_a57_a53_cp_reginfo); } +static void cpu_max_get_sve_vq(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + visit_type_uint32(v, name, &cpu->sve_max_vq, errp); +} + +static void cpu_max_set_sve_vq(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + Error *err = NULL; + + visit_type_uint32(v, name, &cpu->sve_max_vq, &err); + + if (!err && (cpu->sve_max_vq == 0 || cpu->sve_max_vq > ARM_MAX_VQ)) { + error_setg(&err, "unsupported SVE vector length"); + error_append_hint(&err, "Valid sve-max-vq in range [1-%d]\n", + ARM_MAX_VQ); + } + error_propagate(errp, err); +} + /* -cpu max: if KVM is enabled, like -cpu host (best possible with this host); * otherwise, a CPU with as many features enabled as our emulation supports. * The version of '-cpu max' for qemu-system-arm is defined in cpu.c; @@ -253,6 +277,10 @@ static void aarch64_max_initfn(Object *obj) cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */ cpu->dcz_blocksize = 7; /* 512 bytes */ #endif + + cpu->sve_max_vq = ARM_MAX_VQ; + object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_vq, + cpu_max_set_sve_vq, NULL, NULL, &error_fatal); } } @@ -405,6 +433,7 @@ void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq) uint64_t pmask; assert(vq >= 1 && vq <= ARM_MAX_VQ); + assert(vq <= arm_env_get_cpu(env)->sve_max_vq); /* Zap the high bits of the zregs. */ for (i = 0; i < 32; i++) { diff --git a/target/arm/helper.c b/target/arm/helper.c index 66afb08ee0..c24c66d43e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -12408,9 +12408,12 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, zcr_len = 0; } else { int current_el = arm_current_el(env); + ARMCPU *cpu = arm_env_get_cpu(env); - zcr_len = env->vfp.zcr_el[current_el <= 1 ? 1 : current_el]; - zcr_len &= 0xf; + zcr_len = cpu->sve_max_vq - 1; + if (current_el <= 1) { + zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[1]); + } if (current_el < 2 && arm_feature(env, ARM_FEATURE_EL2)) { zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[2]); }
This allows the default (and maximum) vector length to be set from the command-line. Which is extraordinarily helpful in debuging problems depending on vector length without having to bake knowledge of PR_SET_SVE_VL into every guest binary. Cc: qemu-stable@nongnu.org (3.0.1) Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/arm/cpu.h | 3 +++ linux-user/syscall.c | 19 +++++++++++++------ target/arm/cpu.c | 6 +++--- target/arm/cpu64.c | 29 +++++++++++++++++++++++++++++ target/arm/helper.c | 7 +++++-- 5 files changed, 53 insertions(+), 11 deletions(-) -- 2.17.1