xref: /linux/arch/x86/kernel/apic/x2apic_savic.c (revision 8c79a68de1d2d63537f2a318e5a3b27744c835ad)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * AMD Secure AVIC Support (SEV-SNP Guests)
4  *
5  * Copyright (C) 2024 Advanced Micro Devices, Inc.
6  *
7  * Author: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>
8  */
9 
10 #include <linux/cc_platform.h>
11 #include <linux/percpu-defs.h>
12 #include <linux/align.h>
13 
14 #include <asm/apic.h>
15 #include <asm/sev.h>
16 
17 #include "local.h"
18 
19 struct secure_avic_page {
20 	u8 regs[PAGE_SIZE];
21 } __aligned(PAGE_SIZE);
22 
23 static struct secure_avic_page __percpu *savic_page __ro_after_init;
24 
25 static int savic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
26 {
27 	return x2apic_enabled() && cc_platform_has(CC_ATTR_SNP_SECURE_AVIC);
28 }
29 
30 static inline void *get_reg_bitmap(unsigned int cpu, unsigned int offset)
31 {
32 	return &per_cpu_ptr(savic_page, cpu)->regs[offset];
33 }
34 
35 static inline void update_vector(unsigned int cpu, unsigned int offset,
36 				 unsigned int vector, bool set)
37 {
38 	void *bitmap = get_reg_bitmap(cpu, offset);
39 
40 	if (set)
41 		apic_set_vector(vector, bitmap);
42 	else
43 		apic_clear_vector(vector, bitmap);
44 }
45 
46 #define SAVIC_ALLOWED_IRR	0x204
47 
48 /*
49  * When Secure AVIC is enabled, RDMSR/WRMSR of the APIC registers
50  * result in #VC exception (for non-accelerated register accesses)
51  * with VMEXIT_AVIC_NOACCEL error code. The #VC exception handler
52  * can read/write the x2APIC register in the guest APIC backing page.
53  *
54  * Since doing this would increase the latency of accessing x2APIC
55  * registers, instead of doing RDMSR/WRMSR based accesses and
56  * handling the APIC register reads/writes in the #VC exception handler,
57  * the read() and write() callbacks directly read/write the APIC register
58  * from/to the vCPU's APIC backing page.
59  */
60 static u32 savic_read(u32 reg)
61 {
62 	void *ap = this_cpu_ptr(savic_page);
63 
64 	switch (reg) {
65 	case APIC_LVTT:
66 	case APIC_TMICT:
67 	case APIC_TMCCT:
68 	case APIC_TDCR:
69 	case APIC_ID:
70 	case APIC_LVR:
71 	case APIC_TASKPRI:
72 	case APIC_ARBPRI:
73 	case APIC_PROCPRI:
74 	case APIC_LDR:
75 	case APIC_SPIV:
76 	case APIC_ESR:
77 	case APIC_LVTTHMR:
78 	case APIC_LVTPC:
79 	case APIC_LVT0:
80 	case APIC_LVT1:
81 	case APIC_LVTERR:
82 	case APIC_EFEAT:
83 	case APIC_ECTRL:
84 	case APIC_SEOI:
85 	case APIC_IER:
86 	case APIC_EILVTn(0) ... APIC_EILVTn(3):
87 		return apic_get_reg(ap, reg);
88 	case APIC_ICR:
89 		return (u32)apic_get_reg64(ap, reg);
90 	case APIC_ISR ... APIC_ISR + 0x70:
91 	case APIC_TMR ... APIC_TMR + 0x70:
92 		if (WARN_ONCE(!IS_ALIGNED(reg, 16),
93 			      "APIC register read offset 0x%x not aligned at 16 bytes", reg))
94 			return 0;
95 		return apic_get_reg(ap, reg);
96 	/* IRR and ALLOWED_IRR offset range */
97 	case APIC_IRR ... APIC_IRR + 0x74:
98 		/*
99 		 * Valid APIC_IRR/SAVIC_ALLOWED_IRR registers are at 16 bytes strides from
100 		 * their respective base offset. APIC_IRRs are in the range
101 		 *
102 		 * (0x200, 0x210,  ..., 0x270)
103 		 *
104 		 * while the SAVIC_ALLOWED_IRR range starts 4 bytes later, in the range
105 		 *
106 		 * (0x204, 0x214, ..., 0x274).
107 		 *
108 		 * Filter out everything else.
109 		 */
110 		if (WARN_ONCE(!(IS_ALIGNED(reg, 16) ||
111 				IS_ALIGNED(reg - 4, 16)),
112 			      "Misaligned APIC_IRR/ALLOWED_IRR APIC register read offset 0x%x", reg))
113 			return 0;
114 		return apic_get_reg(ap, reg);
115 	default:
116 		pr_err("Error reading unknown Secure AVIC reg offset 0x%x\n", reg);
117 		return 0;
118 	}
119 }
120 
121 #define SAVIC_NMI_REQ		0x278
122 
123 static void savic_write(u32 reg, u32 data)
124 {
125 	void *ap = this_cpu_ptr(savic_page);
126 
127 	switch (reg) {
128 	case APIC_LVTT:
129 	case APIC_LVT0:
130 	case APIC_LVT1:
131 	case APIC_TMICT:
132 	case APIC_TDCR:
133 	case APIC_SELF_IPI:
134 	case APIC_TASKPRI:
135 	case APIC_EOI:
136 	case APIC_SPIV:
137 	case SAVIC_NMI_REQ:
138 	case APIC_ESR:
139 	case APIC_LVTTHMR:
140 	case APIC_LVTPC:
141 	case APIC_LVTERR:
142 	case APIC_ECTRL:
143 	case APIC_SEOI:
144 	case APIC_IER:
145 	case APIC_EILVTn(0) ... APIC_EILVTn(3):
146 		apic_set_reg(ap, reg, data);
147 		break;
148 	case APIC_ICR:
149 		apic_set_reg64(ap, reg, (u64)data);
150 		break;
151 	/* ALLOWED_IRR offsets are writable */
152 	case SAVIC_ALLOWED_IRR ... SAVIC_ALLOWED_IRR + 0x70:
153 		if (IS_ALIGNED(reg - 4, 16)) {
154 			apic_set_reg(ap, reg, data);
155 			break;
156 		}
157 		fallthrough;
158 	default:
159 		pr_err("Error writing unknown Secure AVIC reg offset 0x%x\n", reg);
160 	}
161 }
162 
163 static void savic_update_vector(unsigned int cpu, unsigned int vector, bool set)
164 {
165 	update_vector(cpu, SAVIC_ALLOWED_IRR, vector, set);
166 }
167 
168 static void savic_setup(void)
169 {
170 	void *ap = this_cpu_ptr(savic_page);
171 	enum es_result res;
172 	unsigned long gpa;
173 
174 	/*
175 	 * Before Secure AVIC is enabled, APIC MSR reads are intercepted.
176 	 * APIC_ID MSR read returns the value from the hypervisor.
177 	 */
178 	apic_set_reg(ap, APIC_ID, native_apic_msr_read(APIC_ID));
179 
180 	gpa = __pa(ap);
181 
182 	/*
183 	 * The NPT entry for a vCPU's APIC backing page must always be
184 	 * present when the vCPU is running in order for Secure AVIC to
185 	 * function. A VMEXIT_BUSY is returned on VMRUN and the vCPU cannot
186 	 * be resumed if the NPT entry for the APIC backing page is not
187 	 * present. Notify GPA of the vCPU's APIC backing page to the
188 	 * hypervisor by calling savic_register_gpa(). Before executing
189 	 * VMRUN, the hypervisor makes use of this information to make sure
190 	 * the APIC backing page is mapped in NPT.
191 	 */
192 	res = savic_register_gpa(gpa);
193 	if (res != ES_OK)
194 		snp_abort();
195 }
196 
197 static int savic_probe(void)
198 {
199 	if (!cc_platform_has(CC_ATTR_SNP_SECURE_AVIC))
200 		return 0;
201 
202 	if (!x2apic_mode) {
203 		pr_err("Secure AVIC enabled in non x2APIC mode\n");
204 		snp_abort();
205 		/* unreachable */
206 	}
207 
208 	savic_page = alloc_percpu(struct secure_avic_page);
209 	if (!savic_page)
210 		snp_abort();
211 
212 	return 1;
213 }
214 
215 static struct apic apic_x2apic_savic __ro_after_init = {
216 
217 	.name				= "secure avic x2apic",
218 	.probe				= savic_probe,
219 	.acpi_madt_oem_check		= savic_acpi_madt_oem_check,
220 	.setup				= savic_setup,
221 
222 	.dest_mode_logical		= false,
223 
224 	.disable_esr			= 0,
225 
226 	.cpu_present_to_apicid		= default_cpu_present_to_apicid,
227 
228 	.max_apic_id			= UINT_MAX,
229 	.x2apic_set_max_apicid		= true,
230 	.get_apic_id			= x2apic_get_apic_id,
231 
232 	.calc_dest_apicid		= apic_default_calc_apicid,
233 
234 	.nmi_to_offline_cpu		= true,
235 
236 	.read				= savic_read,
237 	.write				= savic_write,
238 	.eoi				= native_apic_msr_eoi,
239 	.icr_read			= native_x2apic_icr_read,
240 	.icr_write			= native_x2apic_icr_write,
241 
242 	.update_vector			= savic_update_vector,
243 };
244 
245 apic_driver(apic_x2apic_savic);
246