xref: /kvm-unit-tests/lib/x86/amd_sev.c (revision 5d80d64dc4823c3f80d9c8a5f553498967dcef6e)
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 	struct cpuid cpuid_out;
21350bf64aSZixuan Wang 	static bool sev_enabled;
22350bf64aSZixuan Wang 	static bool initialized = false;
23350bf64aSZixuan Wang 
24350bf64aSZixuan Wang 	/* Check CPUID and MSR for SEV status and store it for future function calls. */
25350bf64aSZixuan Wang 	if (!initialized) {
26350bf64aSZixuan Wang 		sev_enabled = false;
27350bf64aSZixuan Wang 		initialized = true;
28350bf64aSZixuan Wang 
29350bf64aSZixuan Wang 		/* Test if we can query SEV features */
30350bf64aSZixuan Wang 		cpuid_out = cpuid(CPUID_FN_LARGEST_EXT_FUNC_NUM);
31350bf64aSZixuan Wang 		if (cpuid_out.a < CPUID_FN_ENCRYPT_MEM_CAPAB) {
32350bf64aSZixuan Wang 			return sev_enabled;
33350bf64aSZixuan Wang 		}
34350bf64aSZixuan Wang 
35350bf64aSZixuan Wang 		/* Test if SEV is supported */
36350bf64aSZixuan Wang 		cpuid_out = cpuid(CPUID_FN_ENCRYPT_MEM_CAPAB);
37350bf64aSZixuan Wang 		if (!(cpuid_out.a & SEV_SUPPORT_MASK)) {
38350bf64aSZixuan Wang 			return sev_enabled;
39350bf64aSZixuan Wang 		}
40350bf64aSZixuan Wang 
41350bf64aSZixuan Wang 		/* Test if SEV is enabled */
42350bf64aSZixuan Wang 		if (rdmsr(MSR_SEV_STATUS) & SEV_ENABLED_MASK) {
43350bf64aSZixuan Wang 			sev_enabled = true;
44350bf64aSZixuan Wang 		}
45350bf64aSZixuan Wang 	}
46350bf64aSZixuan Wang 
47350bf64aSZixuan Wang 	return sev_enabled;
48350bf64aSZixuan Wang }
49350bf64aSZixuan Wang 
50350bf64aSZixuan Wang efi_status_t setup_amd_sev(void)
51350bf64aSZixuan Wang {
52350bf64aSZixuan Wang 	struct cpuid cpuid_out;
53350bf64aSZixuan Wang 
54350bf64aSZixuan Wang 	if (!amd_sev_enabled()) {
55350bf64aSZixuan Wang 		return EFI_UNSUPPORTED;
56350bf64aSZixuan Wang 	}
57350bf64aSZixuan Wang 
58350bf64aSZixuan Wang 	/*
59350bf64aSZixuan Wang 	 * Extract C-Bit position from ebx[5:0]
60350bf64aSZixuan Wang 	 * AMD64 Architecture Programmer's Manual Volume 3
61350bf64aSZixuan Wang 	 *   - Section " Function 8000_001Fh - Encrypted Memory Capabilities"
62350bf64aSZixuan Wang 	 */
63350bf64aSZixuan Wang 	cpuid_out = cpuid(CPUID_FN_ENCRYPT_MEM_CAPAB);
64350bf64aSZixuan Wang 	amd_sev_c_bit_pos = (unsigned short)(cpuid_out.b & 0x3f);
65350bf64aSZixuan Wang 
66350bf64aSZixuan Wang 	return EFI_SUCCESS;
67350bf64aSZixuan Wang }
68350bf64aSZixuan Wang 
69bf812590SZixuan Wang bool amd_sev_es_enabled(void)
70bf812590SZixuan Wang {
71bf812590SZixuan Wang 	static bool sev_es_enabled;
72bf812590SZixuan Wang 	static bool initialized = false;
73bf812590SZixuan Wang 
74bf812590SZixuan Wang 	if (!initialized) {
75bf812590SZixuan Wang 		sev_es_enabled = false;
76bf812590SZixuan Wang 		initialized = true;
77bf812590SZixuan Wang 
78bf812590SZixuan Wang 		if (!amd_sev_enabled()) {
79bf812590SZixuan Wang 			return sev_es_enabled;
80bf812590SZixuan Wang 		}
81bf812590SZixuan Wang 
82bf812590SZixuan Wang 		/* Test if SEV-ES is enabled */
83bf812590SZixuan Wang 		if (rdmsr(MSR_SEV_STATUS) & SEV_ES_ENABLED_MASK) {
84bf812590SZixuan Wang 			sev_es_enabled = true;
85bf812590SZixuan Wang 		}
86bf812590SZixuan Wang 	}
87bf812590SZixuan Wang 
88bf812590SZixuan Wang 	return sev_es_enabled;
89bf812590SZixuan Wang }
90bf812590SZixuan Wang 
91706ede18SZixuan Wang efi_status_t setup_amd_sev_es(void)
92706ede18SZixuan Wang {
93706ede18SZixuan Wang 	struct descriptor_table_ptr idtr;
94706ede18SZixuan Wang 	idt_entry_t *idt;
95706ede18SZixuan Wang 	idt_entry_t vc_handler_idt;
96706ede18SZixuan Wang 
97706ede18SZixuan Wang 	if (!amd_sev_es_enabled()) {
98706ede18SZixuan Wang 		return EFI_UNSUPPORTED;
99706ede18SZixuan Wang 	}
100706ede18SZixuan Wang 
101706ede18SZixuan Wang 	/*
102706ede18SZixuan Wang 	 * Copy UEFI's #VC IDT entry, so KVM-Unit-Tests can reuse it and does
103706ede18SZixuan Wang 	 * not have to re-implement a #VC handler. Also update the #VC IDT code
104706ede18SZixuan Wang 	 * segment to use KVM-Unit-Tests segments, KERNEL_CS, so that we do not
105706ede18SZixuan Wang 	 * have to copy the UEFI GDT entries into KVM-Unit-Tests GDT.
106706ede18SZixuan Wang 	 *
107706ede18SZixuan Wang 	 * TODO: Reusing UEFI #VC handler is a temporary workaround to simplify
108706ede18SZixuan Wang 	 * the boot up process, the long-term solution is to implement a #VC
109706ede18SZixuan Wang 	 * handler in kvm-unit-tests and load it, so that kvm-unit-tests does
110706ede18SZixuan Wang 	 * not depend on specific UEFI #VC handler implementation.
111706ede18SZixuan Wang 	 */
112706ede18SZixuan Wang 	sidt(&idtr);
113706ede18SZixuan Wang 	idt = (idt_entry_t *)idtr.base;
114*5d80d64dSSean Christopherson 	vc_handler_idt = idt[VC_VECTOR];
115706ede18SZixuan Wang 	vc_handler_idt.selector = KERNEL_CS;
116*5d80d64dSSean Christopherson 	boot_idt[VC_VECTOR] = vc_handler_idt;
117706ede18SZixuan Wang 
118706ede18SZixuan Wang 	return EFI_SUCCESS;
119706ede18SZixuan Wang }
120706ede18SZixuan Wang 
121b114aa57SZixuan Wang void setup_ghcb_pte(pgd_t *page_table)
122b114aa57SZixuan Wang {
123b114aa57SZixuan Wang 	/*
124b114aa57SZixuan Wang 	 * SEV-ES guest uses GHCB page to communicate with the host. This page
125b114aa57SZixuan Wang 	 * must be unencrypted, i.e. its c-bit should be unset. To do so, this
126b114aa57SZixuan Wang 	 * function searches GHCB's L1 pte, creates corresponding L1 ptes if not
127b114aa57SZixuan Wang 	 * found, and unsets the c-bit of GHCB's L1 pte.
128b114aa57SZixuan Wang 	 */
129b114aa57SZixuan Wang 	phys_addr_t ghcb_addr, ghcb_base_addr;
130b114aa57SZixuan Wang 	pteval_t *pte;
131b114aa57SZixuan Wang 
132b114aa57SZixuan Wang 	/* Read the current GHCB page addr */
133b114aa57SZixuan Wang 	ghcb_addr = rdmsr(SEV_ES_GHCB_MSR_INDEX);
134b114aa57SZixuan Wang 
135b114aa57SZixuan Wang 	/* Search Level 1 page table entry for GHCB page */
136b114aa57SZixuan Wang 	pte = get_pte_level(page_table, (void *)ghcb_addr, 1);
137b114aa57SZixuan Wang 
138b114aa57SZixuan Wang 	/* Create Level 1 pte for GHCB page if not found */
139b114aa57SZixuan Wang 	if (pte == NULL) {
140b114aa57SZixuan Wang 		/* Find Level 2 page base address */
141b114aa57SZixuan Wang 		ghcb_base_addr = ghcb_addr & ~(LARGE_PAGE_SIZE - 1);
142b114aa57SZixuan Wang 		/* Install Level 1 ptes */
143b114aa57SZixuan Wang 		install_pages(page_table, ghcb_base_addr, LARGE_PAGE_SIZE, (void *)ghcb_base_addr);
144b114aa57SZixuan Wang 		/* Find Level 2 pte, set as 4KB pages */
145b114aa57SZixuan Wang 		pte = get_pte_level(page_table, (void *)ghcb_addr, 2);
146b114aa57SZixuan Wang 		assert(pte);
147b114aa57SZixuan Wang 		*pte &= ~(PT_PAGE_SIZE_MASK);
148b114aa57SZixuan Wang 		/* Find Level 1 GHCB pte */
149b114aa57SZixuan Wang 		pte = get_pte_level(page_table, (void *)ghcb_addr, 1);
150b114aa57SZixuan Wang 		assert(pte);
151b114aa57SZixuan Wang 	}
152b114aa57SZixuan Wang 
153b114aa57SZixuan Wang 	/* Unset c-bit in Level 1 GHCB pte */
154b114aa57SZixuan Wang 	*pte &= ~(get_amd_sev_c_bit_mask());
155b114aa57SZixuan Wang }
156b114aa57SZixuan Wang 
157350bf64aSZixuan Wang unsigned long long get_amd_sev_c_bit_mask(void)
158350bf64aSZixuan Wang {
159350bf64aSZixuan Wang 	if (amd_sev_enabled()) {
160350bf64aSZixuan Wang 		return 1ull << amd_sev_c_bit_pos;
161350bf64aSZixuan Wang 	} else {
162350bf64aSZixuan Wang 		return 0;
163350bf64aSZixuan Wang 	}
164350bf64aSZixuan Wang }
16530203ea5SZixuan Wang 
16630203ea5SZixuan Wang unsigned long long get_amd_sev_addr_upperbound(void)
16730203ea5SZixuan Wang {
16830203ea5SZixuan Wang 	if (amd_sev_enabled()) {
16930203ea5SZixuan Wang 		return amd_sev_c_bit_pos - 1;
17030203ea5SZixuan Wang 	} else {
17130203ea5SZixuan Wang 		/* Default memory upper bound */
17230203ea5SZixuan Wang 		return PT_ADDR_UPPER_BOUND_DEFAULT;
17330203ea5SZixuan Wang 	}
17430203ea5SZixuan Wang }
175