@samitouri / QOSamiQemu / commits / 62e961af8f

target/i386/mshv: impl init/load/store_vcpu_state

In migration we will handle more than registers, so we rework the routines that were used to load & store CPU registers from/to the hypervisor into more explicit init/load/store_vcpu_state() functions that can be called from the appropriate hooks. load/store_regs() still exists for the purpose of MMIO emulation, but it will only address standard and special x86 registers. Functions to retrieve FPU and XCR0 state from the hypervsisor have been introduced. MSR and APIC state covered are covered only as part of init_vcpu(). They are not yet part of the load/store routines. Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com> Link: https://lore.kernel.org/r/20260417105618.3621-4-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Magnus Kulke committed Apr 17, 2026 at 12:55 UTC 62e961af8feb886df7e0405cad3b218a00906f33
3 files changed +185 -184
accel/mshv/mshv-all.c
+5 -5
@@ -479,13 +479,13 @@ static int mshv_init_vcpu(CPUState *cpu)
479 int ret;
480
481 cpu->accel = g_new0(AccelCPUState, 1);
482 - mshv_arch_init_vcpu(cpu);
482
483 ret = mshv_create_vcpu(vm_fd, vp_index, &cpu->accel->cpufd);
484 if (ret < 0) {
485 return -1;
486 }
487
488 + mshv_arch_init_vcpu(cpu);
489 cpu->accel->dirty = true;
490
491 return 0;
@@ -567,7 +567,7 @@ static int mshv_cpu_exec(CPUState *cpu)
567
568 do {
569 if (cpu->accel->dirty) {
570 - ret = mshv_arch_put_registers(cpu);
570 + ret = mshv_arch_store_vcpu_state(cpu);
571 if (ret) {
572 error_report("Failed to put registers after init: %s",
573 strerror(-ret));
@@ -689,7 +689,7 @@ static void mshv_start_vcpu_thread(CPUState *cpu)
689 static void do_mshv_cpu_synchronize_post_init(CPUState *cpu,
690 run_on_cpu_data arg)
691 {
692 - int ret = mshv_arch_put_registers(cpu);
692 + int ret = mshv_arch_store_vcpu_state(cpu);
693 if (ret < 0) {
694 error_report("Failed to put registers after init: %s", strerror(-ret));
695 abort();
@@ -705,7 +705,7 @@ static void mshv_cpu_synchronize_post_init(CPUState *cpu)
705
706 static void mshv_cpu_synchronize_post_reset(CPUState *cpu)
707 {
708 - int ret = mshv_arch_put_registers(cpu);
708 + int ret = mshv_arch_store_vcpu_state(cpu);
709 if (ret) {
710 error_report("Failed to put registers after reset: %s",
711 strerror(-ret));
@@ -729,7 +729,7 @@ static void mshv_cpu_synchronize_pre_loadvm(CPUState *cpu)
729 static void do_mshv_cpu_synchronize(CPUState *cpu, run_on_cpu_data arg)
730 {
731 if (!cpu->accel->dirty) {
732 - int ret = mshv_arch_load_regs(cpu);
732 + int ret = mshv_arch_load_vcpu_state(cpu);
733 if (ret < 0) {
734 error_report("Failed to load registers for vcpu %d",
735 cpu->cpu_index);
include/system/mshv_int.h
+2 -3
@@ -70,11 +70,10 @@ int mshv_create_vcpu(int vm_fd, uint8_t vp_index, int *cpu_fd);
70 void mshv_remove_vcpu(int vm_fd, int cpu_fd);
71 int mshv_configure_vcpu(const CPUState *cpu);
72 int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit);
73 -int mshv_arch_load_regs(CPUState *cpu);
74 -int mshv_arch_store_regs(CPUState *cpu);
73 int mshv_set_generic_regs(const CPUState *cpu, const hv_register_assoc *assocs,
74 size_t n_regs);
77 -int mshv_arch_put_registers(const CPUState *cpu);
75 +int mshv_arch_store_vcpu_state(const CPUState *cpu);
76 +int mshv_arch_load_vcpu_state(CPUState *cpu);
77 void mshv_arch_init_vcpu(CPUState *cpu);
78 void mshv_arch_destroy_vcpu(CPUState *cpu);
79 void mshv_arch_amend_proc_features(
target/i386/mshv/mshv-cpu.c
+178 -176
@@ -115,6 +115,92 @@ static int get_generic_regs(CPUState *cpu,
115 struct hv_register_assoc *assocs,
116 size_t n_regs);
117
118 +static void populate_fpu(const hv_register_assoc *assocs, X86CPU *x86cpu)
119 +{
120 + union hv_register_value value;
121 + const union hv_x64_fp_control_status_register *ctrl_status;
122 + const union hv_x64_xmm_control_status_register *xmm_ctrl;
123 + CPUX86State *env = &x86cpu->env;
124 + size_t i, fp_i;
125 + bool valid;
126 +
127 + /* first 16 registers are xmm0-xmm15 */
128 + for (i = 0; i < 16; i++) {
129 + value = assocs[i].value;
130 + env->xmm_regs[i].ZMM_Q(0) = value.reg128.low_part;
131 + env->xmm_regs[i].ZMM_Q(1) = value.reg128.high_part;
132 + }
133 +
134 + /* next 8 registers are fp_mmx0-fp_mmx7 */
135 + for (i = 16; i < 24; i++) {
136 + fp_i = i - 16;
137 + value = assocs[i].value;
138 + env->fpregs[fp_i].d.low = value.fp.mantissa;
139 + env->fpregs[fp_i].d.high = (value.fp.sign << 15)
140 + | (value.fp.biased_exponent & 0x7FFF);
141 + }
142 +
143 + /* last two registers are fp_control_status and xmm_control_status */
144 + ctrl_status = &assocs[24].value.fp_control_status;
145 + env->fpuc = ctrl_status->fp_control;
146 +
147 + env->fpus = ctrl_status->fp_status & ~0x3800;
148 + /* bits 11,12,13 are the top of stack pointer */
149 + env->fpstt = (ctrl_status->fp_status >> 11) & 0x7;
150 +
151 + for (i = 0; i < 8; i++) {
152 + valid = ctrl_status->fp_tag & (1 << i);
153 + env->fptags[i] = valid ? 0 : 1;
154 + }
155 +
156 + env->fpop = ctrl_status->last_fp_op;
157 + env->fpip = ctrl_status->last_fp_rip;
158 +
159 + xmm_ctrl = &assocs[25].value.xmm_control_status;
160 + env->mxcsr = xmm_ctrl->xmm_status_control;
161 + env->fpdp = xmm_ctrl->last_fp_rdp;
162 +}
163 +
164 +static int get_fpu(CPUState *cpu)
165 +{
166 + struct hv_register_assoc assocs[ARRAY_SIZE(FPU_REGISTER_NAMES)];
167 + int ret;
168 + X86CPU *x86cpu = X86_CPU(cpu);
169 + size_t n_regs = ARRAY_SIZE(FPU_REGISTER_NAMES);
170 +
171 + for (size_t i = 0; i < n_regs; i++) {
172 + assocs[i].name = FPU_REGISTER_NAMES[i];
173 + }
174 + ret = get_generic_regs(cpu, assocs, n_regs);
175 + if (ret < 0) {
176 + error_report("failed to get special registers");
177 + return -errno;
178 + }
179 +
180 + populate_fpu(assocs, x86cpu);
181 +
182 + return 0;
183 +}
184 +
185 +static int get_xc_reg(CPUState *cpu)
186 +{
187 + int ret;
188 + X86CPU *x86cpu = X86_CPU(cpu);
189 + CPUX86State *env = &x86cpu->env;
190 + struct hv_register_assoc assocs[1];
191 +
192 + assocs[0].name = HV_X64_REGISTER_XFEM;
193 +
194 + ret = get_generic_regs(cpu, assocs, 1);
195 + if (ret < 0) {
196 + error_report("failed to get xcr0");
197 + return -1;
198 + }
199 + env->xcr0 = assocs[0].value.reg64;
200 +
201 + return 0;
202 +}
203 +
204 static int translate_gva(const CPUState *cpu, uint64_t gva, uint64_t *gpa,
205 uint64_t flags)
206 {
@@ -293,7 +379,7 @@ static int set_standard_regs(const CPUState *cpu)
379 return 0;
380 }
381
296 -int mshv_arch_store_regs(CPUState *cpu)
382 +static int store_regs(CPUState *cpu)
383 {
384 int ret;
385
@@ -435,20 +521,45 @@ static int get_special_regs(CPUState *cpu)
521 return 0;
522 }
523
438 -int mshv_arch_load_regs(CPUState *cpu)
524 +static int load_regs(CPUState *cpu)
525 {
526 int ret;
527
528 ret = get_standard_regs(cpu);
529 if (ret < 0) {
444 - error_report("Failed to load standard registers");
445 - return -1;
530 + return ret;
531 }
532
533 ret = get_special_regs(cpu);
534 if (ret < 0) {
450 - error_report("Failed to load special registers");
451 - return -1;
535 + return ret;
536 + }
537 +
538 + return 0;
539 +}
540 +
541 +int mshv_arch_load_vcpu_state(CPUState *cpu)
542 +{
543 + int ret;
544 +
545 + ret = get_standard_regs(cpu);
546 + if (ret < 0) {
547 + return ret;
548 + }
549 +
550 + ret = get_special_regs(cpu);
551 + if (ret < 0) {
552 + return ret;
553 + }
554 +
555 + ret = get_xc_reg(cpu);
556 + if (ret < 0) {
557 + return ret;
558 + }
559 +
560 + ret = get_fpu(cpu);
561 + if (ret < 0) {
562 + return ret;
563 }
564
565 return 0;
@@ -667,7 +778,7 @@ static int register_intercept_result_cpuid(const CPUState *cpu,
778 return ret;
779 }
780
670 -static int set_cpuid2(const CPUState *cpu)
781 +static int init_cpuid2(const CPUState *cpu)
782 {
783 int ret;
784 size_t n_entries, cpuid_size;
@@ -858,29 +969,6 @@ static int set_xc_reg(const CPUState *cpu)
969 return 0;
970 }
971
861 -static int set_cpu_state(const CPUState *cpu)
862 -{
863 - int ret;
864 -
865 - ret = set_standard_regs(cpu);
866 - if (ret < 0) {
867 - return ret;
868 - }
869 - ret = set_special_regs(cpu);
870 - if (ret < 0) {
871 - return ret;
872 - }
873 - ret = set_fpu(cpu);
874 - if (ret < 0) {
875 - return ret;
876 - }
877 - ret = set_xc_reg(cpu);
878 - if (ret < 0) {
879 - return ret;
880 - }
881 - return 0;
882 -}
883 -
972 static int get_vp_state(int cpu_fd, struct mshv_get_set_vp_state *state)
973 {
974 int ret;
@@ -894,7 +982,7 @@ static int get_vp_state(int cpu_fd, struct mshv_get_set_vp_state *state)
982 return 0;
983 }
984
897 -static int get_lapic(int cpu_fd,
985 +static int get_lapic(const CPUState *cpu,
986 struct hv_local_interrupt_controller_state *state)
987 {
988 int ret;
@@ -902,6 +990,7 @@ static int get_lapic(int cpu_fd,
990 /* buffer aligned to 4k, as *state requires that */
991 void *buffer = qemu_memalign(size, size);
992 struct mshv_get_set_vp_state mshv_state = { 0 };
993 + int cpu_fd = mshv_vcpufd(cpu);
994
995 mshv_state.buf_ptr = (uint64_t) buffer;
996 mshv_state.buf_sz = size;
@@ -938,7 +1027,7 @@ static int set_vp_state(int cpu_fd, const struct mshv_get_set_vp_state *state)
1027 return 0;
1028 }
1029
941 -static int set_lapic(int cpu_fd,
1030 +static int set_lapic(const CPUState *cpu,
1031 const struct hv_local_interrupt_controller_state *state)
1032 {
1033 int ret;
@@ -946,6 +1035,7 @@ static int set_lapic(int cpu_fd,
1035 /* buffer aligned to 4k, as *state requires that */
1036 void *buffer = qemu_memalign(size, size);
1037 struct mshv_get_set_vp_state mshv_state = { 0 };
1038 + int cpu_fd = mshv_vcpufd(cpu);
1039
1040 if (!state) {
1041 error_report("lapic state is NULL");
@@ -967,13 +1057,13 @@ static int set_lapic(int cpu_fd,
1057 return 0;
1058 }
1059
970 -static int set_lint(int cpu_fd)
1060 +static int init_lint(const CPUState *cpu)
1061 {
1062 int ret;
1063 uint32_t *lvt_lint0, *lvt_lint1;
1064
1065 struct hv_local_interrupt_controller_state lapic_state = { 0 };
976 - ret = get_lapic(cpu_fd, &lapic_state);
1066 + ret = get_lapic(cpu, &lapic_state);
1067 if (ret < 0) {
1068 return ret;
1069 }
@@ -986,161 +1076,31 @@ static int set_lint(int cpu_fd)
1076
1077 /* TODO: should we skip setting lapic if the values are the same? */
1078
989 - return set_lapic(cpu_fd, &lapic_state);
990 -}
991 -
992 -static int setup_msrs(const CPUState *cpu)
993 -{
994 - int ret;
995 - uint64_t default_type = MSR_MTRR_ENABLE | MSR_MTRR_MEM_TYPE_WB;
996 -
997 - /* boot msr entries */
998 - MshvMsrEntry msrs[9] = {
999 - { .index = IA32_MSR_SYSENTER_CS, .data = 0x0, },
1000 - { .index = IA32_MSR_SYSENTER_ESP, .data = 0x0, },
1001 - { .index = IA32_MSR_SYSENTER_EIP, .data = 0x0, },
1002 - { .index = IA32_MSR_STAR, .data = 0x0, },
1003 - { .index = IA32_MSR_CSTAR, .data = 0x0, },
1004 - { .index = IA32_MSR_LSTAR, .data = 0x0, },
1005 - { .index = IA32_MSR_KERNEL_GS_BASE, .data = 0x0, },
1006 - { .index = IA32_MSR_SFMASK, .data = 0x0, },
1007 - { .index = IA32_MSR_MTRR_DEF_TYPE, .data = default_type, },
1008 - };
1009 -
1010 - ret = mshv_configure_msr(cpu, msrs, 9);
1011 - if (ret < 0) {
1012 - error_report("failed to setup msrs");
1013 - return -1;
1014 - }
1015 -
1016 - return 0;
1079 + return set_lapic(cpu, &lapic_state);
1080 }
1081
1019 -/*
1020 - * TODO: populate topology info:
1021 - *
1022 - * X86CPU *x86cpu = X86_CPU(cpu);
1023 - * CPUX86State *env = &x86cpu->env;
1024 - * X86CPUTopoInfo *topo_info = &env->topo_info;
1025 - */
1026 -int mshv_configure_vcpu(const CPUState *cpu)
1082 +int mshv_arch_store_vcpu_state(const CPUState *cpu)
1083 {
1084 int ret;
1029 - int cpu_fd = mshv_vcpufd(cpu);
1030 -
1031 - ret = set_cpuid2(cpu);
1032 - if (ret < 0) {
1033 - error_report("failed to set cpuid");
1034 - return -1;
1035 - }
1036 -
1037 - ret = setup_msrs(cpu);
1038 - if (ret < 0) {
1039 - error_report("failed to setup msrs");
1040 - return -1;
1041 - }
1042 -
1043 - ret = set_cpu_state(cpu);
1044 - if (ret < 0) {
1045 - error_report("failed to set cpu state");
1046 - return -1;
1047 - }
1085
1049 - ret = set_lint(cpu_fd);
1086 + ret = set_standard_regs(cpu);
1087 if (ret < 0) {
1051 - error_report("failed to set lpic int");
1052 - return -1;
1088 + return ret;
1089 }
1090
1055 - return 0;
1056 -}
1057 -
1058 -static int put_regs(const CPUState *cpu)
1059 -{
1060 - int ret;
1061 -
1062 - ret = mshv_configure_vcpu(cpu);
1091 + ret = set_special_regs(cpu);
1092 if (ret < 0) {
1064 - error_report("failed to configure vcpu");
1093 return ret;
1094 }
1095
1068 - return 0;
1069 -}
1070 -
1071 -struct MsrPair {
1072 - uint32_t index;
1073 - uint64_t value;
1074 -};
1075 -
1076 -static int put_msrs(const CPUState *cpu)
1077 -{
1078 - int ret = 0;
1079 - X86CPU *x86cpu = X86_CPU(cpu);
1080 - CPUX86State *env = &x86cpu->env;
1081 - MshvMsrEntries *msrs = g_malloc0(sizeof(MshvMsrEntries));
1082 -
1083 - struct MsrPair pairs[] = {
1084 - { MSR_IA32_SYSENTER_CS, env->sysenter_cs },
1085 - { MSR_IA32_SYSENTER_ESP, env->sysenter_esp },
1086 - { MSR_IA32_SYSENTER_EIP, env->sysenter_eip },
1087 - { MSR_EFER, env->efer },
1088 - { MSR_PAT, env->pat },
1089 - { MSR_STAR, env->star },
1090 - { MSR_CSTAR, env->cstar },
1091 - { MSR_LSTAR, env->lstar },
1092 - { MSR_KERNELGSBASE, env->kernelgsbase },
1093 - { MSR_FMASK, env->fmask },
1094 - { MSR_MTRRdefType, env->mtrr_deftype },
1095 - { MSR_VM_HSAVE_PA, env->vm_hsave },
1096 - { MSR_SMI_COUNT, env->msr_smi_count },
1097 - { MSR_IA32_PKRS, env->pkrs },
1098 - { MSR_IA32_BNDCFGS, env->msr_bndcfgs },
1099 - { MSR_IA32_XSS, env->xss },
1100 - { MSR_IA32_UMWAIT_CONTROL, env->umwait },
1101 - { MSR_IA32_TSX_CTRL, env->tsx_ctrl },
1102 - { MSR_AMD64_TSC_RATIO, env->amd_tsc_scale_msr },
1103 - { MSR_TSC_AUX, env->tsc_aux },
1104 - { MSR_TSC_ADJUST, env->tsc_adjust },
1105 - { MSR_IA32_SMBASE, env->smbase },
1106 - { MSR_IA32_SPEC_CTRL, env->spec_ctrl },
1107 - { MSR_VIRT_SSBD, env->virt_ssbd },
1108 - };
1109 -
1110 - if (ARRAY_SIZE(pairs) > MSHV_MSR_ENTRIES_COUNT) {
1111 - error_report("MSR entries exceed maximum size");
1112 - g_free(msrs);
1113 - return -1;
1114 - }
1115 -
1116 - for (size_t i = 0; i < ARRAY_SIZE(pairs); i++) {
1117 - MshvMsrEntry *entry = &msrs->entries[i];
1118 - entry->index = pairs[i].index;
1119 - entry->reserved = 0;
1120 - entry->data = pairs[i].value;
1121 - msrs->nmsrs++;
1122 - }
1123 -
1124 - ret = mshv_configure_msr(cpu, &msrs->entries[0], msrs->nmsrs);
1125 - g_free(msrs);
1126 - return ret;
1127 -}
1128 -
1129 -
1130 -int mshv_arch_put_registers(const CPUState *cpu)
1131 -{
1132 - int ret;
1133 -
1134 - ret = put_regs(cpu);
1096 + ret = set_xc_reg(cpu);
1097 if (ret < 0) {
1136 - error_report("Failed to put registers");
1137 - return -1;
1098 + return ret;
1099 }
1100
1140 - ret = put_msrs(cpu);
1101 + ret = set_fpu(cpu);
1102 if (ret < 0) {
1142 - error_report("Failed to put msrs");
1143 - return -1;
1103 + return ret;
1104 }
1105
1106 return 0;
@@ -1182,7 +1142,7 @@ static int emulate_instruction(CPUState *cpu,
1142 int ret;
1143 x86_insn_stream stream = { .bytes = insn_bytes, .len = insn_len };
1144
1185 - ret = mshv_arch_load_regs(cpu);
1145 + ret = load_regs(cpu);
1146 if (ret < 0) {
1147 error_report("Failed to load registers");
1148 return -1;
@@ -1191,7 +1151,7 @@ static int emulate_instruction(CPUState *cpu,
1151 decode_instruction_stream(env, &decode, &stream);
1152 exec_instruction(env, &decode);
1153
1194 - ret = mshv_arch_store_regs(cpu);
1154 + ret = store_regs(cpu);
1155 if (ret < 0) {
1156 error_report("failed to store registers");
1157 return -1;
@@ -1489,7 +1449,7 @@ static int handle_pio_str(CPUState *cpu, hv_x64_io_port_intercept_message *info)
1449 X86CPU *x86_cpu = X86_CPU(cpu);
1450 CPUX86State *env = &x86_cpu->env;
1451
1492 - ret = mshv_arch_load_regs(cpu);
1452 + ret = load_regs(cpu);
1453 if (ret < 0) {
1454 error_report("Failed to load registers");
1455 return -1;
@@ -1660,6 +1620,33 @@ void mshv_init_mmio_emu(void)
1620 init_emu(&mshv_x86_emul_ops);
1621 }
1622
1623 +static int init_msrs(const CPUState *cpu)
1624 +{
1625 + int ret;
1626 + uint64_t d_t = MSR_MTRR_ENABLE | MSR_MTRR_MEM_TYPE_WB;
1627 +
1628 + const struct hv_register_assoc assocs[] = {
1629 + { .name = HV_X64_REGISTER_SYSENTER_CS, .value.reg64 = 0x0 },
1630 + { .name = HV_X64_REGISTER_SYSENTER_ESP, .value.reg64 = 0x0 },
1631 + { .name = HV_X64_REGISTER_SYSENTER_EIP, .value.reg64 = 0x0 },
1632 + { .name = HV_X64_REGISTER_STAR, .value.reg64 = 0x0 },
1633 + { .name = HV_X64_REGISTER_CSTAR, .value.reg64 = 0x0 },
1634 + { .name = HV_X64_REGISTER_LSTAR, .value.reg64 = 0x0 },
1635 + { .name = HV_X64_REGISTER_KERNEL_GS_BASE, .value.reg64 = 0x0 },
1636 + { .name = HV_X64_REGISTER_SFMASK, .value.reg64 = 0x0 },
1637 + { .name = HV_X64_REGISTER_MSR_MTRR_DEF_TYPE, .value.reg64 = d_t },
1638 + };
1639 + QEMU_BUILD_BUG_ON(ARRAY_SIZE(assocs) > MSHV_MSR_ENTRIES_COUNT);
1640 +
1641 + ret = mshv_set_generic_regs(cpu, assocs, ARRAY_SIZE(assocs));
1642 + if (ret < 0) {
1643 + error_report("failed to put msrs");
1644 + return -1;
1645 + }
1646 +
1647 + return 0;
1648 +}
1649 +
1650 void mshv_arch_init_vcpu(CPUState *cpu)
1651 {
1652 X86CPU *x86_cpu = X86_CPU(cpu);
@@ -1667,6 +1654,7 @@ void mshv_arch_init_vcpu(CPUState *cpu)
1654 AccelCPUState *state = cpu->accel;
1655 size_t page = HV_HYP_PAGE_SIZE;
1656 void *mem = qemu_memalign(page, 2 * page);
1657 + int ret;
1658
1659 /* sanity check, to make sure we don't overflow the page */
1660 QEMU_BUILD_BUG_ON((MAX_REGISTER_COUNT
@@ -1679,6 +1667,20 @@ void mshv_arch_init_vcpu(CPUState *cpu)
1667 state->hvcall_args.output_page = (uint8_t *)mem + page;
1668
1669 env->emu_mmio_buf = g_new(char, 4096);
1670 +
1671 + /*
1672 + * TODO: populate topology info:
1673 + * X86CPUTopoInfo *topo_info = &env->topo_info;
1674 + */
1675 +
1676 + ret = init_cpuid2(cpu);
1677 + assert(ret == 0);
1678 +
1679 + ret = init_msrs(cpu);
1680 + assert(ret == 0);
1681 +
1682 + ret = init_lint(cpu);
1683 + assert(ret == 0);
1684 }
1685
1686 void mshv_arch_destroy_vcpu(CPUState *cpu)