@samitouri / QOSamiQemu / commits / d540dcc5e2

target/i386/mshv: migrate MSRs

In this change the we rewrite the existing MSR logic to make MSRs migratable: - we map them on existing QEMU fields in the CPU. A table and a macro MSHV_ENV_FIELD is used to associate a HV register name to the their msr index and their offset in the cpu state struct. The list is not exhaustive and will be extended in follow-up commits. - mshv_set/get_msrs() fns are called in the arch_load/store_vcpu_state() fns. they use use generic registers ioctl's and map the input/output via load/store_to/from_env() from/to the hv register content to the cpu state representation. - init_msrs() has been moved from mshv-vcpu to the msr source file - we need to perform some filtering of MSR because before writing and reading, because the hvcalls will fail if the partition doesn't support a given MSRs. - Some MSRs are partition-wide and so we will only write the to on the BSP. Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com> Link: https://lore.kernel.org/r/20260417105618.3621-21-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Magnus Kulke committed Apr 17, 2026 at 12:56 UTC d540dcc5e28c206d1091090b1ed0eebd5dd3ddff
4 files changed +252 -367
include/hw/hyperv/hvgdk_mini.h
+14
@@ -9,6 +9,19 @@
9
10 #define MSHV_IOCTL 0xB8
11
12 +/* Hyper-V specific model specific registers (MSRs) */
13 +
14 +/* HV_X64_SYNTHETIC_MSR */
15 +#define HV_X64_MSR_GUEST_OS_ID 0x40000000
16 +#define HV_X64_MSR_HYPERCALL 0x40000001
17 +#define HV_X64_MSR_VP_INDEX 0x40000002
18 +#define HV_X64_MSR_RESET 0x40000003
19 +#define HV_X64_MSR_VP_RUNTIME 0x40000010
20 +#define HV_X64_MSR_TIME_REF_COUNT 0x40000020
21 +#define HV_X64_MSR_REFERENCE_TSC 0x40000021
22 +#define HV_X64_MSR_TSC_FREQUENCY 0x40000022
23 +#define HV_X64_MSR_APIC_FREQUENCY 0x40000023
24 +
25 typedef enum hv_register_name {
26 /* Pending Interruption Register */
27 HV_REGISTER_PENDING_INTERRUPTION = 0x00010002,
@@ -161,6 +174,7 @@ typedef enum hv_register_name {
174 HV_X64_REGISTER_MSR_IA32_MISC_ENABLE = 0x000800A0,
175
176 /* Misc */
177 + HV_X64_REGISTER_HYPERCALL = 0x00090001,
178 HV_REGISTER_GUEST_OS_ID = 0x00090002,
179 HV_REGISTER_REFERENCE_TSC = 0x00090017,
180
include/system/mshv_int.h
+3 -13
@@ -129,18 +129,8 @@ bool mshv_log_global_start(MemoryListener *listener, Error **errp);
129 void mshv_log_global_stop(MemoryListener *listener);
130
131 /* msr */
132 -typedef struct MshvMsrEntry {
133 - uint32_t index;
134 - uint32_t reserved;
135 - uint64_t data;
136 -} MshvMsrEntry;
137 -
138 -typedef struct MshvMsrEntries {
139 - MshvMsrEntry entries[MSHV_MSR_ENTRIES_COUNT];
140 - uint32_t nmsrs;
141 -} MshvMsrEntries;
142 -
143 -int mshv_configure_msr(const CPUState *cpu, const MshvMsrEntry *msrs,
144 - size_t n_msrs);
132 +int mshv_init_msrs(const CPUState *cpu);
133 +int mshv_get_msrs(CPUState *cpu);
134 +int mshv_set_msrs(const CPUState *cpu);
135
136 #endif
target/i386/mshv/mshv-cpu.c
+11 -28
@@ -802,6 +802,11 @@ int mshv_arch_load_vcpu_state(CPUState *cpu)
802 return ret;
803 }
804
805 + ret = mshv_get_msrs(cpu);
806 + if (ret < 0) {
807 + return ret;
808 + }
809 +
810 ret = get_xsave_state(cpu);
811 if (ret < 0) {
812 return ret;
@@ -1353,6 +1358,11 @@ int mshv_arch_store_vcpu_state(const CPUState *cpu)
1358 return ret;
1359 }
1360
1361 + ret = mshv_set_msrs(cpu);
1362 + if (ret < 0) {
1363 + return ret;
1364 + }
1365 +
1366 ret = set_xsave_state(cpu);
1367 if (ret < 0) {
1368 return ret;
@@ -1880,33 +1890,6 @@ void mshv_init_mmio_emu(void)
1890 init_emu(&mshv_x86_emul_ops);
1891 }
1892
1883 -static int init_msrs(const CPUState *cpu)
1884 -{
1885 - int ret;
1886 - uint64_t d_t = MSR_MTRR_ENABLE | MSR_MTRR_MEM_TYPE_WB;
1887 -
1888 - const struct hv_register_assoc assocs[] = {
1889 - { .name = HV_X64_REGISTER_SYSENTER_CS, .value.reg64 = 0x0 },
1890 - { .name = HV_X64_REGISTER_SYSENTER_ESP, .value.reg64 = 0x0 },
1891 - { .name = HV_X64_REGISTER_SYSENTER_EIP, .value.reg64 = 0x0 },
1892 - { .name = HV_X64_REGISTER_STAR, .value.reg64 = 0x0 },
1893 - { .name = HV_X64_REGISTER_CSTAR, .value.reg64 = 0x0 },
1894 - { .name = HV_X64_REGISTER_LSTAR, .value.reg64 = 0x0 },
1895 - { .name = HV_X64_REGISTER_KERNEL_GS_BASE, .value.reg64 = 0x0 },
1896 - { .name = HV_X64_REGISTER_SFMASK, .value.reg64 = 0x0 },
1897 - { .name = HV_X64_REGISTER_MSR_MTRR_DEF_TYPE, .value.reg64 = d_t },
1898 - };
1899 - QEMU_BUILD_BUG_ON(ARRAY_SIZE(assocs) > MSHV_MSR_ENTRIES_COUNT);
1900 -
1901 - ret = mshv_set_generic_regs(cpu, assocs, ARRAY_SIZE(assocs));
1902 - if (ret < 0) {
1903 - error_report("failed to put msrs");
1904 - return -1;
1905 - }
1906 -
1907 - return 0;
1908 -}
1909 -
1893 void mshv_arch_init_vcpu(CPUState *cpu)
1894 {
1895 X86CPU *x86_cpu = X86_CPU(cpu);
@@ -1948,7 +1931,7 @@ void mshv_arch_init_vcpu(CPUState *cpu)
1931 ret = init_cpuid2(cpu);
1932 assert(ret == 0);
1933
1951 - ret = init_msrs(cpu);
1934 + ret = mshv_init_msrs(cpu);
1935 assert(ret == 0);
1936
1937 ret = init_lint(cpu);
target/i386/mshv/msr.c
+224 -326
@@ -14,362 +14,260 @@
14 #include "hw/hyperv/hvgdk_mini.h"
15 #include "linux/mshv.h"
16 #include "qemu/error-report.h"
17 +#include "cpu.h"
18
18 -static uint32_t supported_msrs[64] = {
19 - IA32_MSR_TSC,
20 - IA32_MSR_EFER,
21 - IA32_MSR_KERNEL_GS_BASE,
22 - IA32_MSR_APIC_BASE,
23 - IA32_MSR_PAT,
24 - IA32_MSR_SYSENTER_CS,
25 - IA32_MSR_SYSENTER_ESP,
26 - IA32_MSR_SYSENTER_EIP,
27 - IA32_MSR_STAR,
28 - IA32_MSR_LSTAR,
29 - IA32_MSR_CSTAR,
30 - IA32_MSR_SFMASK,
31 - IA32_MSR_MTRR_DEF_TYPE,
32 - IA32_MSR_MTRR_PHYSBASE0,
33 - IA32_MSR_MTRR_PHYSMASK0,
34 - IA32_MSR_MTRR_PHYSBASE1,
35 - IA32_MSR_MTRR_PHYSMASK1,
36 - IA32_MSR_MTRR_PHYSBASE2,
37 - IA32_MSR_MTRR_PHYSMASK2,
38 - IA32_MSR_MTRR_PHYSBASE3,
39 - IA32_MSR_MTRR_PHYSMASK3,
40 - IA32_MSR_MTRR_PHYSBASE4,
41 - IA32_MSR_MTRR_PHYSMASK4,
42 - IA32_MSR_MTRR_PHYSBASE5,
43 - IA32_MSR_MTRR_PHYSMASK5,
44 - IA32_MSR_MTRR_PHYSBASE6,
45 - IA32_MSR_MTRR_PHYSMASK6,
46 - IA32_MSR_MTRR_PHYSBASE7,
47 - IA32_MSR_MTRR_PHYSMASK7,
48 - IA32_MSR_MTRR_FIX64K_00000,
49 - IA32_MSR_MTRR_FIX16K_80000,
50 - IA32_MSR_MTRR_FIX16K_A0000,
51 - IA32_MSR_MTRR_FIX4K_C0000,
52 - IA32_MSR_MTRR_FIX4K_C8000,
53 - IA32_MSR_MTRR_FIX4K_D0000,
54 - IA32_MSR_MTRR_FIX4K_D8000,
55 - IA32_MSR_MTRR_FIX4K_E0000,
56 - IA32_MSR_MTRR_FIX4K_E8000,
57 - IA32_MSR_MTRR_FIX4K_F0000,
58 - IA32_MSR_MTRR_FIX4K_F8000,
59 - IA32_MSR_TSC_AUX,
60 - IA32_MSR_DEBUG_CTL,
61 - HV_X64_MSR_GUEST_OS_ID,
62 - HV_X64_MSR_SINT0,
63 - HV_X64_MSR_SINT1,
64 - HV_X64_MSR_SINT2,
65 - HV_X64_MSR_SINT3,
66 - HV_X64_MSR_SINT4,
67 - HV_X64_MSR_SINT5,
68 - HV_X64_MSR_SINT6,
69 - HV_X64_MSR_SINT7,
70 - HV_X64_MSR_SINT8,
71 - HV_X64_MSR_SINT9,
72 - HV_X64_MSR_SINT10,
73 - HV_X64_MSR_SINT11,
74 - HV_X64_MSR_SINT12,
75 - HV_X64_MSR_SINT13,
76 - HV_X64_MSR_SINT14,
77 - HV_X64_MSR_SINT15,
78 - HV_X64_MSR_SCONTROL,
79 - HV_X64_MSR_SIEFP,
80 - HV_X64_MSR_SIMP,
81 - HV_X64_MSR_REFERENCE_TSC,
82 - HV_X64_MSR_EOM,
19 +#define MSHV_ENV_FIELD(env, offset) (*(uint64_t *)((char *)(env) + (offset)))
20 +
21 +typedef struct MshvMsrEnvMap {
22 + uint32_t msr_index;
23 + uint32_t hv_name;
24 + ptrdiff_t env_offset;
25 +} MshvMsrEnvMap;
26 +
27 +/* We assert that 64bit access to sysenter_cs is safe because of padding */
28 +QEMU_BUILD_BUG_ON(offsetof(CPUX86State, sysenter_esp) -
29 + offsetof(CPUX86State, sysenter_cs)
30 + < sizeof(uint64_t));
31 +
32 +/* Those MSRs have a direct mapping to fields in CPUX86State */
33 +static const MshvMsrEnvMap msr_env_map[] = {
34 + /* Architectural */
35 + { IA32_MSR_EFER, HV_X64_REGISTER_EFER, offsetof(CPUX86State, efer) },
36 + { IA32_MSR_PAT, HV_X64_REGISTER_PAT, offsetof(CPUX86State, pat) },
37 +
38 + /* Syscall */
39 + { IA32_MSR_SYSENTER_CS, HV_X64_REGISTER_SYSENTER_CS,
40 + offsetof(CPUX86State, sysenter_cs) },
41 + { IA32_MSR_SYSENTER_ESP, HV_X64_REGISTER_SYSENTER_ESP,
42 + offsetof(CPUX86State, sysenter_esp) },
43 + { IA32_MSR_SYSENTER_EIP, HV_X64_REGISTER_SYSENTER_EIP,
44 + offsetof(CPUX86State, sysenter_eip) },
45 + { IA32_MSR_STAR, HV_X64_REGISTER_STAR,
46 + offsetof(CPUX86State, star) },
47 + { IA32_MSR_LSTAR, HV_X64_REGISTER_LSTAR,
48 + offsetof(CPUX86State, lstar) },
49 + { IA32_MSR_CSTAR, HV_X64_REGISTER_CSTAR,
50 + offsetof(CPUX86State, cstar) },
51 + { IA32_MSR_SFMASK, HV_X64_REGISTER_SFMASK,
52 + offsetof(CPUX86State, fmask) },
53 + { IA32_MSR_KERNEL_GS_BASE, HV_X64_REGISTER_KERNEL_GS_BASE,
54 + offsetof(CPUX86State, kernelgsbase) },
55 +
56 + /* TSC-related */
57 + { IA32_MSR_TSC, HV_X64_REGISTER_TSC,
58 + offsetof(CPUX86State, tsc) },
59 + { IA32_MSR_TSC_AUX, HV_X64_REGISTER_TSC_AUX,
60 + offsetof(CPUX86State, tsc_aux) },
61 + { IA32_MSR_TSC_ADJUST, HV_X64_REGISTER_TSC_ADJUST,
62 + offsetof(CPUX86State, tsc_adjust) },
63 +
64 + /* Hyper-V per-partition MSRs */
65 + { HV_X64_MSR_HYPERCALL, HV_X64_REGISTER_HYPERCALL,
66 + offsetof(CPUX86State, msr_hv_hypercall) },
67 + { HV_X64_MSR_GUEST_OS_ID, HV_REGISTER_GUEST_OS_ID,
68 + offsetof(CPUX86State, msr_hv_guest_os_id) },
69 + { HV_X64_MSR_REFERENCE_TSC, HV_REGISTER_REFERENCE_TSC,
70 + offsetof(CPUX86State, msr_hv_tsc) },
71 +
72 + /* Hyper-V MSRs (non-SINT) */
73 + { HV_X64_MSR_SCONTROL, HV_REGISTER_SCONTROL,
74 + offsetof(CPUX86State, msr_hv_synic_control) },
75 + { HV_X64_MSR_SIEFP, HV_REGISTER_SIEFP,
76 + offsetof(CPUX86State, msr_hv_synic_evt_page) },
77 + { HV_X64_MSR_SIMP, HV_REGISTER_SIMP,
78 + offsetof(CPUX86State, msr_hv_synic_msg_page) },
79 +
80 + /* Other */
81 +
82 + /* TODO: find out processor features that correlate to unsupported MSRs. */
83 + /* { IA32_MSR_MISC_ENABLE, HV_X64_REGISTER_MSR_IA32_MISC_ENABLE, */
84 + /* offsetof(CPUX86State, msr_ia32_misc_enable) }, */
85 + /* { IA32_MSR_BNDCFGS, HV_X64_REGISTER_BNDCFGS, */
86 + /* offsetof(CPUX86State, msr_bndcfgs) }, */
87 + { IA32_MSR_SPEC_CTRL, HV_X64_REGISTER_SPEC_CTRL,
88 + offsetof(CPUX86State, spec_ctrl) },
89 };
84 -static const size_t msr_count = ARRAY_SIZE(supported_msrs);
90
86 -static int compare_msr_index(const void *a, const void *b)
91 +int mshv_init_msrs(const CPUState *cpu)
92 {
88 - return *(uint32_t *)a - *(uint32_t *)b;
93 + int ret;
94 + uint64_t d_t = MSR_MTRR_ENABLE | MSR_MTRR_MEM_TYPE_WB;
95 +
96 + const struct hv_register_assoc assocs[] = {
97 + { .name = HV_X64_REGISTER_SYSENTER_CS, .value.reg64 = 0x0 },
98 + { .name = HV_X64_REGISTER_SYSENTER_ESP, .value.reg64 = 0x0 },
99 + { .name = HV_X64_REGISTER_SYSENTER_EIP, .value.reg64 = 0x0 },
100 + { .name = HV_X64_REGISTER_STAR, .value.reg64 = 0x0 },
101 + { .name = HV_X64_REGISTER_CSTAR, .value.reg64 = 0x0 },
102 + { .name = HV_X64_REGISTER_LSTAR, .value.reg64 = 0x0 },
103 + { .name = HV_X64_REGISTER_KERNEL_GS_BASE, .value.reg64 = 0x0 },
104 + { .name = HV_X64_REGISTER_SFMASK, .value.reg64 = 0x0 },
105 + { .name = HV_X64_REGISTER_MSR_MTRR_DEF_TYPE, .value.reg64 = d_t },
106 + };
107 +
108 + ret = mshv_set_generic_regs(cpu, assocs, ARRAY_SIZE(assocs));
109 + if (ret < 0) {
110 + error_report("failed to put msrs");
111 + return -1;
112 + }
113 +
114 + return 0;
115 }
116
91 -__attribute__((constructor))
92 -static void init_sorted_msr_map(void)
117 +
118 +/*
119 + * INVARIANT: this fn expects assocs in the same order as they appear in
120 + * msr_env_map.
121 + */
122 +static void store_in_env(CPUState *cpu, const struct hv_register_assoc *assocs,
123 + size_t n_assocs)
124 {
94 - qsort(supported_msrs, msr_count, sizeof(uint32_t), compare_msr_index);
125 + X86CPU *x86_cpu = X86_CPU(cpu);
126 + CPUX86State *env = &x86_cpu->env;
127 + size_t i, j;
128 + const MshvMsrEnvMap *mapping;
129 + union hv_register_value hv_value;
130 + ptrdiff_t offset;
131 + uint32_t hv_name;
132 +
133 + assert(n_assocs <= (ARRAY_SIZE(msr_env_map)));
134 +
135 + for (i = 0, j = 0; i < ARRAY_SIZE(msr_env_map); i++) {
136 + hv_name = assocs[j].name;
137 + mapping = &msr_env_map[i];
138 + if (hv_name != mapping->hv_name) {
139 + continue;
140 + }
141 +
142 + hv_value = assocs[j].value;
143 + offset = mapping->env_offset;
144 + MSHV_ENV_FIELD(env, offset) = hv_value.reg64;
145 + j++;
146 + }
147 }
148
97 -static int mshv_is_supported_msr(uint32_t msr)
149 +static void set_hv_name_in_assocs(struct hv_register_assoc *assocs,
150 + size_t n_assocs)
151 {
99 - return bsearch(&msr, supported_msrs, msr_count, sizeof(uint32_t),
100 - compare_msr_index) != NULL;
152 + size_t i;
153 +
154 + assert(n_assocs == ARRAY_SIZE(msr_env_map));
155 + for (i = 0; i < ARRAY_SIZE(msr_env_map); i++) {
156 + assocs[i].name = msr_env_map[i].hv_name;
157 + }
158 }
159
103 -static int mshv_msr_to_hv_reg_name(uint32_t msr, uint32_t *hv_reg)
160 +static bool msr_supported(uint32_t name)
161 {
105 - switch (msr) {
106 - case IA32_MSR_TSC:
107 - *hv_reg = HV_X64_REGISTER_TSC;
108 - return 0;
109 - case IA32_MSR_EFER:
110 - *hv_reg = HV_X64_REGISTER_EFER;
111 - return 0;
112 - case IA32_MSR_KERNEL_GS_BASE:
113 - *hv_reg = HV_X64_REGISTER_KERNEL_GS_BASE;
114 - return 0;
115 - case IA32_MSR_APIC_BASE:
116 - *hv_reg = HV_X64_REGISTER_APIC_BASE;
117 - return 0;
118 - case IA32_MSR_PAT:
119 - *hv_reg = HV_X64_REGISTER_PAT;
120 - return 0;
121 - case IA32_MSR_SYSENTER_CS:
122 - *hv_reg = HV_X64_REGISTER_SYSENTER_CS;
123 - return 0;
124 - case IA32_MSR_SYSENTER_ESP:
125 - *hv_reg = HV_X64_REGISTER_SYSENTER_ESP;
126 - return 0;
127 - case IA32_MSR_SYSENTER_EIP:
128 - *hv_reg = HV_X64_REGISTER_SYSENTER_EIP;
129 - return 0;
130 - case IA32_MSR_STAR:
131 - *hv_reg = HV_X64_REGISTER_STAR;
132 - return 0;
133 - case IA32_MSR_LSTAR:
134 - *hv_reg = HV_X64_REGISTER_LSTAR;
135 - return 0;
136 - case IA32_MSR_CSTAR:
137 - *hv_reg = HV_X64_REGISTER_CSTAR;
138 - return 0;
139 - case IA32_MSR_SFMASK:
140 - *hv_reg = HV_X64_REGISTER_SFMASK;
141 - return 0;
142 - case IA32_MSR_MTRR_CAP:
143 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_CAP;
144 - return 0;
145 - case IA32_MSR_MTRR_DEF_TYPE:
146 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_DEF_TYPE;
147 - return 0;
148 - case IA32_MSR_MTRR_PHYSBASE0:
149 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE0;
150 - return 0;
151 - case IA32_MSR_MTRR_PHYSMASK0:
152 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK0;
153 - return 0;
154 - case IA32_MSR_MTRR_PHYSBASE1:
155 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE1;
156 - return 0;
157 - case IA32_MSR_MTRR_PHYSMASK1:
158 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK1;
159 - return 0;
160 - case IA32_MSR_MTRR_PHYSBASE2:
161 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE2;
162 - return 0;
163 - case IA32_MSR_MTRR_PHYSMASK2:
164 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK2;
165 - return 0;
166 - case IA32_MSR_MTRR_PHYSBASE3:
167 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE3;
168 - return 0;
169 - case IA32_MSR_MTRR_PHYSMASK3:
170 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK3;
171 - return 0;
172 - case IA32_MSR_MTRR_PHYSBASE4:
173 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE4;
174 - return 0;
175 - case IA32_MSR_MTRR_PHYSMASK4:
176 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK4;
177 - return 0;
178 - case IA32_MSR_MTRR_PHYSBASE5:
179 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE5;
180 - return 0;
181 - case IA32_MSR_MTRR_PHYSMASK5:
182 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK5;
183 - return 0;
184 - case IA32_MSR_MTRR_PHYSBASE6:
185 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE6;
186 - return 0;
187 - case IA32_MSR_MTRR_PHYSMASK6:
188 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK6;
189 - return 0;
190 - case IA32_MSR_MTRR_PHYSBASE7:
191 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE7;
192 - return 0;
193 - case IA32_MSR_MTRR_PHYSMASK7:
194 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK7;
195 - return 0;
196 - case IA32_MSR_MTRR_FIX64K_00000:
197 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX64K00000;
198 - return 0;
199 - case IA32_MSR_MTRR_FIX16K_80000:
200 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX16K80000;
201 - return 0;
202 - case IA32_MSR_MTRR_FIX16K_A0000:
203 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX16KA0000;
204 - return 0;
205 - case IA32_MSR_MTRR_FIX4K_C0000:
206 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KC0000;
207 - return 0;
208 - case IA32_MSR_MTRR_FIX4K_C8000:
209 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KC8000;
210 - return 0;
211 - case IA32_MSR_MTRR_FIX4K_D0000:
212 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KD0000;
213 - return 0;
214 - case IA32_MSR_MTRR_FIX4K_D8000:
215 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KD8000;
216 - return 0;
217 - case IA32_MSR_MTRR_FIX4K_E0000:
218 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KE0000;
219 - return 0;
220 - case IA32_MSR_MTRR_FIX4K_E8000:
221 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KE8000;
222 - return 0;
223 - case IA32_MSR_MTRR_FIX4K_F0000:
224 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KF0000;
225 - return 0;
226 - case IA32_MSR_MTRR_FIX4K_F8000:
227 - *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KF8000;
228 - return 0;
229 - case IA32_MSR_TSC_AUX:
230 - *hv_reg = HV_X64_REGISTER_TSC_AUX;
231 - return 0;
232 - case IA32_MSR_BNDCFGS:
233 - *hv_reg = HV_X64_REGISTER_BNDCFGS;
234 - return 0;
235 - case IA32_MSR_DEBUG_CTL:
236 - *hv_reg = HV_X64_REGISTER_DEBUG_CTL;
237 - return 0;
238 - case IA32_MSR_TSC_ADJUST:
239 - *hv_reg = HV_X64_REGISTER_TSC_ADJUST;
240 - return 0;
241 - case IA32_MSR_SPEC_CTRL:
242 - *hv_reg = HV_X64_REGISTER_SPEC_CTRL;
243 - return 0;
244 - case HV_X64_MSR_GUEST_OS_ID:
245 - *hv_reg = HV_REGISTER_GUEST_OS_ID;
246 - return 0;
247 - case HV_X64_MSR_SINT0:
248 - *hv_reg = HV_REGISTER_SINT0;
249 - return 0;
250 - case HV_X64_MSR_SINT1:
251 - *hv_reg = HV_REGISTER_SINT1;
252 - return 0;
253 - case HV_X64_MSR_SINT2:
254 - *hv_reg = HV_REGISTER_SINT2;
255 - return 0;
256 - case HV_X64_MSR_SINT3:
257 - *hv_reg = HV_REGISTER_SINT3;
258 - return 0;
259 - case HV_X64_MSR_SINT4:
260 - *hv_reg = HV_REGISTER_SINT4;
261 - return 0;
262 - case HV_X64_MSR_SINT5:
263 - *hv_reg = HV_REGISTER_SINT5;
264 - return 0;
265 - case HV_X64_MSR_SINT6:
266 - *hv_reg = HV_REGISTER_SINT6;
267 - return 0;
268 - case HV_X64_MSR_SINT7:
269 - *hv_reg = HV_REGISTER_SINT7;
270 - return 0;
271 - case HV_X64_MSR_SINT8:
272 - *hv_reg = HV_REGISTER_SINT8;
273 - return 0;
274 - case HV_X64_MSR_SINT9:
275 - *hv_reg = HV_REGISTER_SINT9;
276 - return 0;
277 - case HV_X64_MSR_SINT10:
278 - *hv_reg = HV_REGISTER_SINT10;
279 - return 0;
280 - case HV_X64_MSR_SINT11:
281 - *hv_reg = HV_REGISTER_SINT11;
282 - return 0;
283 - case HV_X64_MSR_SINT12:
284 - *hv_reg = HV_REGISTER_SINT12;
285 - return 0;
286 - case HV_X64_MSR_SINT13:
287 - *hv_reg = HV_REGISTER_SINT13;
288 - return 0;
289 - case HV_X64_MSR_SINT14:
290 - *hv_reg = HV_REGISTER_SINT14;
291 - return 0;
292 - case HV_X64_MSR_SINT15:
293 - *hv_reg = HV_REGISTER_SINT15;
294 - return 0;
295 - case IA32_MSR_MISC_ENABLE:
296 - *hv_reg = HV_X64_REGISTER_MSR_IA32_MISC_ENABLE;
297 - return 0;
298 - case HV_X64_MSR_SCONTROL:
299 - *hv_reg = HV_REGISTER_SCONTROL;
300 - return 0;
301 - case HV_X64_MSR_SIEFP:
302 - *hv_reg = HV_REGISTER_SIEFP;
303 - return 0;
304 - case HV_X64_MSR_SIMP:
305 - *hv_reg = HV_REGISTER_SIMP;
306 - return 0;
307 - case HV_X64_MSR_REFERENCE_TSC:
308 - *hv_reg = HV_REGISTER_REFERENCE_TSC;
309 - return 0;
310 - case HV_X64_MSR_EOM:
311 - *hv_reg = HV_REGISTER_EOM;
312 - return 0;
313 - default:
314 - error_report("failed to map MSR %u to HV register name", msr);
315 - return -1;
162 + /*
163 + * This check is not done comprehensively, it's meant to avoid hvcall
164 + * failures for certain MSRs on architectures that don't support them.
165 + */
166 +
167 + switch (name) {
168 + case HV_X64_REGISTER_SPEC_CTRL:
169 + return mshv_state->processor_features.ibrs_support;
170 + case HV_X64_REGISTER_TSC_ADJUST:
171 + return mshv_state->processor_features.tsc_adjust_support;
172 }
173 +
174 + return true;
175 }
176
319 -static int set_msrs(const CPUState *cpu, GList *msrs)
177 +int mshv_get_msrs(CPUState *cpu)
178 {
321 - size_t n_msrs;
322 - GList *entries;
323 - MshvMsrEntry *entry;
324 - enum hv_register_name name;
325 - struct hv_register_assoc *assoc;
326 - int ret;
327 - size_t i = 0;
328 -
329 - n_msrs = g_list_length(msrs);
330 - hv_register_assoc *assocs = g_new0(hv_register_assoc, n_msrs);
331 -
332 - entries = msrs;
333 - for (const GList *elem = entries; elem != NULL; elem = elem->next) {
334 - entry = elem->data;
335 - ret = mshv_msr_to_hv_reg_name(entry->index, &name);
336 - if (ret < 0) {
337 - g_free(assocs);
338 - return ret;
179 + int ret = 0;
180 + size_t n_assocs = ARRAY_SIZE(msr_env_map);
181 + struct hv_register_assoc assocs[ARRAY_SIZE(msr_env_map)];
182 + size_t i, j;
183 + uint32_t name;
184 +
185 + set_hv_name_in_assocs(assocs, n_assocs);
186 +
187 + /* Filter out MSRs that cannot be read */
188 + for (i = 0, j = 0; i < n_assocs; i++) {
189 + name = assocs[i].name;
190 +
191 + if (!msr_supported(name)) {
192 + continue;
193 }
340 - assoc = &assocs[i];
341 - assoc->name = name;
342 - /* the union has been initialized to 0 */
343 - assoc->value.reg64 = entry->data;
344 - i++;
194 +
195 + if (j != i) {
196 + assocs[j] = assocs[i];
197 + }
198 + j++;
199 }
346 - ret = mshv_set_generic_regs(cpu, assocs, n_msrs);
347 - g_free(assocs);
200 + n_assocs = j;
201 +
202 + ret = mshv_get_generic_regs(cpu, assocs, n_assocs);
203 if (ret < 0) {
349 - error_report("failed to set msrs");
350 - return -1;
204 + error_report("Failed to get MSRs");
205 + return -errno;
206 }
207 +
208 + store_in_env(cpu, assocs, n_assocs);
209 +
210 return 0;
211 }
212
213 +static void load_from_env(const CPUState *cpu, struct hv_register_assoc *assocs,
214 + size_t n_assocs)
215 +{
216 + size_t i;
217 + const MshvMsrEnvMap *mapping;
218 + X86CPU *x86_cpu = X86_CPU(cpu);
219 + CPUX86State *env = &x86_cpu->env;
220 + ptrdiff_t offset;
221 + union hv_register_value *hv_value;
222 +
223 + assert(n_assocs == ARRAY_SIZE(msr_env_map));
224 +
225 + for (i = 0; i < ARRAY_SIZE(msr_env_map); i++) {
226 + mapping = &msr_env_map[i];
227 + offset = mapping->env_offset;
228 + assocs[i].name = mapping->hv_name;
229 + hv_value = &assocs[i].value;
230 + hv_value->reg64 = MSHV_ENV_FIELD(env, offset);
231 + }
232 +}
233
356 -int mshv_configure_msr(const CPUState *cpu, const MshvMsrEntry *msrs,
357 - size_t n_msrs)
234 +int mshv_set_msrs(const CPUState *cpu)
235 {
359 - GList *valid_msrs = NULL;
360 - uint32_t msr_index;
236 + size_t n_assocs = ARRAY_SIZE(msr_env_map);
237 + struct hv_register_assoc assocs[ARRAY_SIZE(msr_env_map)];
238 int ret;
239 + size_t i, j;
240 +
241 + load_from_env(cpu, assocs, n_assocs);
242 +
243 + /* Filter out MSRs that cannot be written */
244 + for (i = 0, j = 0; i < n_assocs; i++) {
245 + uint32_t name = assocs[i].name;
246
363 - for (size_t i = 0; i < n_msrs; i++) {
364 - msr_index = msrs[i].index;
365 - /* check whether index of msrs is in SUPPORTED_MSRS */
366 - if (mshv_is_supported_msr(msr_index)) {
367 - valid_msrs = g_list_append(valid_msrs, (void *) &msrs[i]);
247 + /* Partition-wide MSRs: only write on vCPU 0 */
248 + if (cpu->cpu_index != 0 &&
249 + (name == HV_X64_REGISTER_HYPERCALL ||
250 + name == HV_REGISTER_GUEST_OS_ID ||
251 + name == HV_REGISTER_REFERENCE_TSC)) {
252 + continue;
253 }
254 +
255 + if (!msr_supported(name)) {
256 + continue;
257 + }
258 +
259 + if (j != i) {
260 + assocs[j] = assocs[i];
261 + }
262 + j++;
263 }
264 + n_assocs = j;
265
371 - ret = set_msrs(cpu, valid_msrs);
372 - g_list_free(valid_msrs);
266 + ret = mshv_set_generic_regs(cpu, assocs, n_assocs);
267 + if (ret < 0) {
268 + error_report("Failed to set MSRs");
269 + return -errno;
270 + }
271
374 - return ret;
272 + return 0;
273 }