Hi,

Gentle ping on this patch from August 26. Could you please take a look when
you have time?

Patch archive
<https://www.mail-archive.com/[email protected]/msg1220122.html>

I'm happy to address any feedback.

Thanks


ср, 26 авг. 2026 г. в 20:16, Artemii Mashanov <[email protected]>:

> TCG's do_xsave_fpu() omitted writing the FOP field and the reserved
> bytes (10..15) of each x87 register slot. Those parts of
> the destination buffer retained their previous contents.
>
> The reserved bytes of all eight slots are zeroed. TCG does not
> yet track the actual FOP value, this patch stores a fixed zero instead.
>
> Add a regression test in tests/tcg/x86_64/fxsave.c. It fills the
> FXSAVE area with 0xcc, executes FNINIT and FXSAVE64, then verifies that
> FOP and all reserved slot bytes are zero.
>
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3522
>
> Signed-off-by: Artemii Mashanov <[email protected]>
> ---
>  target/i386/tcg/fpu_helper.c     |  3 ++
>  tests/tcg/x86_64/Makefile.target |  1 +
>  tests/tcg/x86_64/fxsave.c        | 66 ++++++++++++++++++++++++++++++++
>  3 files changed, 70 insertions(+)
>  create mode 100644 tests/tcg/x86_64/fxsave.c
>
> diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
> index b812125efa..9a2be488ef 100644
> --- a/target/i386/tcg/fpu_helper.c
> +++ b/target/i386/tcg/fpu_helper.c
> @@ -2601,6 +2601,7 @@ static void do_xsave_fpu(X86Access *ac, target_ulong
> ptr)
>      access_stw(ac, ptr + XO(legacy.fcw), env->fpuc);
>      access_stw(ac, ptr + XO(legacy.fsw), fpus);
>      access_stw(ac, ptr + XO(legacy.ftw), fptag ^ 0xff);
> +    access_stw(ac, ptr + XO(legacy.fpop), 0);
>
>      /* In 32-bit mode this is eip, sel, dp, sel.
>         In 64-bit mode this is rip, rdp.
> @@ -2613,6 +2614,8 @@ static void do_xsave_fpu(X86Access *ac, target_ulong
> ptr)
>      for (i = 0; i < 8; i++) {
>          floatx80 tmp = ST(i);
>          do_fstt(ac, addr, tmp);
> +        access_stw(ac, addr + 10, 0);
> +        access_stl(ac, addr + 12, 0);
>          addr += 16;
>      }
>  }
> diff --git a/tests/tcg/x86_64/Makefile.target
> b/tests/tcg/x86_64/Makefile.target
> index c48767fef8..0f8f48b1a5 100644
> --- a/tests/tcg/x86_64/Makefile.target
> +++ b/tests/tcg/x86_64/Makefile.target
> @@ -20,6 +20,7 @@ X86_64_TESTS += test-1648
>  X86_64_TESTS += test-2175
>  X86_64_TESTS += cross-modifying-code
>  X86_64_TESTS += fma
> +X86_64_TESTS += fxsave
>  TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64
>  else
>  TESTS=$(MULTIARCH_TESTS)
> diff --git a/tests/tcg/x86_64/fxsave.c b/tests/tcg/x86_64/fxsave.c
> new file mode 100644
> index 0000000000..d08a4e8a0e
> --- /dev/null
> +++ b/tests/tcg/x86_64/fxsave.c
> @@ -0,0 +1,66 @@
> +/*
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + * See https://gitlab.com/qemu-project/qemu/-/issues/3522
> + */
> +
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <string.h>
> +
> +#define FXSAVE_FOP_OFFSET      6
> +#define FXSAVE_X87_OFFSET      32
> +#define FXSAVE_SLOT_SIZE       16
> +#define FXSAVE_RESERVED_START  10
> +#define FXSAVE_NUM_SLOTS       8
> +
> +struct fxsave_area {
> +    uint8_t raw[512];
> +} __attribute__((aligned(16)));
> +
> +_Static_assert(sizeof(struct fxsave_area) == 512,
> +                "FXSAVE area must be exactly 512 bytes");
> +
> +static uint16_t u16_le(const uint8_t *p)
> +{
> +    uint16_t v;
> +    memcpy(&v, p, sizeof(v));
> +    return v;
> +}
> +
> +int main(void)
> +{
> +    struct fxsave_area area;
> +    uint16_t fop;
> +
> +    memset(&area, 0xcc, sizeof(area));
> +
> +    __asm__ volatile(
> +        "fninit\n\t"
> +        "fxsave64 %0"
> +        : "+m" (area)
> +        :
> +        : "memory"
> +    );
> +
> +    fop = u16_le(&area.raw[FXSAVE_FOP_OFFSET]);
> +    if (fop != 0) {
> +        fprintf(stderr, "FOP: expected 0, got 0x%04x\n", (unsigned)fop);
> +        return 1;
> +    }
> +
> +    for (int slot = 0; slot < FXSAVE_NUM_SLOTS; slot++) {
> +        int base = FXSAVE_X87_OFFSET + slot * FXSAVE_SLOT_SIZE;
> +        for (int b = FXSAVE_RESERVED_START; b < FXSAVE_SLOT_SIZE; b++) {
> +            uint8_t val = area.raw[base + b];
> +            if (val != 0) {
> +                fprintf(stderr,
> +                        "Slot %d byte %d (offset %d): expected 0x00, "
> +                        "got 0x%02x\n",
> +                        slot, b, base + b, (unsigned)val);
> +                return 1;
> +            }
> +        }
> +    }
> +
> +    return 0;
> +}
> --
> 2.54.0
>
>

Reply via email to