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. */ 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 114 static inline u64 rd_ghcb_msr(void) 115 { 116 return native_rdmsrq(MSR_AMD64_SEV_ES_GHCB); 117 } 118 119 static inline void wr_ghcb_msr(u64 val) 120 { 121 native_wrmsrq(MSR_AMD64_SEV_ES_GHCB, val); 122 } 123 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 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 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 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 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 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 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 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 389 static inline void hv_ghcb_msr_write(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 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 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 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 438 static inline void hv_tdx_msr_write(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) 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 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 */ 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 */ 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 */ 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 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 610 static bool hv_vtom_cache_flush_required(void) 611 { 612 return false; 613 } 614 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 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 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 */ 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 */ 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 */ 718 bool hv_isolation_type_tdx(void) 719 { 720 return static_branch_unlikely(&isolation_type_tdx); 721 } 722