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