1350bf64aSZixuan Wang /* 2350bf64aSZixuan Wang * AMD SEV support in kvm-unit-tests 3350bf64aSZixuan Wang * 4350bf64aSZixuan Wang * Copyright (c) 2021, Google Inc 5350bf64aSZixuan Wang * 6350bf64aSZixuan Wang * Authors: 7350bf64aSZixuan Wang * Zixuan Wang <zixuanwang@google.com> 8350bf64aSZixuan Wang * 9350bf64aSZixuan Wang * SPDX-License-Identifier: LGPL-2.0-or-later 10350bf64aSZixuan Wang */ 11350bf64aSZixuan Wang 12350bf64aSZixuan Wang #include "amd_sev.h" 13350bf64aSZixuan Wang #include "x86/processor.h" 14b114aa57SZixuan Wang #include "x86/vm.h" 15350bf64aSZixuan Wang 16350bf64aSZixuan Wang static unsigned short amd_sev_c_bit_pos; 17350bf64aSZixuan Wang 18350bf64aSZixuan Wang bool amd_sev_enabled(void) 19350bf64aSZixuan Wang { 20350bf64aSZixuan Wang static bool sev_enabled; 21350bf64aSZixuan Wang static bool initialized = false; 22350bf64aSZixuan Wang 23350bf64aSZixuan Wang /* Check CPUID and MSR for SEV status and store it for future function calls. */ 24350bf64aSZixuan Wang if (!initialized) { 25350bf64aSZixuan Wang initialized = true; 26350bf64aSZixuan Wang 27*b643ae62SSean Christopherson sev_enabled = this_cpu_has(X86_FEATURE_SEV) && 28*b643ae62SSean Christopherson rdmsr(MSR_SEV_STATUS) & SEV_ENABLED_MASK; 29350bf64aSZixuan Wang } 30350bf64aSZixuan Wang 31350bf64aSZixuan Wang return sev_enabled; 32350bf64aSZixuan Wang } 33350bf64aSZixuan Wang 34350bf64aSZixuan Wang efi_status_t setup_amd_sev(void) 35350bf64aSZixuan Wang { 36350bf64aSZixuan Wang struct cpuid cpuid_out; 37350bf64aSZixuan Wang 38350bf64aSZixuan Wang if (!amd_sev_enabled()) { 39350bf64aSZixuan Wang return EFI_UNSUPPORTED; 40350bf64aSZixuan Wang } 41350bf64aSZixuan Wang 42350bf64aSZixuan Wang /* 43350bf64aSZixuan Wang * Extract C-Bit position from ebx[5:0] 44350bf64aSZixuan Wang * AMD64 Architecture Programmer's Manual Volume 3 45350bf64aSZixuan Wang * - Section " Function 8000_001Fh - Encrypted Memory Capabilities" 46350bf64aSZixuan Wang */ 47350bf64aSZixuan Wang cpuid_out = cpuid(CPUID_FN_ENCRYPT_MEM_CAPAB); 48350bf64aSZixuan Wang amd_sev_c_bit_pos = (unsigned short)(cpuid_out.b & 0x3f); 49350bf64aSZixuan Wang 50350bf64aSZixuan Wang return EFI_SUCCESS; 51350bf64aSZixuan Wang } 52350bf64aSZixuan Wang 53bf812590SZixuan Wang bool amd_sev_es_enabled(void) 54bf812590SZixuan Wang { 55bf812590SZixuan Wang static bool sev_es_enabled; 56bf812590SZixuan Wang static bool initialized = false; 57bf812590SZixuan Wang 58bf812590SZixuan Wang if (!initialized) { 59bf812590SZixuan Wang initialized = true; 60bf812590SZixuan Wang 61*b643ae62SSean Christopherson sev_es_enabled = amd_sev_enabled() && 62*b643ae62SSean Christopherson this_cpu_has(X86_FEATURE_SEV_ES) && 63*b643ae62SSean Christopherson rdmsr(MSR_SEV_STATUS) & SEV_ES_ENABLED_MASK; 64bf812590SZixuan Wang } 65bf812590SZixuan Wang 66bf812590SZixuan Wang return sev_es_enabled; 67bf812590SZixuan Wang } 68bf812590SZixuan Wang 69706ede18SZixuan Wang efi_status_t setup_amd_sev_es(void) 70706ede18SZixuan Wang { 71706ede18SZixuan Wang struct descriptor_table_ptr idtr; 72706ede18SZixuan Wang idt_entry_t *idt; 73706ede18SZixuan Wang idt_entry_t vc_handler_idt; 74706ede18SZixuan Wang 75706ede18SZixuan Wang if (!amd_sev_es_enabled()) { 76706ede18SZixuan Wang return EFI_UNSUPPORTED; 77706ede18SZixuan Wang } 78706ede18SZixuan Wang 79706ede18SZixuan Wang /* 80706ede18SZixuan Wang * Copy UEFI's #VC IDT entry, so KVM-Unit-Tests can reuse it and does 81706ede18SZixuan Wang * not have to re-implement a #VC handler. Also update the #VC IDT code 82706ede18SZixuan Wang * segment to use KVM-Unit-Tests segments, KERNEL_CS, so that we do not 83706ede18SZixuan Wang * have to copy the UEFI GDT entries into KVM-Unit-Tests GDT. 84706ede18SZixuan Wang * 85706ede18SZixuan Wang * TODO: Reusing UEFI #VC handler is a temporary workaround to simplify 86706ede18SZixuan Wang * the boot up process, the long-term solution is to implement a #VC 87706ede18SZixuan Wang * handler in kvm-unit-tests and load it, so that kvm-unit-tests does 88706ede18SZixuan Wang * not depend on specific UEFI #VC handler implementation. 89706ede18SZixuan Wang */ 90706ede18SZixuan Wang sidt(&idtr); 91706ede18SZixuan Wang idt = (idt_entry_t *)idtr.base; 925d80d64dSSean Christopherson vc_handler_idt = idt[VC_VECTOR]; 93706ede18SZixuan Wang vc_handler_idt.selector = KERNEL_CS; 945d80d64dSSean Christopherson boot_idt[VC_VECTOR] = vc_handler_idt; 95706ede18SZixuan Wang 96706ede18SZixuan Wang return EFI_SUCCESS; 97706ede18SZixuan Wang } 98706ede18SZixuan Wang 99b114aa57SZixuan Wang void setup_ghcb_pte(pgd_t *page_table) 100b114aa57SZixuan Wang { 101b114aa57SZixuan Wang /* 102b114aa57SZixuan Wang * SEV-ES guest uses GHCB page to communicate with the host. This page 103b114aa57SZixuan Wang * must be unencrypted, i.e. its c-bit should be unset. To do so, this 104b114aa57SZixuan Wang * function searches GHCB's L1 pte, creates corresponding L1 ptes if not 105b114aa57SZixuan Wang * found, and unsets the c-bit of GHCB's L1 pte. 106b114aa57SZixuan Wang */ 107b114aa57SZixuan Wang phys_addr_t ghcb_addr, ghcb_base_addr; 108b114aa57SZixuan Wang pteval_t *pte; 109b114aa57SZixuan Wang 110b114aa57SZixuan Wang /* Read the current GHCB page addr */ 111b114aa57SZixuan Wang ghcb_addr = rdmsr(SEV_ES_GHCB_MSR_INDEX); 112b114aa57SZixuan Wang 113b114aa57SZixuan Wang /* Search Level 1 page table entry for GHCB page */ 114b114aa57SZixuan Wang pte = get_pte_level(page_table, (void *)ghcb_addr, 1); 115b114aa57SZixuan Wang 116b114aa57SZixuan Wang /* Create Level 1 pte for GHCB page if not found */ 117b114aa57SZixuan Wang if (pte == NULL) { 118b114aa57SZixuan Wang /* Find Level 2 page base address */ 119b114aa57SZixuan Wang ghcb_base_addr = ghcb_addr & ~(LARGE_PAGE_SIZE - 1); 120b114aa57SZixuan Wang /* Install Level 1 ptes */ 121b114aa57SZixuan Wang install_pages(page_table, ghcb_base_addr, LARGE_PAGE_SIZE, (void *)ghcb_base_addr); 122b114aa57SZixuan Wang /* Find Level 2 pte, set as 4KB pages */ 123b114aa57SZixuan Wang pte = get_pte_level(page_table, (void *)ghcb_addr, 2); 124b114aa57SZixuan Wang assert(pte); 125b114aa57SZixuan Wang *pte &= ~(PT_PAGE_SIZE_MASK); 126b114aa57SZixuan Wang /* Find Level 1 GHCB pte */ 127b114aa57SZixuan Wang pte = get_pte_level(page_table, (void *)ghcb_addr, 1); 128b114aa57SZixuan Wang assert(pte); 129b114aa57SZixuan Wang } 130b114aa57SZixuan Wang 131b114aa57SZixuan Wang /* Unset c-bit in Level 1 GHCB pte */ 132b114aa57SZixuan Wang *pte &= ~(get_amd_sev_c_bit_mask()); 133b114aa57SZixuan Wang } 134b114aa57SZixuan Wang 135350bf64aSZixuan Wang unsigned long long get_amd_sev_c_bit_mask(void) 136350bf64aSZixuan Wang { 137350bf64aSZixuan Wang if (amd_sev_enabled()) { 138350bf64aSZixuan Wang return 1ull << amd_sev_c_bit_pos; 139350bf64aSZixuan Wang } else { 140350bf64aSZixuan Wang return 0; 141350bf64aSZixuan Wang } 142350bf64aSZixuan Wang } 14330203ea5SZixuan Wang 14430203ea5SZixuan Wang unsigned long long get_amd_sev_addr_upperbound(void) 14530203ea5SZixuan Wang { 14630203ea5SZixuan Wang if (amd_sev_enabled()) { 14730203ea5SZixuan Wang return amd_sev_c_bit_pos - 1; 14830203ea5SZixuan Wang } else { 14930203ea5SZixuan Wang /* Default memory upper bound */ 15030203ea5SZixuan Wang return PT_ADDR_UPPER_BOUND_DEFAULT; 15130203ea5SZixuan Wang } 15230203ea5SZixuan Wang } 153