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
amd_sev_enabled(void)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
setup_amd_sev(void)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
amd_sev_es_enabled(void)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
setup_amd_sev_es(void)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
setup_ghcb_pte(pgd_t * page_table)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
get_amd_sev_c_bit_mask(void)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
get_amd_sev_addr_upperbound(void)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