master
c 465 lines 15.2 KB
Raw
1 /*
2 * QEMU MSHV support
3 *
4 * Copyright Microsoft, Corp. 2025
5 *
6 * Authors: Magnus Kulke <magnuskulke@microsoft.com>
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "qemu/osdep.h"
12 #include "system/mshv.h"
13 #include "system/mshv_int.h"
14 #include "hw/hyperv/hvgdk_mini.h"
15 #include "linux/mshv.h"
16 #include "qemu/error-report.h"
17 #include "cpu.h"
18
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 { IA32_MSR_TSC_DEADLINE, HV_X64_REGISTER_TSC_DEADLINE,
64 offsetof(CPUX86State, tsc_deadline) },
65
66 /* Hyper-V per-partition MSRs */
67 { HV_X64_MSR_HYPERCALL, HV_X64_REGISTER_HYPERCALL,
68 offsetof(CPUX86State, msr_hv_hypercall) },
69 { HV_X64_MSR_GUEST_OS_ID, HV_REGISTER_GUEST_OS_ID,
70 offsetof(CPUX86State, msr_hv_guest_os_id) },
71 { HV_X64_MSR_REFERENCE_TSC, HV_REGISTER_REFERENCE_TSC,
72 offsetof(CPUX86State, msr_hv_tsc) },
73
74 /* Hyper-V MSRs (non-SINT) */
75 { HV_X64_MSR_SCONTROL, HV_REGISTER_SCONTROL,
76 offsetof(CPUX86State, msr_hv_synic_control) },
77 { HV_X64_MSR_SIEFP, HV_REGISTER_SIEFP,
78 offsetof(CPUX86State, msr_hv_synic_evt_page) },
79 { HV_X64_MSR_SIMP, HV_REGISTER_SIMP,
80 offsetof(CPUX86State, msr_hv_synic_msg_page) },
81
82 /* MTRR default type */
83 { IA32_MSR_MTRR_DEF_TYPE, HV_X64_REGISTER_MSR_MTRR_DEF_TYPE,
84 offsetof(CPUX86State, mtrr_deftype) },
85
86 /* CET / Shadow Stack */
87 { MSR_IA32_U_CET, HV_X64_REGISTER_U_CET,
88 offsetof(CPUX86State, u_cet) },
89 { MSR_IA32_S_CET, HV_X64_REGISTER_S_CET,
90 offsetof(CPUX86State, s_cet) },
91 { MSR_IA32_PL0_SSP, HV_X64_REGISTER_PL0_SSP,
92 offsetof(CPUX86State, pl0_ssp) },
93 { MSR_IA32_PL1_SSP, HV_X64_REGISTER_PL1_SSP,
94 offsetof(CPUX86State, pl1_ssp) },
95 { MSR_IA32_PL2_SSP, HV_X64_REGISTER_PL2_SSP,
96 offsetof(CPUX86State, pl2_ssp) },
97 { MSR_IA32_PL3_SSP, HV_X64_REGISTER_PL3_SSP,
98 offsetof(CPUX86State, pl3_ssp) },
99 { MSR_IA32_INT_SSP_TAB, HV_X64_REGISTER_INTERRUPT_SSP_TABLE_ADDR,
100 offsetof(CPUX86State, int_ssp_table) },
101
102 /* XSAVE Supervisor State */
103 { MSR_IA32_XSS, HV_X64_REGISTER_U_XSS,
104 offsetof(CPUX86State, xss) },
105
106 /* Other */
107
108 /* TODO: find out processor features that correlate to unsupported MSRs. */
109 /* { IA32_MSR_MISC_ENABLE, HV_X64_REGISTER_MSR_IA32_MISC_ENABLE, */
110 /* offsetof(CPUX86State, msr_ia32_misc_enable) }, */
111 /* { IA32_MSR_BNDCFGS, HV_X64_REGISTER_BNDCFGS, */
112 /* offsetof(CPUX86State, msr_bndcfgs) }, */
113 { IA32_MSR_SPEC_CTRL, HV_X64_REGISTER_SPEC_CTRL,
114 offsetof(CPUX86State, spec_ctrl) },
115 };
116
117 /*
118 * The assocs have to be set according to this schema:
119 * 8 entries for 0-7 mtrr_base
120 * 8 entries for mtrr_mask 0-7
121 * 11 entries for 1 x 64k, 2 x 16k, 8 x 4k fixed MTRR
122 * 27 total entries
123 */
124
125 #define MSHV_MTRR_MSR_COUNT 27
126 #define MSHV_MSR_TOTAL_COUNT (ARRAY_SIZE(msr_env_map) + MSHV_MTRR_MSR_COUNT)
127
128 static void store_in_env_mtrr_phys(CPUState *cpu,
129 const struct hv_register_assoc *assocs,
130 size_t n_assocs)
131 {
132 X86CPU *x86_cpu = X86_CPU(cpu);
133 CPUX86State *env = &x86_cpu->env;
134 size_t i, fixed_offset;
135 hv_register_name hv_name;
136 uint64_t base, mask;
137
138 assert(n_assocs == MSHV_MTRR_MSR_COUNT);
139
140 for (i = 0; i < MSR_MTRRcap_VCNT; i++) {
141 hv_name = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE0 + i;
142 assert(assocs[i].name == hv_name);
143 hv_name = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK0 + i;
144 assert(assocs[i + MSR_MTRRcap_VCNT].name == hv_name);
145
146 base = assocs[i].value.reg64;
147 mask = assocs[i + MSR_MTRRcap_VCNT].value.reg64;
148 env->mtrr_var[i].base = base;
149 env->mtrr_var[i].mask = mask;
150 }
151
152 /* fixed 1x 64, 2x 16, 8x 4 kB */
153 fixed_offset = MSR_MTRRcap_VCNT * 2;
154 for (i = 0; i < 11; i++) {
155 hv_name = HV_X64_REGISTER_MSR_MTRR_FIX64K00000 + i;
156 assert(assocs[fixed_offset + i].name == hv_name);
157 env->mtrr_fixed[i] = assocs[fixed_offset + i].value.reg64;
158 }
159 }
160
161 /*
162 * The assocs have to be set according to this schema:
163 * 8 entries for 0-7 mtrr_base
164 * 8 entries for mtrr_mask 0-7
165 * 11 entries for 1 x 64k, 2 x 16k, 8 x 4k fixed MTRR
166 * 27 total entries
167 */
168 static void load_from_env_mtrr_phys(const CPUState *cpu,
169 struct hv_register_assoc *assocs,
170 size_t n_assocs)
171 {
172 X86CPU *x86_cpu = X86_CPU(cpu);
173 CPUX86State *env = &x86_cpu->env;
174 size_t i, fixed_offset;
175 uint64_t base, mask, fixed_value;
176 hv_register_name base_name, mask_name, fixed_name;
177 hv_register_assoc *assoc;
178
179 assert(n_assocs == MSHV_MTRR_MSR_COUNT);
180
181 for (i = 0; i < MSR_MTRRcap_VCNT; i++) {
182 base = env->mtrr_var[i].base;
183 mask = env->mtrr_var[i].mask;
184
185 base_name = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE0 + i;
186 mask_name = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK0 + i;
187
188 assoc = &assocs[i];
189 assoc->name = base_name;
190 assoc->value.reg64 = base;
191
192 assoc = &assocs[i + MSR_MTRRcap_VCNT];
193 assoc->name = mask_name;
194 assoc->value.reg64 = mask;
195 }
196
197 /* fixed 1x 64, 2x 16, 8x 4 kB */
198 fixed_offset = MSR_MTRRcap_VCNT * 2;
199 for (i = 0; i < 11; i++) {
200 fixed_name = HV_X64_REGISTER_MSR_MTRR_FIX64K00000 + i;
201 fixed_value = env->mtrr_fixed[i];
202
203 assoc = &assocs[fixed_offset + i];
204 assoc->name = fixed_name;
205 assoc->value.reg64 = fixed_value;
206 }
207 }
208
209 int mshv_init_msrs(const CPUState *cpu)
210 {
211 int ret;
212 uint64_t d_t = MSR_MTRR_ENABLE | MSR_MTRR_MEM_TYPE_WB;
213
214 const struct hv_register_assoc assocs[] = {
215 { .name = HV_X64_REGISTER_SYSENTER_CS, .value.reg64 = 0x0 },
216 { .name = HV_X64_REGISTER_SYSENTER_ESP, .value.reg64 = 0x0 },
217 { .name = HV_X64_REGISTER_SYSENTER_EIP, .value.reg64 = 0x0 },
218 { .name = HV_X64_REGISTER_STAR, .value.reg64 = 0x0 },
219 { .name = HV_X64_REGISTER_CSTAR, .value.reg64 = 0x0 },
220 { .name = HV_X64_REGISTER_LSTAR, .value.reg64 = 0x0 },
221 { .name = HV_X64_REGISTER_KERNEL_GS_BASE, .value.reg64 = 0x0 },
222 { .name = HV_X64_REGISTER_SFMASK, .value.reg64 = 0x0 },
223 { .name = HV_X64_REGISTER_MSR_MTRR_DEF_TYPE, .value.reg64 = d_t },
224 };
225
226 ret = mshv_set_generic_regs(cpu, assocs, ARRAY_SIZE(assocs));
227 if (ret < 0) {
228 error_report("failed to put msrs");
229 return -1;
230 }
231
232 return 0;
233 }
234
235
236 /*
237 * INVARIANT: this fn expects assocs in the same order as they appear in
238 * msr_env_map.
239 */
240 static void store_in_env(CPUState *cpu, const struct hv_register_assoc *assocs,
241 size_t n_assocs)
242 {
243 X86CPU *x86_cpu = X86_CPU(cpu);
244 CPUX86State *env = &x86_cpu->env;
245 size_t i, j;
246 const MshvMsrEnvMap *mapping;
247 union hv_register_value hv_value;
248 ptrdiff_t offset;
249 uint32_t hv_name;
250 size_t mtrr_index;
251
252 assert(n_assocs <= MSHV_MSR_TOTAL_COUNT);
253
254 for (i = 0, j = 0; i < ARRAY_SIZE(msr_env_map); i++) {
255 hv_name = assocs[j].name;
256 mapping = &msr_env_map[i];
257 if (hv_name != mapping->hv_name) {
258 continue;
259 }
260
261 hv_value = assocs[j].value;
262 offset = mapping->env_offset;
263 MSHV_ENV_FIELD(env, offset) = hv_value.reg64;
264 j++;
265 }
266
267 mtrr_index = j;
268 store_in_env_mtrr_phys(cpu, &assocs[mtrr_index], MSHV_MTRR_MSR_COUNT);
269 }
270
271 static void set_hv_name_in_assocs(struct hv_register_assoc *assocs,
272 size_t n_assocs)
273 {
274 size_t i;
275 size_t mtrr_offset, mtrr_fixed_offset;
276 hv_register_name hv_name;
277
278 assert(n_assocs == MSHV_MSR_TOTAL_COUNT);
279
280 for (i = 0; i < ARRAY_SIZE(msr_env_map); i++) {
281 assocs[i].name = msr_env_map[i].hv_name;
282 }
283
284 mtrr_offset = ARRAY_SIZE(msr_env_map);
285 for (i = 0; i < MSR_MTRRcap_VCNT; i++) {
286 hv_name = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE0 + i;
287 assocs[mtrr_offset + i].name = hv_name;
288 hv_name = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK0 + i;
289 assocs[mtrr_offset + MSR_MTRRcap_VCNT + i].name = hv_name;
290 }
291
292 /* fixed 1x 64, 2x 16, 8x 4 kB */
293 mtrr_fixed_offset = mtrr_offset + MSR_MTRRcap_VCNT * 2;
294 for (i = 0; i < 11; i++) {
295 hv_name = HV_X64_REGISTER_MSR_MTRR_FIX64K00000 + i;
296 assocs[mtrr_fixed_offset + i].name = hv_name;
297 }
298 }
299
300 static bool msr_supported(uint32_t name)
301 {
302 /*
303 * This check is not done comprehensively, it's meant to avoid hvcall
304 * failures for certain MSRs on architectures that don't support them.
305 */
306
307 switch (name) {
308 case HV_X64_REGISTER_SPEC_CTRL:
309 return mshv_state->processor_features.ibrs_support;
310 case HV_X64_REGISTER_TSC_ADJUST:
311 return mshv_state->processor_features.tsc_adjust_support;
312 case HV_X64_REGISTER_U_CET:
313 case HV_X64_REGISTER_S_CET:
314 case HV_X64_REGISTER_PL0_SSP:
315 case HV_X64_REGISTER_PL1_SSP:
316 case HV_X64_REGISTER_PL2_SSP:
317 case HV_X64_REGISTER_PL3_SSP:
318 case HV_X64_REGISTER_INTERRUPT_SSP_TABLE_ADDR:
319 case HV_X64_REGISTER_U_XSS:
320 return mshv_state->processor_features.cet_ss_support ||
321 mshv_state->processor_features.cet_ibt_support;
322 }
323
324 return true;
325 }
326
327 int mshv_get_msrs(CPUState *cpu)
328 {
329 int ret = 0;
330 size_t n_assocs = MSHV_MSR_TOTAL_COUNT;
331 struct hv_register_assoc assocs[MSHV_MSR_TOTAL_COUNT];
332 size_t i, j;
333 uint32_t name;
334 X86CPU *x86cpu = X86_CPU(cpu);
335
336 set_hv_name_in_assocs(assocs, n_assocs);
337
338 /* Filter out MSRs that cannot be read */
339 for (i = 0, j = 0; i < n_assocs; i++) {
340 name = assocs[i].name;
341
342 if (!msr_supported(name)) {
343 continue;
344 }
345
346 if (j != i) {
347 assocs[j] = assocs[i];
348 }
349 j++;
350 }
351 n_assocs = j;
352
353 ret = mshv_get_generic_regs(cpu, assocs, n_assocs);
354 if (ret < 0) {
355 error_report("Failed to get MSRs");
356 return -errno;
357 }
358
359 store_in_env(cpu, assocs, n_assocs);
360
361 /* Read SINT MSRs only if SynIC is enabled */
362 if (mshv_synic_enabled(cpu)) {
363 QEMU_BUILD_BUG_ON(MSHV_MSR_TOTAL_COUNT < HV_SINT_COUNT);
364
365 for (i = 0; i < HV_SINT_COUNT; i++) {
366 assocs[i].name = HV_REGISTER_SINT0 + i;
367 }
368
369 ret = mshv_get_generic_regs(cpu, assocs, HV_SINT_COUNT);
370 if (ret < 0) {
371 error_report("Failed to get SynIC SINT MSRs");
372 return -errno;
373 }
374
375 for (i = 0; i < HV_SINT_COUNT; i++) {
376 uint64_t hv_sint_value = assocs[i].value.reg64;
377 x86cpu->env.msr_hv_synic_sint[i] = hv_sint_value;
378 }
379 }
380
381 return 0;
382 }
383
384 static void load_from_env(const CPUState *cpu, struct hv_register_assoc *assocs,
385 size_t n_assocs)
386 {
387 size_t i;
388 const MshvMsrEnvMap *mapping;
389 X86CPU *x86_cpu = X86_CPU(cpu);
390 CPUX86State *env = &x86_cpu->env;
391 ptrdiff_t offset;
392 union hv_register_value *hv_value;
393 size_t mtrr_offset;
394
395 assert(n_assocs == MSHV_MSR_TOTAL_COUNT);
396
397 for (i = 0; i < ARRAY_SIZE(msr_env_map); i++) {
398 mapping = &msr_env_map[i];
399 offset = mapping->env_offset;
400 assocs[i].name = mapping->hv_name;
401 hv_value = &assocs[i].value;
402 hv_value->reg64 = MSHV_ENV_FIELD(env, offset);
403 }
404
405 mtrr_offset = ARRAY_SIZE(msr_env_map);
406 load_from_env_mtrr_phys(cpu, &assocs[mtrr_offset], MSHV_MTRR_MSR_COUNT);
407 }
408
409 int mshv_set_msrs(const CPUState *cpu)
410 {
411 size_t n_assocs = MSHV_MSR_TOTAL_COUNT;
412 struct hv_register_assoc assocs[MSHV_MSR_TOTAL_COUNT];
413 int ret;
414 size_t i, j;
415 X86CPU *x86cpu = X86_CPU(cpu);
416
417 load_from_env(cpu, assocs, n_assocs);
418
419 /* Filter out MSRs that cannot be written */
420 for (i = 0, j = 0; i < n_assocs; i++) {
421 uint32_t name = assocs[i].name;
422
423 /* Partition-wide MSRs: only write on vCPU 0 */
424 if (cpu->cpu_index != 0 &&
425 (name == HV_X64_REGISTER_HYPERCALL ||
426 name == HV_REGISTER_GUEST_OS_ID ||
427 name == HV_REGISTER_REFERENCE_TSC)) {
428 continue;
429 }
430
431 if (!msr_supported(name)) {
432 continue;
433 }
434
435 if (j != i) {
436 assocs[j] = assocs[i];
437 }
438 j++;
439 }
440 n_assocs = j;
441
442 ret = mshv_set_generic_regs(cpu, assocs, n_assocs);
443 if (ret < 0) {
444 error_report("Failed to set MSRs");
445 return -errno;
446 }
447
448 /* SINT MSRs can only be written if SCONTROL has been set, so we split */
449 if (mshv_synic_enabled(cpu)) {
450 QEMU_BUILD_BUG_ON(MSHV_MSR_TOTAL_COUNT < HV_SINT_COUNT);
451
452 for (i = 0; i < HV_SINT_COUNT; i++) {
453 assocs[i].name = HV_REGISTER_SINT0 + i;
454 assocs[i].value.reg64 = x86cpu->env.msr_hv_synic_sint[i];
455 }
456
457 ret = mshv_set_generic_regs(cpu, assocs, HV_SINT_COUNT);
458 if (ret < 0) {
459 error_report("Failed to set SynIC SINT MSRs");
460 return -errno;
461 }
462 }
463
464 return 0;
465 }