1 /* 2 * AMD SEV support in kvm-unit-tests 3 * 4 * Copyright (c) 2021, Google Inc 5 * 6 * Authors: 7 * Zixuan Wang <zixuanwang@google.com> 8 * 9 * SPDX-License-Identifier: LGPL-2.0-or-later 10 */ 11 12 #include "amd_sev.h" 13 #include "x86/processor.h" 14 #include "x86/vm.h" 15 16 static unsigned short amd_sev_c_bit_pos; 17 18 bool amd_sev_enabled(void) 19 { 20 static bool sev_enabled; 21 static bool initialized = false; 22 23 /* Check CPUID and MSR for SEV status and store it for future function calls. */ 24 if (!initialized) { 25 initialized = true; 26 27 sev_enabled = this_cpu_has(X86_FEATURE_SEV) && 28 rdmsr(MSR_SEV_STATUS) & SEV_ENABLED_MASK; 29 } 30 31 return sev_enabled; 32 } 33 34 efi_status_t setup_amd_sev(void) 35 { 36 struct cpuid cpuid_out; 37 38 if (!amd_sev_enabled()) { 39 return EFI_UNSUPPORTED; 40 } 41 42 /* 43 * Extract C-Bit position from ebx[5:0] 44 * AMD64 Architecture Programmer's Manual Volume 3 45 * - Section " Function 8000_001Fh - Encrypted Memory Capabilities" 46 */ 47 cpuid_out = cpuid(CPUID_FN_ENCRYPT_MEM_CAPAB); 48 amd_sev_c_bit_pos = (unsigned short)(cpuid_out.b & 0x3f); 49 50 return EFI_SUCCESS; 51 } 52 53 bool amd_sev_es_enabled(void) 54 { 55 static bool sev_es_enabled; 56 static bool initialized = false; 57 58 if (!initialized) { 59 initialized = true; 60 61 sev_es_enabled = amd_sev_enabled() && 62 this_cpu_has(X86_FEATURE_SEV_ES) && 63 rdmsr(MSR_SEV_STATUS) & SEV_ES_ENABLED_MASK; 64 } 65 66 return sev_es_enabled; 67 } 68 69 efi_status_t setup_amd_sev_es(void) 70 { 71 struct descriptor_table_ptr idtr; 72 idt_entry_t *idt; 73 idt_entry_t vc_handler_idt; 74 75 if (!amd_sev_es_enabled()) { 76 return EFI_UNSUPPORTED; 77 } 78 79 /* 80 * Copy UEFI's #VC IDT entry, so KVM-Unit-Tests can reuse it and does 81 * not have to re-implement a #VC handler. Also update the #VC IDT code 82 * segment to use KVM-Unit-Tests segments, KERNEL_CS, so that we do not 83 * have to copy the UEFI GDT entries into KVM-Unit-Tests GDT. 84 * 85 * TODO: Reusing UEFI #VC handler is a temporary workaround to simplify 86 * the boot up process, the long-term solution is to implement a #VC 87 * handler in kvm-unit-tests and load it, so that kvm-unit-tests does 88 * not depend on specific UEFI #VC handler implementation. 89 */ 90 sidt(&idtr); 91 idt = (idt_entry_t *)idtr.base; 92 vc_handler_idt = idt[VC_VECTOR]; 93 vc_handler_idt.selector = KERNEL_CS; 94 boot_idt[VC_VECTOR] = vc_handler_idt; 95 96 return EFI_SUCCESS; 97 } 98 99 void setup_ghcb_pte(pgd_t *page_table) 100 { 101 /* 102 * SEV-ES guest uses GHCB page to communicate with the host. This page 103 * must be unencrypted, i.e. its c-bit should be unset. To do so, this 104 * function searches GHCB's L1 pte, creates corresponding L1 ptes if not 105 * found, and unsets the c-bit of GHCB's L1 pte. 106 */ 107 phys_addr_t ghcb_addr, ghcb_base_addr; 108 pteval_t *pte; 109 110 /* Read the current GHCB page addr */ 111 ghcb_addr = rdmsr(SEV_ES_GHCB_MSR_INDEX); 112 113 /* Search Level 1 page table entry for GHCB page */ 114 pte = get_pte_level(page_table, (void *)ghcb_addr, 1); 115 116 /* Create Level 1 pte for GHCB page if not found */ 117 if (pte == NULL) { 118 /* Find Level 2 page base address */ 119 ghcb_base_addr = ghcb_addr & ~(LARGE_PAGE_SIZE - 1); 120 /* Install Level 1 ptes */ 121 install_pages(page_table, ghcb_base_addr, LARGE_PAGE_SIZE, (void *)ghcb_base_addr); 122 /* Find Level 2 pte, set as 4KB pages */ 123 pte = get_pte_level(page_table, (void *)ghcb_addr, 2); 124 assert(pte); 125 *pte &= ~(PT_PAGE_SIZE_MASK); 126 /* Find Level 1 GHCB pte */ 127 pte = get_pte_level(page_table, (void *)ghcb_addr, 1); 128 assert(pte); 129 } 130 131 /* Unset c-bit in Level 1 GHCB pte */ 132 *pte &= ~(get_amd_sev_c_bit_mask()); 133 } 134 135 unsigned long long get_amd_sev_c_bit_mask(void) 136 { 137 if (amd_sev_enabled()) { 138 return 1ull << amd_sev_c_bit_pos; 139 } else { 140 return 0; 141 } 142 } 143 144 unsigned long long get_amd_sev_addr_upperbound(void) 145 { 146 if (amd_sev_enabled()) { 147 return amd_sev_c_bit_pos - 1; 148 } else { 149 /* Default memory upper bound */ 150 return PT_ADDR_UPPER_BOUND_DEFAULT; 151 } 152 } 153