@@ -46,6 +46,7 @@
#include "migration/qemu-file-types.h"
#include "migration/global_state.h"
#include "migration/register.h"
+#include "migration/blocker.h"
#include "mmu-hash64.h"
#include "mmu-book3s-v3.h"
#include "cpu-models.h"
@@ -1830,6 +1831,8 @@ static void spapr_machine_reset(MachineState *machine)
/* Signal all vCPUs waiting on this condition */
qemu_cond_broadcast(&spapr->mc_delivery_cond);
+
+ migrate_del_blocker(spapr->fwnmi_migration_blocker);
}
static void spapr_create_nvram(SpaprMachineState *spapr)
@@ -2120,6 +2123,43 @@ static const VMStateDescription vmstate_spapr_dtb = {
},
};
+static bool spapr_fwnmi_needed(void *opaque)
+{
+ SpaprMachineState *spapr = (SpaprMachineState *)opaque;
+
+ return spapr->guest_machine_check_addr != -1;
+}
+
+static int spapr_fwnmi_pre_save(void *opaque)
+{
+ SpaprMachineState *spapr = (SpaprMachineState *)opaque;
+
+ /*
+ * With -only-migratable QEMU option, we cannot block migration.
+ * Hence check if machine check handling is in progress and print
+ * a warning message.
+ */
+ if (spapr->mc_status != -1) {
+ warn_report("A machine check is being handled during migration. The"
+ "handler may run and log hardware error on the destination");
+ }
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_spapr_machine_check = {
+ .name = "spapr_machine_check",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = spapr_fwnmi_needed,
+ .pre_save = spapr_fwnmi_pre_save,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(guest_machine_check_addr, SpaprMachineState),
+ VMSTATE_INT32(mc_status, SpaprMachineState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static const VMStateDescription vmstate_spapr = {
.name = "spapr",
.version_id = 3,
@@ -2153,6 +2193,7 @@ static const VMStateDescription vmstate_spapr = {
&vmstate_spapr_dtb,
&vmstate_spapr_cap_large_decr,
&vmstate_spapr_cap_ccf_assist,
+ &vmstate_spapr_machine_check,
NULL
}
};
@@ -43,6 +43,7 @@
#include "qemu/main-loop.h"
#include "hw/ppc/spapr_ovec.h"
#include <libfdt.h>
+#include "migration/blocker.h"
#define RTAS_LOG_VERSION_MASK 0xff000000
#define RTAS_LOG_VERSION_6 0x06000000
@@ -842,6 +843,8 @@ void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered)
{
SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
CPUState *cs = CPU(cpu);
+ int ret;
+ Error *local_err = NULL;
if (spapr->guest_machine_check_addr == -1) {
/*
@@ -871,8 +874,19 @@ void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered)
return;
}
}
- spapr->mc_status = cpu->vcpu_id;
+ ret = migrate_add_blocker(spapr->fwnmi_migration_blocker, &local_err);
+ if (ret == -EBUSY) {
+ /*
+ * We don't want to abort so we let the migration to continue.
+ * In a rare case, the machine check handler will run on the target.
+ * Though this is not preferable, it is better than aborting
+ * the migration or killing the VM.
+ */
+ warn_report_err(local_err);
+ }
+
+ spapr->mc_status = cpu->vcpu_id;
spapr_mce_dispatch_elog(cpu, recovered);
}
@@ -50,6 +50,7 @@
#include "hw/ppc/fdt.h"
#include "target/ppc/mmu-hash64.h"
#include "target/ppc/mmu-book3s-v3.h"
+#include "migration/blocker.h"
static void rtas_display_character(PowerPCCPU *cpu, SpaprMachineState *spapr,
uint32_t token, uint32_t nargs,
@@ -446,6 +447,7 @@ static void rtas_ibm_nmi_interlock(PowerPCCPU *cpu,
*/
spapr->mc_status = -1;
qemu_cond_signal(&spapr->mc_delivery_cond);
+ migrate_del_blocker(spapr->fwnmi_migration_blocker);
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
@@ -217,6 +217,8 @@ struct SpaprMachineState {
unsigned gpu_numa_id;
SpaprTpmProxy *tpm_proxy;
+
+ Error *fwnmi_migration_blocker;
};
#define H_SUCCESS 0