2016-01-26 21:16:58 +03:00
|
|
|
#include "qemu/osdep.h"
|
2016-03-15 18:58:45 +03:00
|
|
|
#include "cpu.h"
|
2016-03-15 15:18:37 +03:00
|
|
|
#include "exec/exec-all.h"
|
2012-12-17 21:20:04 +04:00
|
|
|
#include "sysemu/kvm.h"
|
2022-03-02 08:51:36 +03:00
|
|
|
#include "sysemu/tcg.h"
|
2013-07-18 23:32:54 +04:00
|
|
|
#include "helper_regs.h"
|
2016-01-27 03:52:57 +03:00
|
|
|
#include "mmu-hash64.h"
|
2016-03-15 14:51:18 +03:00
|
|
|
#include "migration/cpu.h"
|
ppc: Rework CPU compatibility testing across migration
Migrating between different CPU versions is a bit complicated for ppc.
A long time ago, we ensured identical CPU versions at either end by
checking the PVR had the same value. However, this breaks under KVM
HV, because we always have to use the host's PVR - it's not
virtualized. That would mean we couldn't migrate between hosts with
different PVRs, even if the CPUs are close enough to compatible in
practice (sometimes identical cores with different surrounding logic
have different PVRs, so this happens in practice quite often).
So, we removed the PVR check, but instead checked that several flags
indicating supported instructions matched. This turns out to be a bad
idea, because those instruction masks are not architected information, but
essentially a TCG implementation detail. So changes to qemu internal CPU
modelling can break migration - this happened between qemu-2.6 and
qemu-2.7. That was addressed by 146c11f1 "target-ppc: Allow eventual
removal of old migration mistakes".
Now, verification of CPU compatibility across a migration basically doesn't
happen. We simply ignore the PVR of the incoming migration, and hope the
cpu on the destination is close enough to work.
Now that we've cleaned up handling of processor compatibility modes
for pseries machine type, we can do better. For new machine types
(pseries-2.10+) We allow migration if:
* The source and destination PVRs are for the same type of CPU, as
determined by CPU class's pvr_match function
OR * When the source was in a compatibility mode, and the destination CPU
supports the same compatibility mode
For older machine types we retain the existing behaviour - current CAS
code will usually set a compat mode which would break backwards
migration if we made them use the new behaviour. [Fixed from an
earlier version by Greg Kurz].
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Tested-by: Andrea Bolognani <abologna@redhat.com>
2017-06-02 05:26:11 +03:00
|
|
|
#include "qapi/error.h"
|
2017-08-09 23:43:46 +03:00
|
|
|
#include "kvm_ppc.h"
|
2022-01-04 09:55:34 +03:00
|
|
|
#include "power8-pmu.h"
|
2023-08-08 07:19:55 +03:00
|
|
|
#include "sysemu/replay.h"
|
2008-05-04 17:11:44 +04:00
|
|
|
|
2021-03-23 21:43:31 +03:00
|
|
|
static void post_load_update_msr(CPUPPCState *env)
|
|
|
|
{
|
|
|
|
target_ulong msr = env->msr;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Invalidate all supported msr bits except MSR_TGPR/MSR_HVB
|
2021-03-23 21:43:38 +03:00
|
|
|
* before restoring. Note that this recomputes hflags.
|
2021-03-23 21:43:31 +03:00
|
|
|
*/
|
|
|
|
env->msr ^= env->msr_mask & ~((1ULL << MSR_TGPR) | MSR_HVB);
|
|
|
|
ppc_store_msr(env, msr);
|
|
|
|
}
|
|
|
|
|
2018-11-14 16:29:30 +03:00
|
|
|
static int get_avr(QEMUFile *f, void *pv, size_t size,
|
|
|
|
const VMStateField *field)
|
2013-07-18 23:32:54 +04:00
|
|
|
{
|
|
|
|
ppc_avr_t *v = pv;
|
|
|
|
|
|
|
|
v->u64[0] = qemu_get_be64(f);
|
|
|
|
v->u64[1] = qemu_get_be64(f);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-14 16:29:30 +03:00
|
|
|
static int put_avr(QEMUFile *f, void *pv, size_t size,
|
2020-12-11 20:11:48 +03:00
|
|
|
const VMStateField *field, JSONWriter *vmdesc)
|
2013-07-18 23:32:54 +04:00
|
|
|
{
|
|
|
|
ppc_avr_t *v = pv;
|
|
|
|
|
|
|
|
qemu_put_be64(f, v->u64[0]);
|
|
|
|
qemu_put_be64(f, v->u64[1]);
|
2017-01-19 22:00:50 +03:00
|
|
|
return 0;
|
2013-07-18 23:32:54 +04:00
|
|
|
}
|
|
|
|
|
2014-03-16 17:49:54 +04:00
|
|
|
static const VMStateInfo vmstate_info_avr = {
|
2013-07-18 23:32:54 +04:00
|
|
|
.name = "avr",
|
|
|
|
.get = get_avr,
|
|
|
|
.put = put_avr,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define VMSTATE_AVR_ARRAY_V(_f, _s, _n, _v) \
|
2019-01-02 12:14:22 +03:00
|
|
|
VMSTATE_SUB_ARRAY(_f, _s, 32, _n, _v, vmstate_info_avr, ppc_avr_t)
|
2013-07-18 23:32:54 +04:00
|
|
|
|
|
|
|
#define VMSTATE_AVR_ARRAY(_f, _s, _n) \
|
|
|
|
VMSTATE_AVR_ARRAY_V(_f, _s, _n, 0)
|
|
|
|
|
2019-01-02 12:14:22 +03:00
|
|
|
static int get_fpr(QEMUFile *f, void *pv, size_t size,
|
|
|
|
const VMStateField *field)
|
|
|
|
{
|
|
|
|
ppc_vsr_t *v = pv;
|
|
|
|
|
2019-03-07 21:05:19 +03:00
|
|
|
v->VsrD(0) = qemu_get_be64(f);
|
2019-01-02 12:14:22 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int put_fpr(QEMUFile *f, void *pv, size_t size,
|
2020-12-11 20:11:48 +03:00
|
|
|
const VMStateField *field, JSONWriter *vmdesc)
|
2019-01-02 12:14:22 +03:00
|
|
|
{
|
|
|
|
ppc_vsr_t *v = pv;
|
|
|
|
|
2019-03-07 21:05:19 +03:00
|
|
|
qemu_put_be64(f, v->VsrD(0));
|
2019-01-02 12:14:22 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const VMStateInfo vmstate_info_fpr = {
|
|
|
|
.name = "fpr",
|
|
|
|
.get = get_fpr,
|
|
|
|
.put = put_fpr,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define VMSTATE_FPR_ARRAY_V(_f, _s, _n, _v) \
|
|
|
|
VMSTATE_SUB_ARRAY(_f, _s, 0, _n, _v, vmstate_info_fpr, ppc_vsr_t)
|
|
|
|
|
|
|
|
#define VMSTATE_FPR_ARRAY(_f, _s, _n) \
|
|
|
|
VMSTATE_FPR_ARRAY_V(_f, _s, _n, 0)
|
|
|
|
|
|
|
|
static int get_vsr(QEMUFile *f, void *pv, size_t size,
|
|
|
|
const VMStateField *field)
|
|
|
|
{
|
|
|
|
ppc_vsr_t *v = pv;
|
|
|
|
|
2019-03-07 21:05:19 +03:00
|
|
|
v->VsrD(1) = qemu_get_be64(f);
|
2019-01-02 12:14:22 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int put_vsr(QEMUFile *f, void *pv, size_t size,
|
2020-12-11 20:11:48 +03:00
|
|
|
const VMStateField *field, JSONWriter *vmdesc)
|
2019-01-02 12:14:22 +03:00
|
|
|
{
|
|
|
|
ppc_vsr_t *v = pv;
|
|
|
|
|
2019-03-07 21:05:19 +03:00
|
|
|
qemu_put_be64(f, v->VsrD(1));
|
2019-01-02 12:14:22 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const VMStateInfo vmstate_info_vsr = {
|
|
|
|
.name = "vsr",
|
|
|
|
.get = get_vsr,
|
|
|
|
.put = put_vsr,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define VMSTATE_VSR_ARRAY_V(_f, _s, _n, _v) \
|
|
|
|
VMSTATE_SUB_ARRAY(_f, _s, 0, _n, _v, vmstate_info_vsr, ppc_vsr_t)
|
|
|
|
|
|
|
|
#define VMSTATE_VSR_ARRAY(_f, _s, _n) \
|
|
|
|
VMSTATE_VSR_ARRAY_V(_f, _s, _n, 0)
|
|
|
|
|
2017-09-25 14:29:12 +03:00
|
|
|
static int cpu_pre_save(void *opaque)
|
2013-07-18 23:32:54 +04:00
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = opaque;
|
|
|
|
CPUPPCState *env = &cpu->env;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
env->spr[SPR_LR] = env->lr;
|
|
|
|
env->spr[SPR_CTR] = env->ctr;
|
2016-04-15 12:03:00 +03:00
|
|
|
env->spr[SPR_XER] = cpu_read_xer(env);
|
2013-07-18 23:32:54 +04:00
|
|
|
#if defined(TARGET_PPC64)
|
|
|
|
env->spr[SPR_CFAR] = env->cfar;
|
|
|
|
#endif
|
|
|
|
env->spr[SPR_BOOKE_SPEFSCR] = env->spe_fscr;
|
|
|
|
|
|
|
|
for (i = 0; (i < 4) && (i < env->nb_BATs); i++) {
|
2019-03-21 14:10:19 +03:00
|
|
|
env->spr[SPR_DBAT0U + 2 * i] = env->DBAT[0][i];
|
|
|
|
env->spr[SPR_DBAT0U + 2 * i + 1] = env->DBAT[1][i];
|
|
|
|
env->spr[SPR_IBAT0U + 2 * i] = env->IBAT[0][i];
|
|
|
|
env->spr[SPR_IBAT0U + 2 * i + 1] = env->IBAT[1][i];
|
2013-07-18 23:32:54 +04:00
|
|
|
}
|
2019-03-21 14:10:19 +03:00
|
|
|
for (i = 0; (i < 4) && ((i + 4) < env->nb_BATs); i++) {
|
|
|
|
env->spr[SPR_DBAT4U + 2 * i] = env->DBAT[0][i + 4];
|
|
|
|
env->spr[SPR_DBAT4U + 2 * i + 1] = env->DBAT[1][i + 4];
|
|
|
|
env->spr[SPR_IBAT4U + 2 * i] = env->IBAT[0][i + 4];
|
|
|
|
env->spr[SPR_IBAT4U + 2 * i + 1] = env->IBAT[1][i + 4];
|
2013-07-18 23:32:54 +04:00
|
|
|
}
|
2016-11-21 08:28:12 +03:00
|
|
|
|
2022-02-09 11:08:55 +03:00
|
|
|
/* Used to retain migration compatibility for pre 6.0 for 601 machines. */
|
|
|
|
env->hflags_compat_nmsr = 0;
|
2021-03-15 21:46:03 +03:00
|
|
|
|
2023-08-08 07:19:52 +03:00
|
|
|
if (tcg_enabled()) {
|
|
|
|
/*
|
|
|
|
* TCG does not maintain the DECR spr (unlike KVM) so have to save
|
|
|
|
* it here.
|
|
|
|
*/
|
|
|
|
env->spr[SPR_DECR] = cpu_ppc_load_decr(env);
|
|
|
|
}
|
|
|
|
|
2017-09-25 14:29:12 +03:00
|
|
|
return 0;
|
2013-07-18 23:32:54 +04:00
|
|
|
}
|
|
|
|
|
ppc: Rework CPU compatibility testing across migration
Migrating between different CPU versions is a bit complicated for ppc.
A long time ago, we ensured identical CPU versions at either end by
checking the PVR had the same value. However, this breaks under KVM
HV, because we always have to use the host's PVR - it's not
virtualized. That would mean we couldn't migrate between hosts with
different PVRs, even if the CPUs are close enough to compatible in
practice (sometimes identical cores with different surrounding logic
have different PVRs, so this happens in practice quite often).
So, we removed the PVR check, but instead checked that several flags
indicating supported instructions matched. This turns out to be a bad
idea, because those instruction masks are not architected information, but
essentially a TCG implementation detail. So changes to qemu internal CPU
modelling can break migration - this happened between qemu-2.6 and
qemu-2.7. That was addressed by 146c11f1 "target-ppc: Allow eventual
removal of old migration mistakes".
Now, verification of CPU compatibility across a migration basically doesn't
happen. We simply ignore the PVR of the incoming migration, and hope the
cpu on the destination is close enough to work.
Now that we've cleaned up handling of processor compatibility modes
for pseries machine type, we can do better. For new machine types
(pseries-2.10+) We allow migration if:
* The source and destination PVRs are for the same type of CPU, as
determined by CPU class's pvr_match function
OR * When the source was in a compatibility mode, and the destination CPU
supports the same compatibility mode
For older machine types we retain the existing behaviour - current CAS
code will usually set a compat mode which would break backwards
migration if we made them use the new behaviour. [Fixed from an
earlier version by Greg Kurz].
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Tested-by: Andrea Bolognani <abologna@redhat.com>
2017-06-02 05:26:11 +03:00
|
|
|
/*
|
|
|
|
* Determine if a given PVR is a "close enough" match to the CPU
|
|
|
|
* object. For TCG and KVM PR it would probably be sufficient to
|
|
|
|
* require an exact PVR match. However for KVM HV the user is
|
|
|
|
* restricted to a PVR exactly matching the host CPU. The correct way
|
|
|
|
* to handle this is to put the guest into an architected
|
|
|
|
* compatibility mode. However, to allow a more forgiving transition
|
|
|
|
* and migration from before this was widely done, we allow migration
|
|
|
|
* between sufficiently similar PVRs, as determined by the CPU class's
|
|
|
|
* pvr_match() hook.
|
|
|
|
*/
|
|
|
|
static bool pvr_match(PowerPCCPU *cpu, uint32_t pvr)
|
|
|
|
{
|
|
|
|
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
|
|
|
|
|
|
|
|
if (pvr == pcc->pvr) {
|
|
|
|
return true;
|
|
|
|
}
|
2022-07-31 04:33:58 +03:00
|
|
|
return pcc->pvr_match(pcc, pvr, true);
|
ppc: Rework CPU compatibility testing across migration
Migrating between different CPU versions is a bit complicated for ppc.
A long time ago, we ensured identical CPU versions at either end by
checking the PVR had the same value. However, this breaks under KVM
HV, because we always have to use the host's PVR - it's not
virtualized. That would mean we couldn't migrate between hosts with
different PVRs, even if the CPUs are close enough to compatible in
practice (sometimes identical cores with different surrounding logic
have different PVRs, so this happens in practice quite often).
So, we removed the PVR check, but instead checked that several flags
indicating supported instructions matched. This turns out to be a bad
idea, because those instruction masks are not architected information, but
essentially a TCG implementation detail. So changes to qemu internal CPU
modelling can break migration - this happened between qemu-2.6 and
qemu-2.7. That was addressed by 146c11f1 "target-ppc: Allow eventual
removal of old migration mistakes".
Now, verification of CPU compatibility across a migration basically doesn't
happen. We simply ignore the PVR of the incoming migration, and hope the
cpu on the destination is close enough to work.
Now that we've cleaned up handling of processor compatibility modes
for pseries machine type, we can do better. For new machine types
(pseries-2.10+) We allow migration if:
* The source and destination PVRs are for the same type of CPU, as
determined by CPU class's pvr_match function
OR * When the source was in a compatibility mode, and the destination CPU
supports the same compatibility mode
For older machine types we retain the existing behaviour - current CAS
code will usually set a compat mode which would break backwards
migration if we made them use the new behaviour. [Fixed from an
earlier version by Greg Kurz].
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Tested-by: Andrea Bolognani <abologna@redhat.com>
2017-06-02 05:26:11 +03:00
|
|
|
}
|
|
|
|
|
2013-07-18 23:32:54 +04:00
|
|
|
static int cpu_post_load(void *opaque, int version_id)
|
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = opaque;
|
|
|
|
CPUPPCState *env = &cpu->env;
|
|
|
|
int i;
|
|
|
|
|
2014-04-15 09:06:10 +04:00
|
|
|
/*
|
ppc: Rework CPU compatibility testing across migration
Migrating between different CPU versions is a bit complicated for ppc.
A long time ago, we ensured identical CPU versions at either end by
checking the PVR had the same value. However, this breaks under KVM
HV, because we always have to use the host's PVR - it's not
virtualized. That would mean we couldn't migrate between hosts with
different PVRs, even if the CPUs are close enough to compatible in
practice (sometimes identical cores with different surrounding logic
have different PVRs, so this happens in practice quite often).
So, we removed the PVR check, but instead checked that several flags
indicating supported instructions matched. This turns out to be a bad
idea, because those instruction masks are not architected information, but
essentially a TCG implementation detail. So changes to qemu internal CPU
modelling can break migration - this happened between qemu-2.6 and
qemu-2.7. That was addressed by 146c11f1 "target-ppc: Allow eventual
removal of old migration mistakes".
Now, verification of CPU compatibility across a migration basically doesn't
happen. We simply ignore the PVR of the incoming migration, and hope the
cpu on the destination is close enough to work.
Now that we've cleaned up handling of processor compatibility modes
for pseries machine type, we can do better. For new machine types
(pseries-2.10+) We allow migration if:
* The source and destination PVRs are for the same type of CPU, as
determined by CPU class's pvr_match function
OR * When the source was in a compatibility mode, and the destination CPU
supports the same compatibility mode
For older machine types we retain the existing behaviour - current CAS
code will usually set a compat mode which would break backwards
migration if we made them use the new behaviour. [Fixed from an
earlier version by Greg Kurz].
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Tested-by: Andrea Bolognani <abologna@redhat.com>
2017-06-02 05:26:11 +03:00
|
|
|
* If we're operating in compat mode, we should be ok as long as
|
2020-10-09 09:44:37 +03:00
|
|
|
* the destination supports the same compatibility mode.
|
ppc: Rework CPU compatibility testing across migration
Migrating between different CPU versions is a bit complicated for ppc.
A long time ago, we ensured identical CPU versions at either end by
checking the PVR had the same value. However, this breaks under KVM
HV, because we always have to use the host's PVR - it's not
virtualized. That would mean we couldn't migrate between hosts with
different PVRs, even if the CPUs are close enough to compatible in
practice (sometimes identical cores with different surrounding logic
have different PVRs, so this happens in practice quite often).
So, we removed the PVR check, but instead checked that several flags
indicating supported instructions matched. This turns out to be a bad
idea, because those instruction masks are not architected information, but
essentially a TCG implementation detail. So changes to qemu internal CPU
modelling can break migration - this happened between qemu-2.6 and
qemu-2.7. That was addressed by 146c11f1 "target-ppc: Allow eventual
removal of old migration mistakes".
Now, verification of CPU compatibility across a migration basically doesn't
happen. We simply ignore the PVR of the incoming migration, and hope the
cpu on the destination is close enough to work.
Now that we've cleaned up handling of processor compatibility modes
for pseries machine type, we can do better. For new machine types
(pseries-2.10+) We allow migration if:
* The source and destination PVRs are for the same type of CPU, as
determined by CPU class's pvr_match function
OR * When the source was in a compatibility mode, and the destination CPU
supports the same compatibility mode
For older machine types we retain the existing behaviour - current CAS
code will usually set a compat mode which would break backwards
migration if we made them use the new behaviour. [Fixed from an
earlier version by Greg Kurz].
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Tested-by: Andrea Bolognani <abologna@redhat.com>
2017-06-02 05:26:11 +03:00
|
|
|
*
|
|
|
|
* Otherwise, however, we require that the destination has exactly
|
|
|
|
* the same CPU model as the source.
|
2014-04-15 09:06:10 +04:00
|
|
|
*/
|
ppc: Rework CPU compatibility testing across migration
Migrating between different CPU versions is a bit complicated for ppc.
A long time ago, we ensured identical CPU versions at either end by
checking the PVR had the same value. However, this breaks under KVM
HV, because we always have to use the host's PVR - it's not
virtualized. That would mean we couldn't migrate between hosts with
different PVRs, even if the CPUs are close enough to compatible in
practice (sometimes identical cores with different surrounding logic
have different PVRs, so this happens in practice quite often).
So, we removed the PVR check, but instead checked that several flags
indicating supported instructions matched. This turns out to be a bad
idea, because those instruction masks are not architected information, but
essentially a TCG implementation detail. So changes to qemu internal CPU
modelling can break migration - this happened between qemu-2.6 and
qemu-2.7. That was addressed by 146c11f1 "target-ppc: Allow eventual
removal of old migration mistakes".
Now, verification of CPU compatibility across a migration basically doesn't
happen. We simply ignore the PVR of the incoming migration, and hope the
cpu on the destination is close enough to work.
Now that we've cleaned up handling of processor compatibility modes
for pseries machine type, we can do better. For new machine types
(pseries-2.10+) We allow migration if:
* The source and destination PVRs are for the same type of CPU, as
determined by CPU class's pvr_match function
OR * When the source was in a compatibility mode, and the destination CPU
supports the same compatibility mode
For older machine types we retain the existing behaviour - current CAS
code will usually set a compat mode which would break backwards
migration if we made them use the new behaviour. [Fixed from an
earlier version by Greg Kurz].
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Tested-by: Andrea Bolognani <abologna@redhat.com>
2017-06-02 05:26:11 +03:00
|
|
|
|
|
|
|
#if defined(TARGET_PPC64)
|
|
|
|
if (cpu->compat_pvr) {
|
2017-11-24 07:23:25 +03:00
|
|
|
uint32_t compat_pvr = cpu->compat_pvr;
|
ppc: Rework CPU compatibility testing across migration
Migrating between different CPU versions is a bit complicated for ppc.
A long time ago, we ensured identical CPU versions at either end by
checking the PVR had the same value. However, this breaks under KVM
HV, because we always have to use the host's PVR - it's not
virtualized. That would mean we couldn't migrate between hosts with
different PVRs, even if the CPUs are close enough to compatible in
practice (sometimes identical cores with different surrounding logic
have different PVRs, so this happens in practice quite often).
So, we removed the PVR check, but instead checked that several flags
indicating supported instructions matched. This turns out to be a bad
idea, because those instruction masks are not architected information, but
essentially a TCG implementation detail. So changes to qemu internal CPU
modelling can break migration - this happened between qemu-2.6 and
qemu-2.7. That was addressed by 146c11f1 "target-ppc: Allow eventual
removal of old migration mistakes".
Now, verification of CPU compatibility across a migration basically doesn't
happen. We simply ignore the PVR of the incoming migration, and hope the
cpu on the destination is close enough to work.
Now that we've cleaned up handling of processor compatibility modes
for pseries machine type, we can do better. For new machine types
(pseries-2.10+) We allow migration if:
* The source and destination PVRs are for the same type of CPU, as
determined by CPU class's pvr_match function
OR * When the source was in a compatibility mode, and the destination CPU
supports the same compatibility mode
For older machine types we retain the existing behaviour - current CAS
code will usually set a compat mode which would break backwards
migration if we made them use the new behaviour. [Fixed from an
earlier version by Greg Kurz].
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Tested-by: Andrea Bolognani <abologna@redhat.com>
2017-06-02 05:26:11 +03:00
|
|
|
Error *local_err = NULL;
|
2020-09-14 15:34:53 +03:00
|
|
|
int ret;
|
ppc: Rework CPU compatibility testing across migration
Migrating between different CPU versions is a bit complicated for ppc.
A long time ago, we ensured identical CPU versions at either end by
checking the PVR had the same value. However, this breaks under KVM
HV, because we always have to use the host's PVR - it's not
virtualized. That would mean we couldn't migrate between hosts with
different PVRs, even if the CPUs are close enough to compatible in
practice (sometimes identical cores with different surrounding logic
have different PVRs, so this happens in practice quite often).
So, we removed the PVR check, but instead checked that several flags
indicating supported instructions matched. This turns out to be a bad
idea, because those instruction masks are not architected information, but
essentially a TCG implementation detail. So changes to qemu internal CPU
modelling can break migration - this happened between qemu-2.6 and
qemu-2.7. That was addressed by 146c11f1 "target-ppc: Allow eventual
removal of old migration mistakes".
Now, verification of CPU compatibility across a migration basically doesn't
happen. We simply ignore the PVR of the incoming migration, and hope the
cpu on the destination is close enough to work.
Now that we've cleaned up handling of processor compatibility modes
for pseries machine type, we can do better. For new machine types
(pseries-2.10+) We allow migration if:
* The source and destination PVRs are for the same type of CPU, as
determined by CPU class's pvr_match function
OR * When the source was in a compatibility mode, and the destination CPU
supports the same compatibility mode
For older machine types we retain the existing behaviour - current CAS
code will usually set a compat mode which would break backwards
migration if we made them use the new behaviour. [Fixed from an
earlier version by Greg Kurz].
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Tested-by: Andrea Bolognani <abologna@redhat.com>
2017-06-02 05:26:11 +03:00
|
|
|
|
2017-11-24 07:23:25 +03:00
|
|
|
cpu->compat_pvr = 0;
|
2020-09-14 15:34:53 +03:00
|
|
|
ret = ppc_set_compat(cpu, compat_pvr, &local_err);
|
|
|
|
if (ret < 0) {
|
ppc: Rework CPU compatibility testing across migration
Migrating between different CPU versions is a bit complicated for ppc.
A long time ago, we ensured identical CPU versions at either end by
checking the PVR had the same value. However, this breaks under KVM
HV, because we always have to use the host's PVR - it's not
virtualized. That would mean we couldn't migrate between hosts with
different PVRs, even if the CPUs are close enough to compatible in
practice (sometimes identical cores with different surrounding logic
have different PVRs, so this happens in practice quite often).
So, we removed the PVR check, but instead checked that several flags
indicating supported instructions matched. This turns out to be a bad
idea, because those instruction masks are not architected information, but
essentially a TCG implementation detail. So changes to qemu internal CPU
modelling can break migration - this happened between qemu-2.6 and
qemu-2.7. That was addressed by 146c11f1 "target-ppc: Allow eventual
removal of old migration mistakes".
Now, verification of CPU compatibility across a migration basically doesn't
happen. We simply ignore the PVR of the incoming migration, and hope the
cpu on the destination is close enough to work.
Now that we've cleaned up handling of processor compatibility modes
for pseries machine type, we can do better. For new machine types
(pseries-2.10+) We allow migration if:
* The source and destination PVRs are for the same type of CPU, as
determined by CPU class's pvr_match function
OR * When the source was in a compatibility mode, and the destination CPU
supports the same compatibility mode
For older machine types we retain the existing behaviour - current CAS
code will usually set a compat mode which would break backwards
migration if we made them use the new behaviour. [Fixed from an
earlier version by Greg Kurz].
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Tested-by: Andrea Bolognani <abologna@redhat.com>
2017-06-02 05:26:11 +03:00
|
|
|
error_report_err(local_err);
|
2020-09-14 15:34:53 +03:00
|
|
|
return ret;
|
ppc: Rework CPU compatibility testing across migration
Migrating between different CPU versions is a bit complicated for ppc.
A long time ago, we ensured identical CPU versions at either end by
checking the PVR had the same value. However, this breaks under KVM
HV, because we always have to use the host's PVR - it's not
virtualized. That would mean we couldn't migrate between hosts with
different PVRs, even if the CPUs are close enough to compatible in
practice (sometimes identical cores with different surrounding logic
have different PVRs, so this happens in practice quite often).
So, we removed the PVR check, but instead checked that several flags
indicating supported instructions matched. This turns out to be a bad
idea, because those instruction masks are not architected information, but
essentially a TCG implementation detail. So changes to qemu internal CPU
modelling can break migration - this happened between qemu-2.6 and
qemu-2.7. That was addressed by 146c11f1 "target-ppc: Allow eventual
removal of old migration mistakes".
Now, verification of CPU compatibility across a migration basically doesn't
happen. We simply ignore the PVR of the incoming migration, and hope the
cpu on the destination is close enough to work.
Now that we've cleaned up handling of processor compatibility modes
for pseries machine type, we can do better. For new machine types
(pseries-2.10+) We allow migration if:
* The source and destination PVRs are for the same type of CPU, as
determined by CPU class's pvr_match function
OR * When the source was in a compatibility mode, and the destination CPU
supports the same compatibility mode
For older machine types we retain the existing behaviour - current CAS
code will usually set a compat mode which would break backwards
migration if we made them use the new behaviour. [Fixed from an
earlier version by Greg Kurz].
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Tested-by: Andrea Bolognani <abologna@redhat.com>
2017-06-02 05:26:11 +03:00
|
|
|
}
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
if (!pvr_match(cpu, env->spr[SPR_PVR])) {
|
2020-09-14 15:34:53 +03:00
|
|
|
return -EINVAL;
|
ppc: Rework CPU compatibility testing across migration
Migrating between different CPU versions is a bit complicated for ppc.
A long time ago, we ensured identical CPU versions at either end by
checking the PVR had the same value. However, this breaks under KVM
HV, because we always have to use the host's PVR - it's not
virtualized. That would mean we couldn't migrate between hosts with
different PVRs, even if the CPUs are close enough to compatible in
practice (sometimes identical cores with different surrounding logic
have different PVRs, so this happens in practice quite often).
So, we removed the PVR check, but instead checked that several flags
indicating supported instructions matched. This turns out to be a bad
idea, because those instruction masks are not architected information, but
essentially a TCG implementation detail. So changes to qemu internal CPU
modelling can break migration - this happened between qemu-2.6 and
qemu-2.7. That was addressed by 146c11f1 "target-ppc: Allow eventual
removal of old migration mistakes".
Now, verification of CPU compatibility across a migration basically doesn't
happen. We simply ignore the PVR of the incoming migration, and hope the
cpu on the destination is close enough to work.
Now that we've cleaned up handling of processor compatibility modes
for pseries machine type, we can do better. For new machine types
(pseries-2.10+) We allow migration if:
* The source and destination PVRs are for the same type of CPU, as
determined by CPU class's pvr_match function
OR * When the source was in a compatibility mode, and the destination CPU
supports the same compatibility mode
For older machine types we retain the existing behaviour - current CAS
code will usually set a compat mode which would break backwards
migration if we made them use the new behaviour. [Fixed from an
earlier version by Greg Kurz].
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Tested-by: Andrea Bolognani <abologna@redhat.com>
2017-06-02 05:26:11 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-09 23:43:46 +03:00
|
|
|
/*
|
|
|
|
* If we're running with KVM HV, there is a chance that the guest
|
|
|
|
* is running with KVM HV and its kernel does not have the
|
|
|
|
* capability of dealing with a different PVR other than this
|
|
|
|
* exact host PVR in KVM_SET_SREGS. If that happens, the
|
|
|
|
* guest freezes after migration.
|
|
|
|
*
|
|
|
|
* The function kvmppc_pvr_workaround_required does this verification
|
|
|
|
* by first checking if the kernel has the cap, returning true immediately
|
|
|
|
* if that is the case. Otherwise, it checks if we're running in KVM PR.
|
|
|
|
* If the guest kernel does not have the cap and we're not running KVM-PR
|
|
|
|
* (so, it is running KVM-HV), we need to ensure that KVM_SET_SREGS will
|
|
|
|
* receive the PVR it expects as a workaround.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
if (kvmppc_pvr_workaround_required(cpu)) {
|
|
|
|
env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value;
|
|
|
|
}
|
|
|
|
|
2013-07-18 23:32:54 +04:00
|
|
|
env->lr = env->spr[SPR_LR];
|
|
|
|
env->ctr = env->spr[SPR_CTR];
|
2016-01-06 21:22:11 +03:00
|
|
|
cpu_write_xer(env, env->spr[SPR_XER]);
|
2013-07-18 23:32:54 +04:00
|
|
|
#if defined(TARGET_PPC64)
|
|
|
|
env->cfar = env->spr[SPR_CFAR];
|
|
|
|
#endif
|
|
|
|
env->spe_fscr = env->spr[SPR_BOOKE_SPEFSCR];
|
|
|
|
|
|
|
|
for (i = 0; (i < 4) && (i < env->nb_BATs); i++) {
|
2019-03-21 14:10:19 +03:00
|
|
|
env->DBAT[0][i] = env->spr[SPR_DBAT0U + 2 * i];
|
|
|
|
env->DBAT[1][i] = env->spr[SPR_DBAT0U + 2 * i + 1];
|
|
|
|
env->IBAT[0][i] = env->spr[SPR_IBAT0U + 2 * i];
|
|
|
|
env->IBAT[1][i] = env->spr[SPR_IBAT0U + 2 * i + 1];
|
2013-07-18 23:32:54 +04:00
|
|
|
}
|
2019-03-21 14:10:19 +03:00
|
|
|
for (i = 0; (i < 4) && ((i + 4) < env->nb_BATs); i++) {
|
|
|
|
env->DBAT[0][i + 4] = env->spr[SPR_DBAT4U + 2 * i];
|
|
|
|
env->DBAT[1][i + 4] = env->spr[SPR_DBAT4U + 2 * i + 1];
|
|
|
|
env->IBAT[0][i + 4] = env->spr[SPR_IBAT4U + 2 * i];
|
|
|
|
env->IBAT[1][i + 4] = env->spr[SPR_IBAT4U + 2 * i + 1];
|
2013-07-18 23:32:54 +04:00
|
|
|
}
|
|
|
|
|
2017-02-23 03:39:18 +03:00
|
|
|
if (!cpu->vhyp) {
|
2014-02-20 21:52:17 +04:00
|
|
|
ppc_store_sdr1(env, env->spr[SPR_SDR1]);
|
|
|
|
}
|
2015-02-10 01:40:48 +03:00
|
|
|
|
2021-03-23 21:43:31 +03:00
|
|
|
post_load_update_msr(env);
|
2015-02-10 01:40:48 +03:00
|
|
|
|
2023-05-30 16:04:47 +03:00
|
|
|
if (tcg_enabled()) {
|
2023-08-08 06:11:14 +03:00
|
|
|
/* Re-set breaks based on regs */
|
|
|
|
#if defined(TARGET_PPC64)
|
|
|
|
ppc_update_ciabr(env);
|
2023-08-08 06:11:15 +03:00
|
|
|
ppc_update_daw0(env);
|
2023-08-08 06:11:14 +03:00
|
|
|
#endif
|
2023-08-08 07:19:52 +03:00
|
|
|
/*
|
|
|
|
* TCG needs to re-start the decrementer timer and/or raise the
|
|
|
|
* interrupt. This works for level-triggered decrementer. Edge
|
|
|
|
* triggered types (including HDEC) would need to carry more state.
|
|
|
|
*/
|
|
|
|
cpu_ppc_store_decr(env, env->spr[SPR_DECR]);
|
2024-03-28 13:41:29 +03:00
|
|
|
pmu_mmcr01a_updated(env);
|
2023-05-30 16:04:47 +03:00
|
|
|
}
|
|
|
|
|
2013-07-18 23:32:54 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool fpu_needed(void *opaque)
|
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = opaque;
|
|
|
|
|
2019-03-21 14:10:19 +03:00
|
|
|
return cpu->env.insns_flags & PPC_FLOAT;
|
2013-07-18 23:32:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static const VMStateDescription vmstate_fpu = {
|
|
|
|
.name = "cpu/fpu",
|
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
2014-09-23 16:09:54 +04:00
|
|
|
.needed = fpu_needed,
|
2023-12-21 06:15:55 +03:00
|
|
|
.fields = (const VMStateField[]) {
|
2019-01-02 12:14:22 +03:00
|
|
|
VMSTATE_FPR_ARRAY(env.vsr, PowerPCCPU, 32),
|
2013-07-18 23:32:54 +04:00
|
|
|
VMSTATE_UINTTL(env.fpscr, PowerPCCPU),
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool altivec_needed(void *opaque)
|
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = opaque;
|
|
|
|
|
2019-03-21 14:10:19 +03:00
|
|
|
return cpu->env.insns_flags & PPC_ALTIVEC;
|
2013-07-18 23:32:54 +04:00
|
|
|
}
|
|
|
|
|
2019-02-15 13:00:54 +03:00
|
|
|
static int get_vscr(QEMUFile *f, void *opaque, size_t size,
|
|
|
|
const VMStateField *field)
|
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = opaque;
|
2021-05-12 17:08:08 +03:00
|
|
|
ppc_store_vscr(&cpu->env, qemu_get_be32(f));
|
2019-02-15 13:00:54 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int put_vscr(QEMUFile *f, void *opaque, size_t size,
|
2020-12-11 20:11:48 +03:00
|
|
|
const VMStateField *field, JSONWriter *vmdesc)
|
2019-02-15 13:00:54 +03:00
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = opaque;
|
2021-05-12 17:08:08 +03:00
|
|
|
qemu_put_be32(f, ppc_get_vscr(&cpu->env));
|
2019-02-15 13:00:54 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const VMStateInfo vmstate_vscr = {
|
|
|
|
.name = "cpu/altivec/vscr",
|
|
|
|
.get = get_vscr,
|
|
|
|
.put = put_vscr,
|
|
|
|
};
|
|
|
|
|
2013-07-18 23:32:54 +04:00
|
|
|
static const VMStateDescription vmstate_altivec = {
|
|
|
|
.name = "cpu/altivec",
|
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
2014-09-23 16:09:54 +04:00
|
|
|
.needed = altivec_needed,
|
2023-12-21 06:15:55 +03:00
|
|
|
.fields = (const VMStateField[]) {
|
2019-01-02 12:14:22 +03:00
|
|
|
VMSTATE_AVR_ARRAY(env.vsr, PowerPCCPU, 32),
|
2019-02-15 13:00:54 +03:00
|
|
|
/*
|
|
|
|
* Save the architecture value of the vscr, not the internally
|
|
|
|
* expanded version. Since this architecture value does not
|
|
|
|
* exist in memory to be stored, this requires a but of hoop
|
|
|
|
* jumping. We want OFFSET=0 so that we effectively pass CPU
|
|
|
|
* to the helper functions.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
.name = "vscr",
|
|
|
|
.version_id = 0,
|
|
|
|
.size = sizeof(uint32_t),
|
|
|
|
.info = &vmstate_vscr,
|
|
|
|
.flags = VMS_SINGLE,
|
|
|
|
.offset = 0
|
|
|
|
},
|
2013-07-18 23:32:54 +04:00
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool vsx_needed(void *opaque)
|
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = opaque;
|
|
|
|
|
2019-03-21 14:10:19 +03:00
|
|
|
return cpu->env.insns_flags2 & PPC2_VSX;
|
2013-07-18 23:32:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static const VMStateDescription vmstate_vsx = {
|
|
|
|
.name = "cpu/vsx",
|
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
2014-09-23 16:09:54 +04:00
|
|
|
.needed = vsx_needed,
|
2023-12-21 06:15:55 +03:00
|
|
|
.fields = (const VMStateField[]) {
|
2019-01-02 12:14:22 +03:00
|
|
|
VMSTATE_VSR_ARRAY(env.vsr, PowerPCCPU, 32),
|
2013-07-18 23:32:54 +04:00
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2014-06-04 16:51:00 +04:00
|
|
|
#ifdef TARGET_PPC64
|
|
|
|
/* Transactional memory state */
|
|
|
|
static bool tm_needed(void *opaque)
|
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = opaque;
|
|
|
|
CPUPPCState *env = &cpu->env;
|
2022-05-05 00:05:37 +03:00
|
|
|
return FIELD_EX64(env->msr, MSR, TS);
|
2014-06-04 16:51:00 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static const VMStateDescription vmstate_tm = {
|
|
|
|
.name = "cpu/tm",
|
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
2014-09-23 16:09:54 +04:00
|
|
|
.needed = tm_needed,
|
2023-12-21 06:15:55 +03:00
|
|
|
.fields = (const VMStateField []) {
|
2014-06-04 16:51:00 +04:00
|
|
|
VMSTATE_UINTTL_ARRAY(env.tm_gpr, PowerPCCPU, 32),
|
|
|
|
VMSTATE_AVR_ARRAY(env.tm_vsr, PowerPCCPU, 64),
|
|
|
|
VMSTATE_UINT64(env.tm_cr, PowerPCCPU),
|
|
|
|
VMSTATE_UINT64(env.tm_lr, PowerPCCPU),
|
|
|
|
VMSTATE_UINT64(env.tm_ctr, PowerPCCPU),
|
|
|
|
VMSTATE_UINT64(env.tm_fpscr, PowerPCCPU),
|
|
|
|
VMSTATE_UINT64(env.tm_amr, PowerPCCPU),
|
|
|
|
VMSTATE_UINT64(env.tm_ppr, PowerPCCPU),
|
|
|
|
VMSTATE_UINT64(env.tm_vrsave, PowerPCCPU),
|
|
|
|
VMSTATE_UINT32(env.tm_vscr, PowerPCCPU),
|
|
|
|
VMSTATE_UINT64(env.tm_dscr, PowerPCCPU),
|
|
|
|
VMSTATE_UINT64(env.tm_tar, PowerPCCPU),
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
},
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2013-07-18 23:32:54 +04:00
|
|
|
static bool sr_needed(void *opaque)
|
|
|
|
{
|
|
|
|
#ifdef TARGET_PPC64
|
|
|
|
PowerPCCPU *cpu = opaque;
|
|
|
|
|
2020-12-09 20:35:36 +03:00
|
|
|
return !mmu_is_64bit(cpu->env.mmu_model);
|
2013-07-18 23:32:54 +04:00
|
|
|
#else
|
|
|
|
return true;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static const VMStateDescription vmstate_sr = {
|
|
|
|
.name = "cpu/sr",
|
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
2014-09-23 16:09:54 +04:00
|
|
|
.needed = sr_needed,
|
2023-12-21 06:15:55 +03:00
|
|
|
.fields = (const VMStateField[]) {
|
2013-07-18 23:32:54 +04:00
|
|
|
VMSTATE_UINTTL_ARRAY(env.sr, PowerPCCPU, 32),
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef TARGET_PPC64
|
2018-11-14 16:29:30 +03:00
|
|
|
static int get_slbe(QEMUFile *f, void *pv, size_t size,
|
|
|
|
const VMStateField *field)
|
2013-07-18 23:32:54 +04:00
|
|
|
{
|
|
|
|
ppc_slb_t *v = pv;
|
|
|
|
|
|
|
|
v->esid = qemu_get_be64(f);
|
|
|
|
v->vsid = qemu_get_be64(f);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-14 16:29:30 +03:00
|
|
|
static int put_slbe(QEMUFile *f, void *pv, size_t size,
|
2020-12-11 20:11:48 +03:00
|
|
|
const VMStateField *field, JSONWriter *vmdesc)
|
2013-07-18 23:32:54 +04:00
|
|
|
{
|
|
|
|
ppc_slb_t *v = pv;
|
|
|
|
|
|
|
|
qemu_put_be64(f, v->esid);
|
|
|
|
qemu_put_be64(f, v->vsid);
|
2017-01-19 22:00:50 +03:00
|
|
|
return 0;
|
2013-07-18 23:32:54 +04:00
|
|
|
}
|
|
|
|
|
2014-03-16 17:49:54 +04:00
|
|
|
static const VMStateInfo vmstate_info_slbe = {
|
2013-07-18 23:32:54 +04:00
|
|
|
.name = "slbe",
|
|
|
|
.get = get_slbe,
|
|
|
|
.put = put_slbe,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define VMSTATE_SLB_ARRAY_V(_f, _s, _n, _v) \
|
|
|
|
VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_slbe, ppc_slb_t)
|
|
|
|
|
|
|
|
#define VMSTATE_SLB_ARRAY(_f, _s, _n) \
|
|
|
|
VMSTATE_SLB_ARRAY_V(_f, _s, _n, 0)
|
|
|
|
|
|
|
|
static bool slb_needed(void *opaque)
|
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = opaque;
|
|
|
|
|
|
|
|
/* We don't support any of the old segment table based 64-bit CPUs */
|
2020-12-09 20:35:36 +03:00
|
|
|
return mmu_is_64bit(cpu->env.mmu_model);
|
2013-07-18 23:32:54 +04:00
|
|
|
}
|
|
|
|
|
2016-01-27 03:52:57 +03:00
|
|
|
static int slb_post_load(void *opaque, int version_id)
|
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = opaque;
|
|
|
|
CPUPPCState *env = &cpu->env;
|
|
|
|
int i;
|
|
|
|
|
2019-03-21 14:10:19 +03:00
|
|
|
/*
|
|
|
|
* We've pulled in the raw esid and vsid values from the migration
|
|
|
|
* stream, but we need to recompute the page size pointers
|
|
|
|
*/
|
2018-03-29 10:29:38 +03:00
|
|
|
for (i = 0; i < cpu->hash64_opts->slb_size; i++) {
|
2016-01-27 03:52:57 +03:00
|
|
|
if (ppc_store_slb(cpu, i, env->slb[i].esid, env->slb[i].vsid) < 0) {
|
|
|
|
/* Migration source had bad values in its SLB */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-18 23:32:54 +04:00
|
|
|
static const VMStateDescription vmstate_slb = {
|
|
|
|
.name = "cpu/slb",
|
2024-10-14 15:27:29 +03:00
|
|
|
.version_id = 2,
|
2013-07-18 23:32:54 +04:00
|
|
|
.minimum_version_id = 1,
|
2014-09-23 16:09:54 +04:00
|
|
|
.needed = slb_needed,
|
2016-01-27 03:52:57 +03:00
|
|
|
.post_load = slb_post_load,
|
2023-12-21 06:15:55 +03:00
|
|
|
.fields = (const VMStateField[]) {
|
2013-10-01 20:19:31 +04:00
|
|
|
VMSTATE_SLB_ARRAY(env.slb, PowerPCCPU, MAX_SLB_ENTRIES),
|
2013-07-18 23:32:54 +04:00
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
#endif /* TARGET_PPC64 */
|
|
|
|
|
|
|
|
static const VMStateDescription vmstate_tlb6xx_entry = {
|
|
|
|
.name = "cpu/tlb6xx_entry",
|
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
2023-12-21 06:15:55 +03:00
|
|
|
.fields = (const VMStateField[]) {
|
2013-07-18 23:32:54 +04:00
|
|
|
VMSTATE_UINTTL(pte0, ppc6xx_tlb_t),
|
|
|
|
VMSTATE_UINTTL(pte1, ppc6xx_tlb_t),
|
|
|
|
VMSTATE_UINTTL(EPN, ppc6xx_tlb_t),
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool tlb6xx_needed(void *opaque)
|
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = opaque;
|
|
|
|
CPUPPCState *env = &cpu->env;
|
|
|
|
|
|
|
|
return env->nb_tlb && (env->tlb_type == TLB_6XX);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const VMStateDescription vmstate_tlb6xx = {
|
|
|
|
.name = "cpu/tlb6xx",
|
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
2014-09-23 16:09:54 +04:00
|
|
|
.needed = tlb6xx_needed,
|
2023-12-21 06:15:55 +03:00
|
|
|
.fields = (const VMStateField[]) {
|
2017-06-23 17:48:23 +03:00
|
|
|
VMSTATE_INT32_EQUAL(env.nb_tlb, PowerPCCPU, NULL),
|
2013-07-18 23:32:54 +04:00
|
|
|
VMSTATE_STRUCT_VARRAY_POINTER_INT32(env.tlb.tlb6, PowerPCCPU,
|
|
|
|
env.nb_tlb,
|
|
|
|
vmstate_tlb6xx_entry,
|
|
|
|
ppc6xx_tlb_t),
|
|
|
|
VMSTATE_UINTTL_ARRAY(env.tgpr, PowerPCCPU, 4),
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const VMStateDescription vmstate_tlbemb_entry = {
|
|
|
|
.name = "cpu/tlbemb_entry",
|
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
2023-12-21 06:15:55 +03:00
|
|
|
.fields = (const VMStateField[]) {
|
2013-07-18 23:32:54 +04:00
|
|
|
VMSTATE_UINT64(RPN, ppcemb_tlb_t),
|
|
|
|
VMSTATE_UINTTL(EPN, ppcemb_tlb_t),
|
|
|
|
VMSTATE_UINTTL(PID, ppcemb_tlb_t),
|
|
|
|
VMSTATE_UINTTL(size, ppcemb_tlb_t),
|
|
|
|
VMSTATE_UINT32(prot, ppcemb_tlb_t),
|
|
|
|
VMSTATE_UINT32(attr, ppcemb_tlb_t),
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool tlbemb_needed(void *opaque)
|
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = opaque;
|
|
|
|
CPUPPCState *env = &cpu->env;
|
|
|
|
|
|
|
|
return env->nb_tlb && (env->tlb_type == TLB_EMB);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const VMStateDescription vmstate_tlbemb = {
|
2024-08-22 19:56:53 +03:00
|
|
|
.name = "cpu/tlbemb",
|
2013-07-18 23:32:54 +04:00
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
2014-09-23 16:09:54 +04:00
|
|
|
.needed = tlbemb_needed,
|
2023-12-21 06:15:55 +03:00
|
|
|
.fields = (const VMStateField[]) {
|
2017-06-23 17:48:23 +03:00
|
|
|
VMSTATE_INT32_EQUAL(env.nb_tlb, PowerPCCPU, NULL),
|
2013-07-18 23:32:54 +04:00
|
|
|
VMSTATE_STRUCT_VARRAY_POINTER_INT32(env.tlb.tlbe, PowerPCCPU,
|
|
|
|
env.nb_tlb,
|
|
|
|
vmstate_tlbemb_entry,
|
|
|
|
ppcemb_tlb_t),
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static const VMStateDescription vmstate_tlbmas_entry = {
|
|
|
|
.name = "cpu/tlbmas_entry",
|
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
2023-12-21 06:15:55 +03:00
|
|
|
.fields = (const VMStateField[]) {
|
2013-07-18 23:32:54 +04:00
|
|
|
VMSTATE_UINT32(mas8, ppcmas_tlb_t),
|
|
|
|
VMSTATE_UINT32(mas1, ppcmas_tlb_t),
|
|
|
|
VMSTATE_UINT64(mas2, ppcmas_tlb_t),
|
|
|
|
VMSTATE_UINT64(mas7_3, ppcmas_tlb_t),
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool tlbmas_needed(void *opaque)
|
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = opaque;
|
|
|
|
CPUPPCState *env = &cpu->env;
|
|
|
|
|
|
|
|
return env->nb_tlb && (env->tlb_type == TLB_MAS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const VMStateDescription vmstate_tlbmas = {
|
|
|
|
.name = "cpu/tlbmas",
|
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
2014-09-23 16:09:54 +04:00
|
|
|
.needed = tlbmas_needed,
|
2023-12-21 06:15:55 +03:00
|
|
|
.fields = (const VMStateField[]) {
|
2017-06-23 17:48:23 +03:00
|
|
|
VMSTATE_INT32_EQUAL(env.nb_tlb, PowerPCCPU, NULL),
|
2013-07-18 23:32:54 +04:00
|
|
|
VMSTATE_STRUCT_VARRAY_POINTER_INT32(env.tlb.tlbm, PowerPCCPU,
|
|
|
|
env.nb_tlb,
|
|
|
|
vmstate_tlbmas_entry,
|
|
|
|
ppcmas_tlb_t),
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
ppc: Rework CPU compatibility testing across migration
Migrating between different CPU versions is a bit complicated for ppc.
A long time ago, we ensured identical CPU versions at either end by
checking the PVR had the same value. However, this breaks under KVM
HV, because we always have to use the host's PVR - it's not
virtualized. That would mean we couldn't migrate between hosts with
different PVRs, even if the CPUs are close enough to compatible in
practice (sometimes identical cores with different surrounding logic
have different PVRs, so this happens in practice quite often).
So, we removed the PVR check, but instead checked that several flags
indicating supported instructions matched. This turns out to be a bad
idea, because those instruction masks are not architected information, but
essentially a TCG implementation detail. So changes to qemu internal CPU
modelling can break migration - this happened between qemu-2.6 and
qemu-2.7. That was addressed by 146c11f1 "target-ppc: Allow eventual
removal of old migration mistakes".
Now, verification of CPU compatibility across a migration basically doesn't
happen. We simply ignore the PVR of the incoming migration, and hope the
cpu on the destination is close enough to work.
Now that we've cleaned up handling of processor compatibility modes
for pseries machine type, we can do better. For new machine types
(pseries-2.10+) We allow migration if:
* The source and destination PVRs are for the same type of CPU, as
determined by CPU class's pvr_match function
OR * When the source was in a compatibility mode, and the destination CPU
supports the same compatibility mode
For older machine types we retain the existing behaviour - current CAS
code will usually set a compat mode which would break backwards
migration if we made them use the new behaviour. [Fixed from an
earlier version by Greg Kurz].
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Tested-by: Andrea Bolognani <abologna@redhat.com>
2017-06-02 05:26:11 +03:00
|
|
|
static bool compat_needed(void *opaque)
|
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = opaque;
|
|
|
|
|
|
|
|
assert(!(cpu->compat_pvr && !cpu->vhyp));
|
2024-10-14 15:27:25 +03:00
|
|
|
return cpu->compat_pvr != 0;
|
ppc: Rework CPU compatibility testing across migration
Migrating between different CPU versions is a bit complicated for ppc.
A long time ago, we ensured identical CPU versions at either end by
checking the PVR had the same value. However, this breaks under KVM
HV, because we always have to use the host's PVR - it's not
virtualized. That would mean we couldn't migrate between hosts with
different PVRs, even if the CPUs are close enough to compatible in
practice (sometimes identical cores with different surrounding logic
have different PVRs, so this happens in practice quite often).
So, we removed the PVR check, but instead checked that several flags
indicating supported instructions matched. This turns out to be a bad
idea, because those instruction masks are not architected information, but
essentially a TCG implementation detail. So changes to qemu internal CPU
modelling can break migration - this happened between qemu-2.6 and
qemu-2.7. That was addressed by 146c11f1 "target-ppc: Allow eventual
removal of old migration mistakes".
Now, verification of CPU compatibility across a migration basically doesn't
happen. We simply ignore the PVR of the incoming migration, and hope the
cpu on the destination is close enough to work.
Now that we've cleaned up handling of processor compatibility modes
for pseries machine type, we can do better. For new machine types
(pseries-2.10+) We allow migration if:
* The source and destination PVRs are for the same type of CPU, as
determined by CPU class's pvr_match function
OR * When the source was in a compatibility mode, and the destination CPU
supports the same compatibility mode
For older machine types we retain the existing behaviour - current CAS
code will usually set a compat mode which would break backwards
migration if we made them use the new behaviour. [Fixed from an
earlier version by Greg Kurz].
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Tested-by: Andrea Bolognani <abologna@redhat.com>
2017-06-02 05:26:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static const VMStateDescription vmstate_compat = {
|
|
|
|
.name = "cpu/compat",
|
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
|
|
|
.needed = compat_needed,
|
2023-12-21 06:15:55 +03:00
|
|
|
.fields = (const VMStateField[]) {
|
ppc: Rework CPU compatibility testing across migration
Migrating between different CPU versions is a bit complicated for ppc.
A long time ago, we ensured identical CPU versions at either end by
checking the PVR had the same value. However, this breaks under KVM
HV, because we always have to use the host's PVR - it's not
virtualized. That would mean we couldn't migrate between hosts with
different PVRs, even if the CPUs are close enough to compatible in
practice (sometimes identical cores with different surrounding logic
have different PVRs, so this happens in practice quite often).
So, we removed the PVR check, but instead checked that several flags
indicating supported instructions matched. This turns out to be a bad
idea, because those instruction masks are not architected information, but
essentially a TCG implementation detail. So changes to qemu internal CPU
modelling can break migration - this happened between qemu-2.6 and
qemu-2.7. That was addressed by 146c11f1 "target-ppc: Allow eventual
removal of old migration mistakes".
Now, verification of CPU compatibility across a migration basically doesn't
happen. We simply ignore the PVR of the incoming migration, and hope the
cpu on the destination is close enough to work.
Now that we've cleaned up handling of processor compatibility modes
for pseries machine type, we can do better. For new machine types
(pseries-2.10+) We allow migration if:
* The source and destination PVRs are for the same type of CPU, as
determined by CPU class's pvr_match function
OR * When the source was in a compatibility mode, and the destination CPU
supports the same compatibility mode
For older machine types we retain the existing behaviour - current CAS
code will usually set a compat mode which would break backwards
migration if we made them use the new behaviour. [Fixed from an
earlier version by Greg Kurz].
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Tested-by: Andrea Bolognani <abologna@redhat.com>
2017-06-02 05:26:11 +03:00
|
|
|
VMSTATE_UINT32(compat_pvr, PowerPCCPU),
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-08-08 07:19:55 +03:00
|
|
|
static bool reservation_needed(void *opaque)
|
|
|
|
{
|
|
|
|
return (replay_mode != REPLAY_MODE_NONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const VMStateDescription vmstate_reservation = {
|
|
|
|
.name = "cpu/reservation",
|
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
|
|
|
.needed = reservation_needed,
|
2023-12-21 06:15:55 +03:00
|
|
|
.fields = (const VMStateField[]) {
|
2023-08-08 07:19:55 +03:00
|
|
|
VMSTATE_UINTTL(env.reserve_addr, PowerPCCPU),
|
|
|
|
VMSTATE_UINTTL(env.reserve_length, PowerPCCPU),
|
|
|
|
VMSTATE_UINTTL(env.reserve_val, PowerPCCPU),
|
|
|
|
#if defined(TARGET_PPC64)
|
|
|
|
VMSTATE_UINTTL(env.reserve_val2, PowerPCCPU),
|
|
|
|
#endif
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-03-28 13:41:37 +03:00
|
|
|
#ifdef TARGET_PPC64
|
|
|
|
static bool bhrb_needed(void *opaque)
|
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = opaque;
|
|
|
|
return (cpu->env.flags & POWERPC_FLAG_BHRB) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const VMStateDescription vmstate_bhrb = {
|
|
|
|
.name = "cpu/bhrb",
|
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
|
|
|
.needed = bhrb_needed,
|
|
|
|
.fields = (VMStateField[]) {
|
|
|
|
VMSTATE_UINTTL(env.bhrb_offset, PowerPCCPU),
|
|
|
|
VMSTATE_UINT64_ARRAY(env.bhrb, PowerPCCPU, BHRB_MAX_NUM_ENTRIES),
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2013-07-18 23:32:54 +04:00
|
|
|
const VMStateDescription vmstate_ppc_cpu = {
|
|
|
|
.name = "cpu",
|
|
|
|
.version_id = 5,
|
|
|
|
.minimum_version_id = 5,
|
|
|
|
.pre_save = cpu_pre_save,
|
|
|
|
.post_load = cpu_post_load,
|
2023-12-21 06:15:55 +03:00
|
|
|
.fields = (const VMStateField[]) {
|
2014-04-15 09:06:10 +04:00
|
|
|
VMSTATE_UNUSED(sizeof(target_ulong)), /* was _EQUAL(env.spr[SPR_PVR]) */
|
2013-07-18 23:32:54 +04:00
|
|
|
|
|
|
|
/* User mode architected state */
|
|
|
|
VMSTATE_UINTTL_ARRAY(env.gpr, PowerPCCPU, 32),
|
|
|
|
#if !defined(TARGET_PPC64)
|
|
|
|
VMSTATE_UINTTL_ARRAY(env.gprh, PowerPCCPU, 32),
|
|
|
|
#endif
|
|
|
|
VMSTATE_UINT32_ARRAY(env.crf, PowerPCCPU, 8),
|
|
|
|
VMSTATE_UINTTL(env.nip, PowerPCCPU),
|
|
|
|
|
|
|
|
/* SPRs */
|
|
|
|
VMSTATE_UINTTL_ARRAY(env.spr, PowerPCCPU, 1024),
|
|
|
|
VMSTATE_UINT64(env.spe_acc, PowerPCCPU),
|
|
|
|
|
2023-08-08 07:19:55 +03:00
|
|
|
VMSTATE_UNUSED(sizeof(target_ulong)), /* was env.reserve_addr */
|
2013-07-18 23:32:54 +04:00
|
|
|
|
|
|
|
/* Supervisor mode architected state */
|
|
|
|
VMSTATE_UINTTL(env.msr, PowerPCCPU),
|
|
|
|
|
2021-03-15 21:46:03 +03:00
|
|
|
/* Backward compatible internal state */
|
|
|
|
VMSTATE_UINTTL(env.hflags_compat_nmsr, PowerPCCPU),
|
2013-07-18 23:32:54 +04:00
|
|
|
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
},
|
2023-12-21 06:15:55 +03:00
|
|
|
.subsections = (const VMStateDescription * const []) {
|
2014-09-23 16:09:54 +04:00
|
|
|
&vmstate_fpu,
|
|
|
|
&vmstate_altivec,
|
|
|
|
&vmstate_vsx,
|
|
|
|
&vmstate_sr,
|
2013-07-18 23:32:54 +04:00
|
|
|
#ifdef TARGET_PPC64
|
2014-09-23 16:09:54 +04:00
|
|
|
&vmstate_tm,
|
|
|
|
&vmstate_slb,
|
2024-03-28 13:41:37 +03:00
|
|
|
&vmstate_bhrb,
|
2013-07-18 23:32:54 +04:00
|
|
|
#endif /* TARGET_PPC64 */
|
2014-09-23 16:09:54 +04:00
|
|
|
&vmstate_tlb6xx,
|
|
|
|
&vmstate_tlbemb,
|
|
|
|
&vmstate_tlbmas,
|
ppc: Rework CPU compatibility testing across migration
Migrating between different CPU versions is a bit complicated for ppc.
A long time ago, we ensured identical CPU versions at either end by
checking the PVR had the same value. However, this breaks under KVM
HV, because we always have to use the host's PVR - it's not
virtualized. That would mean we couldn't migrate between hosts with
different PVRs, even if the CPUs are close enough to compatible in
practice (sometimes identical cores with different surrounding logic
have different PVRs, so this happens in practice quite often).
So, we removed the PVR check, but instead checked that several flags
indicating supported instructions matched. This turns out to be a bad
idea, because those instruction masks are not architected information, but
essentially a TCG implementation detail. So changes to qemu internal CPU
modelling can break migration - this happened between qemu-2.6 and
qemu-2.7. That was addressed by 146c11f1 "target-ppc: Allow eventual
removal of old migration mistakes".
Now, verification of CPU compatibility across a migration basically doesn't
happen. We simply ignore the PVR of the incoming migration, and hope the
cpu on the destination is close enough to work.
Now that we've cleaned up handling of processor compatibility modes
for pseries machine type, we can do better. For new machine types
(pseries-2.10+) We allow migration if:
* The source and destination PVRs are for the same type of CPU, as
determined by CPU class's pvr_match function
OR * When the source was in a compatibility mode, and the destination CPU
supports the same compatibility mode
For older machine types we retain the existing behaviour - current CAS
code will usually set a compat mode which would break backwards
migration if we made them use the new behaviour. [Fixed from an
earlier version by Greg Kurz].
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Tested-by: Andrea Bolognani <abologna@redhat.com>
2017-06-02 05:26:11 +03:00
|
|
|
&vmstate_compat,
|
2023-08-08 07:19:55 +03:00
|
|
|
&vmstate_reservation,
|
2014-09-23 16:09:54 +04:00
|
|
|
NULL
|
2013-07-18 23:32:54 +04:00
|
|
|
}
|
|
|
|
};
|