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 <[email protected]> --- accel/mshv/mshv-all.c | 10 +++++ include/system/mshv_int.h | 1 + target/i386/mshv/mshv-cpu.c | 80 +++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c index 3927a82925..45fe1ef468 100644 --- a/accel/mshv/mshv-all.c +++ b/accel/mshv/mshv-all.c @@ -205,6 +205,7 @@ static int mshv_load_setup(QEMUFile *f, void *opaque, Error **errp) static int mshv_load_cleanup(void *opaque) { MshvState *s = opaque; + CPUState *cpu; int ret; ret = mshv_arch_set_partition_msrs(first_cpu); @@ -213,6 +214,15 @@ static int mshv_load_cleanup(void *opaque) return -1; } + CPU_FOREACH(cpu) { + ret = mshv_arch_set_mp_state(cpu); + if (ret < 0) { + error_report("Failed to set mp state for vCPU %d: %s", + cpu->cpu_index, strerror(-ret)); + return -1; + } + } + resume_vm(s->vm); return 0; diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h index bc16b794b2..c24efc8675 100644 --- a/include/system/mshv_int.h +++ b/include/system/mshv_int.h @@ -98,6 +98,7 @@ int mshv_get_generic_regs(CPUState *cpu, hv_register_assoc *assocs, int mshv_arch_store_vcpu_state(const CPUState *cpu); int mshv_arch_load_vcpu_state(CPUState *cpu); int mshv_arch_set_partition_msrs(const CPUState *cpu); +int mshv_arch_set_mp_state(const CPUState *cpu); void mshv_arch_init_vcpu(CPUState *cpu); void mshv_arch_destroy_vcpu(CPUState *cpu); void mshv_arch_amend_proc_features( diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c index 80e5dd5a4b..c2c217372a 100644 --- a/target/i386/mshv/mshv-cpu.c +++ b/target/i386/mshv/mshv-cpu.c @@ -33,6 +33,11 @@ #include <sys/ioctl.h> +#define MSHV_MP_STATE_RUNNABLE 0 +#define MSHV_MP_STATE_UNINITIALIZED 1 +#define MSHV_MP_STATE_INIT_RECEIVED 2 +#define MSHV_MP_STATE_HALTED 3 + #define MAX_REGISTER_COUNT (MAX_CONST(ARRAY_SIZE(STANDARD_REGISTER_NAMES), \ MAX_CONST(ARRAY_SIZE(SPECIAL_REGISTER_NAMES), \ ARRAY_SIZE(FPU_REGISTER_NAMES)))) @@ -814,6 +819,76 @@ static int set_vcpu_events(const CPUState *cpu) return 0; } +static int get_mp_state(CPUState *cpu) +{ + X86CPU *x86cpu = X86_CPU(cpu); + CPUX86State *env = &x86cpu->env; + struct hv_register_assoc assoc = { + .name = HV_REGISTER_INTERNAL_ACTIVITY_STATE, + }; + union hv_internal_activity_register activity; + int ret; + + ret = mshv_get_generic_regs(cpu, &assoc, 1); + if (ret < 0) { + error_report("failed to get internal activity state"); + return -1; + } + + activity.as_uint64 = assoc.value.reg64; + + /* + * map MSHV activity state to KVM mp_state values, which are used as the + * shared representation in env->mp_state and serialized by vmstate_x86_cpu. + */ + + if (activity.startup_suspend) { + env->mp_state = MSHV_MP_STATE_UNINITIALIZED; + } else if (activity.halt_suspend) { + env->mp_state = MSHV_MP_STATE_HALTED; + } else { + env->mp_state = MSHV_MP_STATE_RUNNABLE; + } + + cpu->halted = (env->mp_state == MSHV_MP_STATE_HALTED); + + return 0; +} + +int mshv_arch_set_mp_state(const CPUState *cpu) +{ + X86CPU *x86cpu = X86_CPU(cpu); + CPUX86State *env = &x86cpu->env; + union hv_internal_activity_register activity = { 0 }; + struct hv_register_assoc assoc = { + .name = HV_REGISTER_INTERNAL_ACTIVITY_STATE, + }; + int ret; + + switch (env->mp_state) { + case MSHV_MP_STATE_HALTED: + activity.halt_suspend = 1; + break; + case MSHV_MP_STATE_UNINITIALIZED: + case MSHV_MP_STATE_INIT_RECEIVED: + activity.startup_suspend = 1; + break; + case MSHV_MP_STATE_RUNNABLE: + default: + break; + } + + assoc.value.reg64 = activity.as_uint64; + + ret = mshv_set_generic_regs(cpu, &assoc, 1); + if (ret < 0) { + error_report("failed to set internal activity state"); + return -1; + } + + return 0; +} + static int update_hflags(CPUState *cpu) { X86CPU *x86cpu = X86_CPU(cpu); @@ -876,6 +951,11 @@ int mshv_arch_load_vcpu_state(CPUState *cpu) return ret; } + ret = get_mp_state(cpu); + if (ret < 0) { + return ret; + } + return 0; } -- 2.34.1
