1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Hyper-V Isolation VM interface with paravisor and hypervisor
4 *
5 * Author:
6 * Tianyu Lan <Tianyu.Lan@microsoft.com>
7 */
8
9 #include <linux/bitfield.h>
10 #include <linux/types.h>
11 #include <linux/slab.h>
12 #include <linux/cpu.h>
13 #include <linux/export.h>
14 #include <asm/svm.h>
15 #include <asm/sev.h>
16 #include <asm/io.h>
17 #include <asm/coco.h>
18 #include <asm/mem_encrypt.h>
19 #include <asm/set_memory.h>
20 #include <asm/mshyperv.h>
21 #include <asm/hypervisor.h>
22 #include <asm/mtrr.h>
23 #include <asm/io_apic.h>
24 #include <asm/realmode.h>
25 #include <asm/e820/api.h>
26 #include <asm/desc.h>
27 #include <asm/msr.h>
28 #include <uapi/asm/vmx.h>
29
30 #ifdef CONFIG_AMD_MEM_ENCRYPT
31
32 #define GHCB_USAGE_HYPERV_CALL 1
33
34 union hv_ghcb {
35 struct ghcb ghcb;
36 struct {
37 u64 hypercalldata[509];
38 u64 outputgpa;
39 union {
40 union {
41 struct {
42 u32 callcode : 16;
43 u32 isfast : 1;
44 u32 reserved1 : 14;
45 u32 isnested : 1;
46 u32 countofelements : 12;
47 u32 reserved2 : 4;
48 u32 repstartindex : 12;
49 u32 reserved3 : 4;
50 };
51 u64 asuint64;
52 } hypercallinput;
53 union {
54 struct {
55 u16 callstatus;
56 u16 reserved1;
57 u32 elementsprocessed : 12;
58 u32 reserved2 : 20;
59 };
60 u64 asunit64;
61 } hypercalloutput;
62 };
63 u64 reserved2;
64 } hypercall;
65 } __packed __aligned(HV_HYP_PAGE_SIZE);
66
67 /* Only used in an SNP VM with the paravisor */
68 static u16 hv_ghcb_version __ro_after_init;
69
70 /* Functions only used in an SNP VM with the paravisor go here. */
hv_ghcb_hypercall(u64 control,void * input,void * output,u32 input_size)71 u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size)
72 {
73 union hv_ghcb *hv_ghcb;
74 void **ghcb_base;
75 unsigned long flags;
76 u64 status;
77
78 if (!hv_ghcb_pg)
79 return -EFAULT;
80
81 WARN_ON(in_nmi());
82
83 local_irq_save(flags);
84 ghcb_base = (void **)this_cpu_ptr(hv_ghcb_pg);
85 hv_ghcb = (union hv_ghcb *)*ghcb_base;
86 if (!hv_ghcb) {
87 local_irq_restore(flags);
88 return -EFAULT;
89 }
90
91 hv_ghcb->ghcb.protocol_version = GHCB_PROTOCOL_MAX;
92 hv_ghcb->ghcb.ghcb_usage = GHCB_USAGE_HYPERV_CALL;
93
94 hv_ghcb->hypercall.outputgpa = (u64)output;
95 hv_ghcb->hypercall.hypercallinput.asuint64 = 0;
96 hv_ghcb->hypercall.hypercallinput.callcode = control;
97
98 if (input_size)
99 memcpy(hv_ghcb->hypercall.hypercalldata, input, input_size);
100
101 VMGEXIT();
102
103 hv_ghcb->ghcb.ghcb_usage = 0xffffffff;
104 memset(hv_ghcb->ghcb.save.valid_bitmap, 0,
105 sizeof(hv_ghcb->ghcb.save.valid_bitmap));
106
107 status = hv_ghcb->hypercall.hypercalloutput.callstatus;
108
109 local_irq_restore(flags);
110
111 return status;
112 }
113
rd_ghcb_msr(void)114 static inline u64 rd_ghcb_msr(void)
115 {
116 return native_rdmsrq(MSR_AMD64_SEV_ES_GHCB);
117 }
118
wr_ghcb_msr(u64 val)119 static inline void wr_ghcb_msr(u64 val)
120 {
121 native_wrmsrq(MSR_AMD64_SEV_ES_GHCB, val);
122 }
123
hv_ghcb_hv_call(struct ghcb * ghcb,u64 exit_code,u64 exit_info_1,u64 exit_info_2)124 static enum es_result hv_ghcb_hv_call(struct ghcb *ghcb, u64 exit_code,
125 u64 exit_info_1, u64 exit_info_2)
126 {
127 /* Fill in protocol and format specifiers */
128 ghcb->protocol_version = hv_ghcb_version;
129 ghcb->ghcb_usage = GHCB_DEFAULT_USAGE;
130
131 ghcb_set_sw_exit_code(ghcb, exit_code);
132 ghcb_set_sw_exit_info_1(ghcb, exit_info_1);
133 ghcb_set_sw_exit_info_2(ghcb, exit_info_2);
134
135 VMGEXIT();
136
137 if (ghcb->save.sw_exit_info_1 & GENMASK_ULL(31, 0))
138 return ES_VMM_ERROR;
139 else
140 return ES_OK;
141 }
142
hv_ghcb_terminate(unsigned int set,unsigned int reason)143 void __noreturn hv_ghcb_terminate(unsigned int set, unsigned int reason)
144 {
145 u64 val = GHCB_MSR_TERM_REQ;
146
147 /* Tell the hypervisor what went wrong. */
148 val |= GHCB_SEV_TERM_REASON(set, reason);
149
150 /* Request Guest Termination from Hypervisor */
151 wr_ghcb_msr(val);
152 VMGEXIT();
153
154 while (true)
155 asm volatile("hlt\n" : : : "memory");
156 }
157
hv_ghcb_negotiate_protocol(void)158 bool hv_ghcb_negotiate_protocol(void)
159 {
160 u64 ghcb_gpa;
161 u64 val;
162
163 /* Save ghcb page gpa. */
164 ghcb_gpa = rd_ghcb_msr();
165
166 /* Do the GHCB protocol version negotiation */
167 wr_ghcb_msr(GHCB_MSR_SEV_INFO_REQ);
168 VMGEXIT();
169 val = rd_ghcb_msr();
170
171 if (GHCB_MSR_INFO(val) != GHCB_MSR_SEV_INFO_RESP)
172 return false;
173
174 if (GHCB_MSR_PROTO_MAX(val) < GHCB_PROTOCOL_MIN ||
175 GHCB_MSR_PROTO_MIN(val) > GHCB_PROTOCOL_MAX)
176 return false;
177
178 hv_ghcb_version = min_t(size_t, GHCB_MSR_PROTO_MAX(val),
179 GHCB_PROTOCOL_MAX);
180
181 /* Write ghcb page back after negotiating protocol. */
182 wr_ghcb_msr(ghcb_gpa);
183 VMGEXIT();
184
185 return true;
186 }
187
hv_ghcb_msr_write(u64 msr,u64 value)188 static void hv_ghcb_msr_write(u64 msr, u64 value)
189 {
190 union hv_ghcb *hv_ghcb;
191 void **ghcb_base;
192 unsigned long flags;
193
194 if (!hv_ghcb_pg)
195 return;
196
197 WARN_ON(in_nmi());
198
199 local_irq_save(flags);
200 ghcb_base = (void **)this_cpu_ptr(hv_ghcb_pg);
201 hv_ghcb = (union hv_ghcb *)*ghcb_base;
202 if (!hv_ghcb) {
203 local_irq_restore(flags);
204 return;
205 }
206
207 ghcb_set_rcx(&hv_ghcb->ghcb, msr);
208 ghcb_set_rax(&hv_ghcb->ghcb, lower_32_bits(value));
209 ghcb_set_rdx(&hv_ghcb->ghcb, upper_32_bits(value));
210
211 if (hv_ghcb_hv_call(&hv_ghcb->ghcb, SVM_EXIT_MSR, 1, 0))
212 pr_warn("Fail to write msr via ghcb %llx.\n", msr);
213
214 local_irq_restore(flags);
215 }
216
hv_ghcb_msr_read(u64 msr,u64 * value)217 static void hv_ghcb_msr_read(u64 msr, u64 *value)
218 {
219 union hv_ghcb *hv_ghcb;
220 void **ghcb_base;
221 unsigned long flags;
222
223 /* Check size of union hv_ghcb here. */
224 BUILD_BUG_ON(sizeof(union hv_ghcb) != HV_HYP_PAGE_SIZE);
225
226 if (!hv_ghcb_pg)
227 return;
228
229 WARN_ON(in_nmi());
230
231 local_irq_save(flags);
232 ghcb_base = (void **)this_cpu_ptr(hv_ghcb_pg);
233 hv_ghcb = (union hv_ghcb *)*ghcb_base;
234 if (!hv_ghcb) {
235 local_irq_restore(flags);
236 return;
237 }
238
239 ghcb_set_rcx(&hv_ghcb->ghcb, msr);
240 if (hv_ghcb_hv_call(&hv_ghcb->ghcb, SVM_EXIT_MSR, 0, 0))
241 pr_warn("Fail to read msr via ghcb %llx.\n", msr);
242 else
243 *value = (u64)lower_32_bits(hv_ghcb->ghcb.save.rax)
244 | ((u64)lower_32_bits(hv_ghcb->ghcb.save.rdx) << 32);
245 local_irq_restore(flags);
246 }
247
248 /* Only used in a fully enlightened SNP VM, i.e. without the paravisor */
249 static u8 ap_start_input_arg[PAGE_SIZE] __bss_decrypted __aligned(PAGE_SIZE);
250 static u8 ap_start_stack[PAGE_SIZE] __aligned(PAGE_SIZE);
251 static DEFINE_PER_CPU(struct sev_es_save_area *, hv_sev_vmsa);
252
253 /* Functions only used in an SNP VM without the paravisor go here. */
254
255 #define hv_populate_vmcb_seg(seg, gdtr_base) \
256 do { \
257 if (seg.selector) { \
258 seg.base = 0; \
259 seg.limit = HV_AP_SEGMENT_LIMIT; \
260 seg.attrib = *(u16 *)(gdtr_base + seg.selector + 5); \
261 seg.attrib = (seg.attrib & 0xFF) | ((seg.attrib >> 4) & 0xF00); \
262 } \
263 } while (0) \
264
snp_set_vmsa(void * va,bool vmsa)265 static int snp_set_vmsa(void *va, bool vmsa)
266 {
267 u64 attrs;
268
269 /*
270 * Running at VMPL0 allows the kernel to change the VMSA bit for a page
271 * using the RMPADJUST instruction. However, for the instruction to
272 * succeed it must target the permissions of a lesser privileged
273 * (higher numbered) VMPL level, so use VMPL1 (refer to the RMPADJUST
274 * instruction in the AMD64 APM Volume 3).
275 */
276 attrs = 1;
277 if (vmsa)
278 attrs |= RMPADJUST_VMSA_PAGE_BIT;
279
280 return rmpadjust((unsigned long)va, RMP_PG_SIZE_4K, attrs);
281 }
282
snp_cleanup_vmsa(struct sev_es_save_area * vmsa)283 static void snp_cleanup_vmsa(struct sev_es_save_area *vmsa)
284 {
285 int err;
286
287 err = snp_set_vmsa(vmsa, false);
288 if (err)
289 pr_err("clear VMSA page failed (%u), leaking page\n", err);
290 else
291 free_page((unsigned long)vmsa);
292 }
293
hv_snp_boot_ap(u32 apic_id,unsigned long start_ip,unsigned int cpu)294 int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip, unsigned int cpu)
295 {
296 struct sev_es_save_area *vmsa = (struct sev_es_save_area *)
297 __get_free_page(GFP_KERNEL | __GFP_ZERO);
298 struct sev_es_save_area *cur_vmsa;
299 struct desc_ptr gdtr;
300 u64 ret, retry = 5;
301 struct hv_enable_vp_vtl *start_vp_input;
302 unsigned long flags;
303 int vp_index;
304
305 if (!vmsa)
306 return -ENOMEM;
307
308 /* Find the Hyper-V VP index which might be not the same as APIC ID */
309 vp_index = hv_apicid_to_vp_index(apic_id);
310 if (vp_index < 0 || vp_index > ms_hyperv.max_vp_index)
311 return -EINVAL;
312
313 native_store_gdt(&gdtr);
314
315 vmsa->gdtr.base = gdtr.address;
316 vmsa->gdtr.limit = gdtr.size;
317
318 asm volatile("movl %%es, %%eax;" : "=a" (vmsa->es.selector));
319 hv_populate_vmcb_seg(vmsa->es, vmsa->gdtr.base);
320
321 asm volatile("movl %%cs, %%eax;" : "=a" (vmsa->cs.selector));
322 hv_populate_vmcb_seg(vmsa->cs, vmsa->gdtr.base);
323
324 asm volatile("movl %%ss, %%eax;" : "=a" (vmsa->ss.selector));
325 hv_populate_vmcb_seg(vmsa->ss, vmsa->gdtr.base);
326
327 asm volatile("movl %%ds, %%eax;" : "=a" (vmsa->ds.selector));
328 hv_populate_vmcb_seg(vmsa->ds, vmsa->gdtr.base);
329
330 vmsa->efer = native_read_msr(MSR_EFER);
331
332 vmsa->cr4 = native_read_cr4();
333 vmsa->cr3 = __native_read_cr3();
334 vmsa->cr0 = native_read_cr0();
335
336 vmsa->xcr0 = 1;
337 vmsa->g_pat = HV_AP_INIT_GPAT_DEFAULT;
338 vmsa->rip = (u64)secondary_startup_64_no_verify;
339 vmsa->rsp = (u64)&ap_start_stack[PAGE_SIZE];
340
341 /*
342 * Set the SNP-specific fields for this VMSA:
343 * VMPL level
344 * SEV_FEATURES (matches the SEV STATUS MSR right shifted 2 bits)
345 */
346 vmsa->vmpl = 0;
347 vmsa->sev_features = sev_status >> 2;
348
349 ret = snp_set_vmsa(vmsa, true);
350 if (ret) {
351 pr_err("RMPADJUST(%llx) failed: %llx\n", (u64)vmsa, ret);
352 free_page((u64)vmsa);
353 return ret;
354 }
355
356 local_irq_save(flags);
357 start_vp_input = (struct hv_enable_vp_vtl *)ap_start_input_arg;
358 memset(start_vp_input, 0, sizeof(*start_vp_input));
359 start_vp_input->partition_id = -1;
360 start_vp_input->vp_index = vp_index;
361 start_vp_input->target_vtl.target_vtl = ms_hyperv.vtl;
362 *(u64 *)&start_vp_input->vp_context = __pa(vmsa) | 1;
363
364 do {
365 ret = hv_do_hypercall(HVCALL_START_VP,
366 start_vp_input, NULL);
367 } while (hv_result(ret) == HV_STATUS_TIME_OUT && retry--);
368
369 local_irq_restore(flags);
370
371 if (!hv_result_success(ret)) {
372 pr_err("HvCallStartVirtualProcessor failed: %llx\n", ret);
373 snp_cleanup_vmsa(vmsa);
374 vmsa = NULL;
375 }
376
377 cur_vmsa = per_cpu(hv_sev_vmsa, cpu);
378 /* Free up any previous VMSA page */
379 if (cur_vmsa)
380 snp_cleanup_vmsa(cur_vmsa);
381
382 /* Record the current VMSA page */
383 per_cpu(hv_sev_vmsa, cpu) = vmsa;
384
385 return ret;
386 }
387
388 #else
hv_ghcb_msr_write(u64 msr,u64 value)389 static inline void hv_ghcb_msr_write(u64 msr, u64 value) {}
hv_ghcb_msr_read(u64 msr,u64 * value)390 static inline void hv_ghcb_msr_read(u64 msr, u64 *value) {}
391 #endif /* CONFIG_AMD_MEM_ENCRYPT */
392
393 #ifdef CONFIG_INTEL_TDX_GUEST
hv_tdx_msr_write(u64 msr,u64 val)394 static void hv_tdx_msr_write(u64 msr, u64 val)
395 {
396 struct tdx_module_args args = {
397 .r10 = TDX_HYPERCALL_STANDARD,
398 .r11 = EXIT_REASON_MSR_WRITE,
399 .r12 = msr,
400 .r13 = val,
401 };
402
403 u64 ret = __tdx_hypercall(&args);
404
405 WARN_ONCE(ret, "Failed to emulate MSR write: %lld\n", ret);
406 }
407
hv_tdx_msr_read(u64 msr,u64 * val)408 static void hv_tdx_msr_read(u64 msr, u64 *val)
409 {
410 struct tdx_module_args args = {
411 .r10 = TDX_HYPERCALL_STANDARD,
412 .r11 = EXIT_REASON_MSR_READ,
413 .r12 = msr,
414 };
415
416 u64 ret = __tdx_hypercall(&args);
417
418 if (WARN_ONCE(ret, "Failed to emulate MSR read: %lld\n", ret))
419 *val = 0;
420 else
421 *val = args.r11;
422 }
423
hv_tdx_hypercall(u64 control,u64 param1,u64 param2)424 u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2)
425 {
426 struct tdx_module_args args = { };
427
428 args.r10 = control;
429 args.rdx = param1;
430 args.r8 = param2;
431
432 (void)__tdx_hypercall(&args);
433
434 return args.r11;
435 }
436
437 #else
hv_tdx_msr_write(u64 msr,u64 value)438 static inline void hv_tdx_msr_write(u64 msr, u64 value) {}
hv_tdx_msr_read(u64 msr,u64 * value)439 static inline void hv_tdx_msr_read(u64 msr, u64 *value) {}
440 #endif /* CONFIG_INTEL_TDX_GUEST */
441
442 #if defined(CONFIG_AMD_MEM_ENCRYPT) || defined(CONFIG_INTEL_TDX_GUEST)
hv_ivm_msr_write(u64 msr,u64 value)443 void hv_ivm_msr_write(u64 msr, u64 value)
444 {
445 if (!ms_hyperv.paravisor_present)
446 return;
447
448 if (hv_isolation_type_tdx())
449 hv_tdx_msr_write(msr, value);
450 else if (hv_isolation_type_snp())
451 hv_ghcb_msr_write(msr, value);
452 }
453
hv_ivm_msr_read(u64 msr,u64 * value)454 void hv_ivm_msr_read(u64 msr, u64 *value)
455 {
456 if (!ms_hyperv.paravisor_present)
457 return;
458
459 if (hv_isolation_type_tdx())
460 hv_tdx_msr_read(msr, value);
461 else if (hv_isolation_type_snp())
462 hv_ghcb_msr_read(msr, value);
463 }
464
465 /*
466 * hv_mark_gpa_visibility - Set pages visible to host via hvcall.
467 *
468 * In Isolation VM, all guest memory is encrypted from host and guest
469 * needs to set memory visible to host via hvcall before sharing memory
470 * with host.
471 */
hv_mark_gpa_visibility(u16 count,const u64 pfn[],enum hv_mem_host_visibility visibility)472 static int hv_mark_gpa_visibility(u16 count, const u64 pfn[],
473 enum hv_mem_host_visibility visibility)
474 {
475 struct hv_gpa_range_for_visibility *input;
476 u64 hv_status;
477 unsigned long flags;
478
479 /* no-op if partition isolation is not enabled */
480 if (!hv_is_isolation_supported())
481 return 0;
482
483 if (count > HV_MAX_MODIFY_GPA_REP_COUNT) {
484 pr_err("Hyper-V: GPA count:%d exceeds supported:%lu\n", count,
485 HV_MAX_MODIFY_GPA_REP_COUNT);
486 return -EINVAL;
487 }
488
489 local_irq_save(flags);
490 input = *this_cpu_ptr(hyperv_pcpu_input_arg);
491
492 if (unlikely(!input)) {
493 local_irq_restore(flags);
494 return -EINVAL;
495 }
496
497 input->partition_id = HV_PARTITION_ID_SELF;
498 input->host_visibility = visibility;
499 input->reserved0 = 0;
500 input->reserved1 = 0;
501 memcpy((void *)input->gpa_page_list, pfn, count * sizeof(*pfn));
502 hv_status = hv_do_rep_hypercall(
503 HVCALL_MODIFY_SPARSE_GPA_PAGE_HOST_VISIBILITY, count,
504 0, input, NULL);
505 local_irq_restore(flags);
506
507 if (hv_result_success(hv_status))
508 return 0;
509 else
510 return -EFAULT;
511 }
512
513 /*
514 * When transitioning memory between encrypted and decrypted, the caller
515 * of set_memory_encrypted() or set_memory_decrypted() is responsible for
516 * ensuring that the memory isn't in use and isn't referenced while the
517 * transition is in progress. The transition has multiple steps, and the
518 * memory is in an inconsistent state until all steps are complete. A
519 * reference while the state is inconsistent could result in an exception
520 * that can't be cleanly fixed up.
521 *
522 * But the Linux kernel load_unaligned_zeropad() mechanism could cause a
523 * stray reference that can't be prevented by the caller, so Linux has
524 * specific code to handle this case. But when the #VC and #VE exceptions
525 * routed to a paravisor, the specific code doesn't work. To avoid this
526 * problem, mark the pages as "not present" while the transition is in
527 * progress. If load_unaligned_zeropad() causes a stray reference, a normal
528 * page fault is generated instead of #VC or #VE, and the page-fault-based
529 * handlers for load_unaligned_zeropad() resolve the reference. When the
530 * transition is complete, hv_vtom_set_host_visibility() marks the pages
531 * as "present" again.
532 */
hv_vtom_clear_present(unsigned long kbuffer,int pagecount,bool enc)533 static int hv_vtom_clear_present(unsigned long kbuffer, int pagecount, bool enc)
534 {
535 return set_memory_np(kbuffer, pagecount);
536 }
537
538 /*
539 * hv_vtom_set_host_visibility - Set specified memory visible to host.
540 *
541 * In Isolation VM, all guest memory is encrypted from host and guest
542 * needs to set memory visible to host via hvcall before sharing memory
543 * with host. This function works as wrap of hv_mark_gpa_visibility()
544 * with memory base and size.
545 */
hv_vtom_set_host_visibility(unsigned long kbuffer,int pagecount,bool enc)546 static int hv_vtom_set_host_visibility(unsigned long kbuffer, int pagecount, bool enc)
547 {
548 enum hv_mem_host_visibility visibility = enc ?
549 VMBUS_PAGE_NOT_VISIBLE : VMBUS_PAGE_VISIBLE_READ_WRITE;
550 u64 *pfn_array;
551 phys_addr_t paddr;
552 int i, pfn, err;
553 void *vaddr;
554 int ret = 0;
555
556 pfn_array = kmalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL);
557 if (!pfn_array) {
558 ret = -ENOMEM;
559 goto err_set_memory_p;
560 }
561
562 for (i = 0, pfn = 0; i < pagecount; i++) {
563 /*
564 * Use slow_virt_to_phys() because the PRESENT bit has been
565 * temporarily cleared in the PTEs. slow_virt_to_phys() works
566 * without the PRESENT bit while virt_to_hvpfn() or similar
567 * does not.
568 */
569 vaddr = (void *)kbuffer + (i * HV_HYP_PAGE_SIZE);
570 paddr = slow_virt_to_phys(vaddr);
571 pfn_array[pfn] = paddr >> HV_HYP_PAGE_SHIFT;
572 pfn++;
573
574 if (pfn == HV_MAX_MODIFY_GPA_REP_COUNT || i == pagecount - 1) {
575 ret = hv_mark_gpa_visibility(pfn, pfn_array,
576 visibility);
577 if (ret)
578 goto err_free_pfn_array;
579 pfn = 0;
580 }
581 }
582
583 err_free_pfn_array:
584 kfree(pfn_array);
585
586 err_set_memory_p:
587 /*
588 * Set the PTE PRESENT bits again to revert what hv_vtom_clear_present()
589 * did. Do this even if there is an error earlier in this function in
590 * order to avoid leaving the memory range in a "broken" state. Setting
591 * the PRESENT bits shouldn't fail, but return an error if it does.
592 */
593 err = set_memory_p(kbuffer, pagecount);
594 if (err && !ret)
595 ret = err;
596
597 return ret;
598 }
599
hv_vtom_tlb_flush_required(bool private)600 static bool hv_vtom_tlb_flush_required(bool private)
601 {
602 /*
603 * Since hv_vtom_clear_present() marks the PTEs as "not present"
604 * and flushes the TLB, they can't be in the TLB. That makes the
605 * flush controlled by this function redundant, so return "false".
606 */
607 return false;
608 }
609
hv_vtom_cache_flush_required(void)610 static bool hv_vtom_cache_flush_required(void)
611 {
612 return false;
613 }
614
hv_is_private_mmio(u64 addr)615 static bool hv_is_private_mmio(u64 addr)
616 {
617 /*
618 * Hyper-V always provides a single IO-APIC in a guest VM.
619 * When a paravisor is used, it is emulated by the paravisor
620 * in the guest context and must be mapped private.
621 */
622 if (addr >= HV_IOAPIC_BASE_ADDRESS &&
623 addr < (HV_IOAPIC_BASE_ADDRESS + PAGE_SIZE))
624 return true;
625
626 /* Same with a vTPM */
627 if (addr >= VTPM_BASE_ADDRESS &&
628 addr < (VTPM_BASE_ADDRESS + PAGE_SIZE))
629 return true;
630
631 return false;
632 }
633
hv_vtom_init(void)634 void __init hv_vtom_init(void)
635 {
636 enum hv_isolation_type type = hv_get_isolation_type();
637
638 switch (type) {
639 case HV_ISOLATION_TYPE_VBS:
640 fallthrough;
641 /*
642 * By design, a VM using vTOM doesn't see the SEV setting,
643 * so SEV initialization is bypassed and sev_status isn't set.
644 * Set it here to indicate a vTOM VM.
645 *
646 * Note: if CONFIG_AMD_MEM_ENCRYPT is not set, sev_status is
647 * defined as 0ULL, to which we can't assigned a value.
648 */
649 #ifdef CONFIG_AMD_MEM_ENCRYPT
650 case HV_ISOLATION_TYPE_SNP:
651 sev_status = MSR_AMD64_SNP_VTOM;
652 cc_vendor = CC_VENDOR_AMD;
653 break;
654 #endif
655
656 case HV_ISOLATION_TYPE_TDX:
657 cc_vendor = CC_VENDOR_INTEL;
658 break;
659
660 default:
661 panic("hv_vtom_init: unsupported isolation type %d\n", type);
662 }
663
664 cc_set_mask(ms_hyperv.shared_gpa_boundary);
665 physical_mask &= ms_hyperv.shared_gpa_boundary - 1;
666
667 x86_platform.hyper.is_private_mmio = hv_is_private_mmio;
668 x86_platform.guest.enc_cache_flush_required = hv_vtom_cache_flush_required;
669 x86_platform.guest.enc_tlb_flush_required = hv_vtom_tlb_flush_required;
670 x86_platform.guest.enc_status_change_prepare = hv_vtom_clear_present;
671 x86_platform.guest.enc_status_change_finish = hv_vtom_set_host_visibility;
672
673 /* Set WB as the default cache mode. */
674 guest_force_mtrr_state(NULL, 0, MTRR_TYPE_WRBACK);
675 }
676
677 #endif /* defined(CONFIG_AMD_MEM_ENCRYPT) || defined(CONFIG_INTEL_TDX_GUEST) */
678
hv_get_isolation_type(void)679 enum hv_isolation_type hv_get_isolation_type(void)
680 {
681 if (!(ms_hyperv.priv_high & HV_ISOLATION))
682 return HV_ISOLATION_TYPE_NONE;
683 return FIELD_GET(HV_ISOLATION_TYPE, ms_hyperv.isolation_config_b);
684 }
685 EXPORT_SYMBOL_GPL(hv_get_isolation_type);
686
687 /*
688 * hv_is_isolation_supported - Check system runs in the Hyper-V
689 * isolation VM.
690 */
hv_is_isolation_supported(void)691 bool hv_is_isolation_supported(void)
692 {
693 if (!cpu_feature_enabled(X86_FEATURE_HYPERVISOR))
694 return false;
695
696 if (!hypervisor_is_type(X86_HYPER_MS_HYPERV))
697 return false;
698
699 return hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE;
700 }
701
702 DEFINE_STATIC_KEY_FALSE(isolation_type_snp);
703
704 /*
705 * hv_isolation_type_snp - Check if the system runs in an AMD SEV-SNP based
706 * isolation VM.
707 */
hv_isolation_type_snp(void)708 bool hv_isolation_type_snp(void)
709 {
710 return static_branch_unlikely(&isolation_type_snp);
711 }
712
713 DEFINE_STATIC_KEY_FALSE(isolation_type_tdx);
714 /*
715 * hv_isolation_type_tdx - Check if the system runs in an Intel TDX based
716 * isolated VM.
717 */
hv_isolation_type_tdx(void)718 bool hv_isolation_type_tdx(void)
719 {
720 return static_branch_unlikely(&isolation_type_tdx);
721 }
722