xref: /kvm-unit-tests/lib/x86/amd_sev.c (revision 706ede18334fb220669bed5e1638a82bb44d18c7)
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"
14350bf64aSZixuan Wang 
15350bf64aSZixuan Wang static unsigned short amd_sev_c_bit_pos;
16350bf64aSZixuan Wang 
17350bf64aSZixuan Wang bool amd_sev_enabled(void)
18350bf64aSZixuan Wang {
19350bf64aSZixuan Wang 	struct cpuid cpuid_out;
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 		sev_enabled = false;
26350bf64aSZixuan Wang 		initialized = true;
27350bf64aSZixuan Wang 
28350bf64aSZixuan Wang 		/* Test if we can query SEV features */
29350bf64aSZixuan Wang 		cpuid_out = cpuid(CPUID_FN_LARGEST_EXT_FUNC_NUM);
30350bf64aSZixuan Wang 		if (cpuid_out.a < CPUID_FN_ENCRYPT_MEM_CAPAB) {
31350bf64aSZixuan Wang 			return sev_enabled;
32350bf64aSZixuan Wang 		}
33350bf64aSZixuan Wang 
34350bf64aSZixuan Wang 		/* Test if SEV is supported */
35350bf64aSZixuan Wang 		cpuid_out = cpuid(CPUID_FN_ENCRYPT_MEM_CAPAB);
36350bf64aSZixuan Wang 		if (!(cpuid_out.a & SEV_SUPPORT_MASK)) {
37350bf64aSZixuan Wang 			return sev_enabled;
38350bf64aSZixuan Wang 		}
39350bf64aSZixuan Wang 
40350bf64aSZixuan Wang 		/* Test if SEV is enabled */
41350bf64aSZixuan Wang 		if (rdmsr(MSR_SEV_STATUS) & SEV_ENABLED_MASK) {
42350bf64aSZixuan Wang 			sev_enabled = true;
43350bf64aSZixuan Wang 		}
44350bf64aSZixuan Wang 	}
45350bf64aSZixuan Wang 
46350bf64aSZixuan Wang 	return sev_enabled;
47350bf64aSZixuan Wang }
48350bf64aSZixuan Wang 
49350bf64aSZixuan Wang efi_status_t setup_amd_sev(void)
50350bf64aSZixuan Wang {
51350bf64aSZixuan Wang 	struct cpuid cpuid_out;
52350bf64aSZixuan Wang 
53350bf64aSZixuan Wang 	if (!amd_sev_enabled()) {
54350bf64aSZixuan Wang 		return EFI_UNSUPPORTED;
55350bf64aSZixuan Wang 	}
56350bf64aSZixuan Wang 
57350bf64aSZixuan Wang 	/*
58350bf64aSZixuan Wang 	 * Extract C-Bit position from ebx[5:0]
59350bf64aSZixuan Wang 	 * AMD64 Architecture Programmer's Manual Volume 3
60350bf64aSZixuan Wang 	 *   - Section " Function 8000_001Fh - Encrypted Memory Capabilities"
61350bf64aSZixuan Wang 	 */
62350bf64aSZixuan Wang 	cpuid_out = cpuid(CPUID_FN_ENCRYPT_MEM_CAPAB);
63350bf64aSZixuan Wang 	amd_sev_c_bit_pos = (unsigned short)(cpuid_out.b & 0x3f);
64350bf64aSZixuan Wang 
65350bf64aSZixuan Wang 	return EFI_SUCCESS;
66350bf64aSZixuan Wang }
67350bf64aSZixuan Wang 
68bf812590SZixuan Wang bool amd_sev_es_enabled(void)
69bf812590SZixuan Wang {
70bf812590SZixuan Wang 	static bool sev_es_enabled;
71bf812590SZixuan Wang 	static bool initialized = false;
72bf812590SZixuan Wang 
73bf812590SZixuan Wang 	if (!initialized) {
74bf812590SZixuan Wang 		sev_es_enabled = false;
75bf812590SZixuan Wang 		initialized = true;
76bf812590SZixuan Wang 
77bf812590SZixuan Wang 		if (!amd_sev_enabled()) {
78bf812590SZixuan Wang 			return sev_es_enabled;
79bf812590SZixuan Wang 		}
80bf812590SZixuan Wang 
81bf812590SZixuan Wang 		/* Test if SEV-ES is enabled */
82bf812590SZixuan Wang 		if (rdmsr(MSR_SEV_STATUS) & SEV_ES_ENABLED_MASK) {
83bf812590SZixuan Wang 			sev_es_enabled = true;
84bf812590SZixuan Wang 		}
85bf812590SZixuan Wang 	}
86bf812590SZixuan Wang 
87bf812590SZixuan Wang 	return sev_es_enabled;
88bf812590SZixuan Wang }
89bf812590SZixuan Wang 
90*706ede18SZixuan Wang efi_status_t setup_amd_sev_es(void)
91*706ede18SZixuan Wang {
92*706ede18SZixuan Wang 	struct descriptor_table_ptr idtr;
93*706ede18SZixuan Wang 	idt_entry_t *idt;
94*706ede18SZixuan Wang 	idt_entry_t vc_handler_idt;
95*706ede18SZixuan Wang 
96*706ede18SZixuan Wang 	if (!amd_sev_es_enabled()) {
97*706ede18SZixuan Wang 		return EFI_UNSUPPORTED;
98*706ede18SZixuan Wang 	}
99*706ede18SZixuan Wang 
100*706ede18SZixuan Wang 	/*
101*706ede18SZixuan Wang 	 * Copy UEFI's #VC IDT entry, so KVM-Unit-Tests can reuse it and does
102*706ede18SZixuan Wang 	 * not have to re-implement a #VC handler. Also update the #VC IDT code
103*706ede18SZixuan Wang 	 * segment to use KVM-Unit-Tests segments, KERNEL_CS, so that we do not
104*706ede18SZixuan Wang 	 * have to copy the UEFI GDT entries into KVM-Unit-Tests GDT.
105*706ede18SZixuan Wang 	 *
106*706ede18SZixuan Wang 	 * TODO: Reusing UEFI #VC handler is a temporary workaround to simplify
107*706ede18SZixuan Wang 	 * the boot up process, the long-term solution is to implement a #VC
108*706ede18SZixuan Wang 	 * handler in kvm-unit-tests and load it, so that kvm-unit-tests does
109*706ede18SZixuan Wang 	 * not depend on specific UEFI #VC handler implementation.
110*706ede18SZixuan Wang 	 */
111*706ede18SZixuan Wang 	sidt(&idtr);
112*706ede18SZixuan Wang 	idt = (idt_entry_t *)idtr.base;
113*706ede18SZixuan Wang 	vc_handler_idt = idt[SEV_ES_VC_HANDLER_VECTOR];
114*706ede18SZixuan Wang 	vc_handler_idt.selector = KERNEL_CS;
115*706ede18SZixuan Wang 	boot_idt[SEV_ES_VC_HANDLER_VECTOR] = vc_handler_idt;
116*706ede18SZixuan Wang 
117*706ede18SZixuan Wang 	return EFI_SUCCESS;
118*706ede18SZixuan Wang }
119*706ede18SZixuan Wang 
120350bf64aSZixuan Wang unsigned long long get_amd_sev_c_bit_mask(void)
121350bf64aSZixuan Wang {
122350bf64aSZixuan Wang 	if (amd_sev_enabled()) {
123350bf64aSZixuan Wang 		return 1ull << amd_sev_c_bit_pos;
124350bf64aSZixuan Wang 	} else {
125350bf64aSZixuan Wang 		return 0;
126350bf64aSZixuan Wang 	}
127350bf64aSZixuan Wang }
12830203ea5SZixuan Wang 
12930203ea5SZixuan Wang unsigned long long get_amd_sev_addr_upperbound(void)
13030203ea5SZixuan Wang {
13130203ea5SZixuan Wang 	if (amd_sev_enabled()) {
13230203ea5SZixuan Wang 		return amd_sev_c_bit_pos - 1;
13330203ea5SZixuan Wang 	} else {
13430203ea5SZixuan Wang 		/* Default memory upper bound */
13530203ea5SZixuan Wang 		return PT_ADDR_UPPER_BOUND_DEFAULT;
13630203ea5SZixuan Wang 	}
13730203ea5SZixuan Wang }
138