Commit d8813fdc4b for qemu.org

commit d8813fdc4bdf3038cc55d03dab2d9dbbeb340226
Author: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Date:   Sat Jul 25 13:33:22 2026 +0100

    target/sparc: set reg window data structures currently after vmstate load

    In the SPARC CPU state, env->regwptr points into the env->regbase
    array at wherever the architectural CWP (current window pointer) says
    we are in the register windows.  We don't migrate this directly,
    since it's a host pointer, so we must ensure it is set up again
    after migration load.

    We also have to deal with a special case when CWP is (nwindows - 1).
    In this case, while running we keep the "in" register data for this
    window in a temporary location at the end of the regbase[] array, so
    that generated code doesn't have to special case this "wrap around"
    case.  In cpu_pre_save() we call cpu_set_cwp() to force a copy of the
    wrapped data from its temporary location into the architectural
    location in window 0's "out" registers.  We then migrate only
    (nwindows * 16) entries in the regbase[] array.  So on the
    destination we need to copy the "in" register data back to its
    temporary location again.

    For 32-bit SPARC we get this right, because the CWP is in the PSR.
    The get_psr() function does:
         env->cwp = 0;
         cpu_put_psr_raw(env, val);
    which causes cpu_put_psr_raw() to call cpu_set_cwp() in a way that
    sets up both regwptr and the wrapped-register data.

    However, for 64-bit SPARC the CWP is not in the PSR, and
    cpu_put_psr_raw() will not call cpu_set_cwp().  This leaves the guest
    register state in a corrupted state, and the guest will likely crash
    on the destination if it didn't happen to be executing with CWP == 0.

    Fix this by adding a custom vmstate_cwp VMStateInfo with corresponding
    get_cwp() and put_cwp() helpers which does the same for the 64-bit
    case.

    Cc: qemu-stable@nongnu.org
    Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
    Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
    Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
    Message-ID: <20260725123411.993099-1-mark.cave-ayland@ilande.co.uk>
    Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>

diff --git a/target/sparc/machine.c b/target/sparc/machine.c
index 5f402e098c..0d5d79b5e7 100644
--- a/target/sparc/machine.c
+++ b/target/sparc/machine.c
@@ -151,6 +151,37 @@ static const VMStateInfo vmstate_xcc = {
     .get = get_xcc,
     .put = put_xcc,
 };
+
+static int get_cwp(QEMUFile *f, void *opaque, size_t size,
+                   const VMStateField *field)
+{
+    SPARCCPU *cpu = opaque;
+    CPUSPARCState *env = &cpu->env;
+    uint32_t val = qemu_get_be32(f);
+
+    /* needed to ensure that the wrapping registers are correctly updated */
+    env->cwp = 0;
+    cpu_set_cwp(env, val);
+
+    return 0;
+}
+
+static int put_cwp(QEMUFile *f, void *opaque, size_t size,
+                   const VMStateField *field, JSONWriter *vmdesc)
+{
+    SPARCCPU *cpu = opaque;
+    CPUSPARCState *env = &cpu->env;
+    uint32_t val = env->cwp;
+
+    qemu_put_be32(f, val);
+    return 0;
+}
+
+static const VMStateInfo vmstate_cwp = {
+    .name = "uint32",
+    .get = get_cwp,
+    .put = put_cwp,
+};
 #else
 static bool fq_needed(void *opaque)
 {
@@ -286,7 +317,14 @@ const VMStateDescription vmstate_sparc_cpu = {
         VMSTATE_CPU_TIMER(env.hstick, SPARCCPU),
         /* On SPARC32 env.psrpil and env.cwp are migrated as part of the PSR */
         VMSTATE_UINT32(env.psrpil, SPARCCPU),
-        VMSTATE_UINT32(env.cwp, SPARCCPU),
+        {
+            .name = "env.cwp",
+            .version_id = 0,
+            .size = sizeof(uint32_t),
+            .info = &vmstate_cwp,
+            .flags = VMS_SINGLE,
+            .offset = 0,
+        },
 #endif
         VMSTATE_END_OF_LIST()
     },