target/i386/mshv: migrate MP_STATE
MSHV's "internal activity state" roughly maps to QEMU's env->mp_state and cpu->halted states that describe state of APs in a guest. We don't invoke set_mp_state as part of store_vcpu_state() b/c we would put all BSP + APs in a RUNNABLE (0) state immediately, breaking SMP boot Instead we store the mp state as part of the load_cleanup() routine after a migration. Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com> Link: https://lore.kernel.org/r/20260710101534.664604-11-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Magnus Kulke committed
Jul 10, 2026 at 12:15 UTC
ec38b3d54c4ff314670b923a50daf0bd7c040b8a
3 files changed
+91
accel/mshv/mshv-all.c
+10
@@ -62,6 +62,7 @@ static int init_mshv(int *mshv_fd)
62
63
static int mshv_load_cleanup(void *opaque)
64
{
65
+ CPUState *cpu;
66
int ret;
67
68
ret = mshv_arch_set_partition_msrs(first_cpu);
@@ -70,6 +71,15 @@ static int mshv_load_cleanup(void *opaque)
71
return -1;
72
}
73
74
+ CPU_FOREACH(cpu) {
75
+ ret = mshv_arch_set_mp_state(cpu);
76
+ if (ret < 0) {
77
+ error_report("Failed to set mp state for vCPU %d: %s",
78
+ cpu->cpu_index, strerror(-ret));
79
+ return -1;
80
+ }
81
+ }
82
+
83
return 0;
84
}
85
include/system/mshv_int.h
+1
@@ -99,6 +99,7 @@ int mshv_get_generic_regs(CPUState *cpu, hv_register_assoc *assocs,
99
int mshv_arch_store_vcpu_state(const CPUState *cpu);
100
int mshv_arch_load_vcpu_state(CPUState *cpu);
101
int mshv_arch_set_partition_msrs(const CPUState *cpu);
102
+int mshv_arch_set_mp_state(const CPUState *cpu);
103
void mshv_arch_init_vcpu(CPUState *cpu);
104
void mshv_arch_destroy_vcpu(CPUState *cpu);
105
void mshv_arch_amend_proc_features(
target/i386/mshv/mshv-cpu.c
+80
@@ -35,6 +35,11 @@
35
36
#include <sys/ioctl.h>
37
38
+#define MSHV_MP_STATE_RUNNABLE 0
39
+#define MSHV_MP_STATE_UNINITIALIZED 1
40
+#define MSHV_MP_STATE_INIT_RECEIVED 2
41
+#define MSHV_MP_STATE_HALTED 3
42
+
43
#define MAX_REGISTER_COUNT (MAX_CONST(ARRAY_SIZE(STANDARD_REGISTER_NAMES), \
44
MAX_CONST(ARRAY_SIZE(SPECIAL_REGISTER_NAMES), \
45
ARRAY_SIZE(FPU_REGISTER_NAMES))))
@@ -950,6 +955,76 @@ static int set_vcpu_events(const CPUState *cpu)
955
return 0;
956
}
957
958
+static int get_mp_state(CPUState *cpu)
959
+{
960
+ X86CPU *x86cpu = X86_CPU(cpu);
961
+ CPUX86State *env = &x86cpu->env;
962
+ struct hv_register_assoc assoc = {
963
+ .name = HV_REGISTER_INTERNAL_ACTIVITY_STATE,
964
+ };
965
+ union hv_internal_activity_register activity;
966
+ int ret;
967
+
968
+ ret = mshv_get_generic_regs(cpu, &assoc, 1);
969
+ if (ret < 0) {
970
+ error_report("failed to get internal activity state");
971
+ return -1;
972
+ }
973
+
974
+ activity.as_uint64 = assoc.value.reg64;
975
+
976
+ /*
977
+ * map MSHV activity state to KVM mp_state values, which are used as the
978
+ * shared representation in env->mp_state and serialized by vmstate_x86_cpu.
979
+ */
980
+
981
+ if (activity.startup_suspend) {
982
+ env->mp_state = MSHV_MP_STATE_UNINITIALIZED;
983
+ } else if (activity.halt_suspend) {
984
+ env->mp_state = MSHV_MP_STATE_HALTED;
985
+ } else {
986
+ env->mp_state = MSHV_MP_STATE_RUNNABLE;
987
+ }
988
+
989
+ cpu->halted = (env->mp_state == MSHV_MP_STATE_HALTED);
990
+
991
+ return 0;
992
+}
993
+
994
+int mshv_arch_set_mp_state(const CPUState *cpu)
995
+{
996
+ X86CPU *x86cpu = X86_CPU(cpu);
997
+ CPUX86State *env = &x86cpu->env;
998
+ union hv_internal_activity_register activity = { 0 };
999
+ struct hv_register_assoc assoc = {
1000
+ .name = HV_REGISTER_INTERNAL_ACTIVITY_STATE,
1001
+ };
1002
+ int ret;
1003
+
1004
+ switch (env->mp_state) {
1005
+ case MSHV_MP_STATE_HALTED:
1006
+ activity.halt_suspend = 1;
1007
+ break;
1008
+ case MSHV_MP_STATE_UNINITIALIZED:
1009
+ case MSHV_MP_STATE_INIT_RECEIVED:
1010
+ activity.startup_suspend = 1;
1011
+ break;
1012
+ case MSHV_MP_STATE_RUNNABLE:
1013
+ default:
1014
+ break;
1015
+ }
1016
+
1017
+ assoc.value.reg64 = activity.as_uint64;
1018
+
1019
+ ret = mshv_set_generic_regs(cpu, &assoc, 1);
1020
+ if (ret < 0) {
1021
+ error_report("failed to set internal activity state");
1022
+ return -1;
1023
+ }
1024
+
1025
+ return 0;
1026
+}
1027
+
1028
static int update_hflags(CPUState *cpu)
1029
{
1030
X86CPU *x86cpu = X86_CPU(cpu);
@@ -1012,6 +1087,11 @@ int mshv_arch_load_vcpu_state(CPUState *cpu)
1087
return ret;
1088
}
1089
1090
+ ret = get_mp_state(cpu);
1091
+ if (ret < 0) {
1092
+ return ret;
1093
+ }
1094
+
1095
return 0;
1096
}
1097