[PULL 5/6] target/sparc: set reg window data structures currently after vmstate load
Philippe Mathieu-Daudé <[email protected]>
| Newsgroups | gmane.comp.emulators.qemu |
|---|---|
| Message-ID | <[email protected]> |
From: Mark Cave-Ayland <[email protected]> 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: [email protected] Signed-off-by: Mark Cave-Ayland <[email protected]> Reviewed-by: Peter Maydell <[email protected]> Reviewed-by: Philippe Mathieu-Daudé <[email protected]> Message-ID: <[email protected]> Signed-off-by: Philippe Mathieu-Daudé <[email protected]> --- target/sparc/machine.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/target/sparc/machine.c b/target/sparc/machine.c index 5f402e098cf..0d5d79b5e7b 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() }, -- 2.53.0