diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2023-10-30 17:40:00 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2023-11-02 13:36:45 +0000 |
commit | 854c001f121578c96b023b5db0c5550250505a0e (patch) | |
tree | 462b14b36d0b5d715b1569a312e3886e949adc9f | |
parent | 63c1b7de0a66e4ff248bdb51a0c3914de4eff034 (diff) |
target/arm: Make FEAT_MOPS SET* insns handle Xs == XZR correctly
Most of the registers used by the FEAT_MOPS instructions cannot use
31 as a register field value; this is CONSTRAINED UNPREDICTABLE to
NOP or UNDEF (we UNDEF). However, it is permitted for the "source
value" register for the memset insns SET* to be 31, which (as usual
for most data-processing insns) means it should be the zero register
XZR. We forgot to handle this case, with the effect that trying to
set memory to zero with a "SET* Xd, Xn, XZR" sets the memory to
the value that happens to be in the low byte of SP.
Handle XZR when getting the SET* data value from the register file.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-id: 20231030174000.3792225-4-peter.maydell@linaro.org
-rw-r--r-- | target/arm/tcg/helper-a64.c | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index 84f54750fc..ce4800b8d1 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -1206,6 +1206,15 @@ static void check_setg_alignment(CPUARMState *env, uint64_t ptr, uint64_t size, } } +static uint64_t arm_reg_or_xzr(CPUARMState *env, int reg) +{ + /* + * Runtime equivalent of cpu_reg() -- return the CPU register value, + * for contexts when index 31 means XZR (not SP). + */ + return reg == 31 ? 0 : env->xregs[reg]; +} + /* * For the Memory Set operation, our implementation chooses * always to use "option A", where we update Xd to the final @@ -1226,7 +1235,7 @@ static void do_setp(CPUARMState *env, uint32_t syndrome, uint32_t mtedesc, int rd = mops_destreg(syndrome); int rs = mops_srcreg(syndrome); int rn = mops_sizereg(syndrome); - uint8_t data = env->xregs[rs]; + uint8_t data = arm_reg_or_xzr(env, rs); uint32_t memidx = FIELD_EX32(mtedesc, MTEDESC, MIDX); uint64_t toaddr = env->xregs[rd]; uint64_t setsize = env->xregs[rn]; @@ -1286,7 +1295,7 @@ static void do_setm(CPUARMState *env, uint32_t syndrome, uint32_t mtedesc, int rd = mops_destreg(syndrome); int rs = mops_srcreg(syndrome); int rn = mops_sizereg(syndrome); - uint8_t data = env->xregs[rs]; + uint8_t data = arm_reg_or_xzr(env, rs); uint64_t toaddr = env->xregs[rd] + env->xregs[rn]; uint64_t setsize = -env->xregs[rn]; uint32_t memidx = FIELD_EX32(mtedesc, MTEDESC, MIDX); @@ -1349,7 +1358,7 @@ static void do_sete(CPUARMState *env, uint32_t syndrome, uint32_t mtedesc, int rd = mops_destreg(syndrome); int rs = mops_srcreg(syndrome); int rn = mops_sizereg(syndrome); - uint8_t data = env->xregs[rs]; + uint8_t data = arm_reg_or_xzr(env, rs); uint64_t toaddr = env->xregs[rd] + env->xregs[rn]; uint64_t setsize = -env->xregs[rn]; uint32_t memidx = FIELD_EX32(mtedesc, MTEDESC, MIDX); |