xref: /openbsd-src/sys/arch/amd64/amd64/ucode.c (revision ccd74f9409a9152da4bb5d9abdb4977db9c6f603)
1 /*	$OpenBSD: ucode.c,v 1.9 2024/04/03 02:01:21 guenther Exp $	*/
2 /*
3  * Copyright (c) 2018 Stefan Fritsch <fritsch@genua.de>
4  * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/mutex.h>
22 #include <sys/malloc.h>
23 
24 #include <uvm/uvm_extern.h>
25 
26 #include <machine/cpu.h>
27 #include <machine/cpufunc.h>
28 #include <machine/specialreg.h>
29 #include <machine/biosvar.h>
30 
31 /* #define UCODE_DEBUG */
32 #ifdef UCODE_DEBUG
33 #define DPRINTF(x)	do { if (cpu_ucode_debug > 0) printf x; } while (0)
34 #define DPRINTFN(n, x)	do { if (cpu_ucode_debug >= (n)) printf x; } while (0)
35 int cpu_ucode_debug = 1;
36 #else
37 #define DPRINTF(x)	do { ; } while (0)
38 #define DPRINTFN(n, x)	do { ; } while (0)
39 #endif
40 
41 struct intel_ucode_header {
42 	uint32_t	header_version;
43 	uint32_t	update_revision;
44 	uint32_t	date;
45 	uint32_t	processor_sig;
46 	uint32_t	checksum;
47 	uint32_t	loader_rev;
48 	uint32_t	processor_flags;
49 	uint32_t	data_size;
50 	uint32_t	total_size;
51 	uint32_t	reserved[3];
52 };
53 
54 struct intel_ucode_ext_sig_header {
55 	uint32_t	ext_sig_count;
56 	uint32_t	checksum;
57 	uint32_t	reserved[3];
58 };
59 
60 struct intel_ucode_ext_sig {
61 	uint32_t	processor_sig;
62 	uint32_t	processor_flags;
63 	uint32_t	checksum;
64 };
65 
66 #define INTEL_UCODE_DEFAULT_DATA_SIZE		2000
67 
68 /* Generic */
69 char *	 cpu_ucode_data;
70 size_t	 cpu_ucode_size;
71 
72 void	 cpu_ucode_setup(void);
73 void	 cpu_ucode_apply(struct cpu_info *);
74 
75 struct mutex	cpu_ucode_mtx = MUTEX_INITIALIZER(IPL_HIGH);
76 
77 /* Intel */
78 void	 cpu_ucode_intel_apply(struct cpu_info *);
79 struct intel_ucode_header *
80 	 cpu_ucode_intel_find(char *, size_t, uint32_t);
81 int	 cpu_ucode_intel_verify(struct intel_ucode_header *);
82 int	 cpu_ucode_intel_match(struct intel_ucode_header *, uint32_t, uint32_t,
83 	    uint32_t);
84 uint32_t cpu_ucode_intel_rev(void);
85 
86 struct intel_ucode_header	*cpu_ucode_intel_applied;
87 
88 void cpu_ucode_amd_apply(struct cpu_info *);
89 
90 void
cpu_ucode_setup(void)91 cpu_ucode_setup(void)
92 {
93 	if (bios_ucode == NULL)
94 		return;
95 
96 	if (!bios_ucode->uc_addr || !bios_ucode->uc_size)
97 		return;
98 
99 	cpu_ucode_size = bios_ucode->uc_size;
100 	cpu_ucode_data = malloc(cpu_ucode_size, M_DEVBUF, M_WAITOK);
101 	memcpy(cpu_ucode_data, (void *)PMAP_DIRECT_MAP(bios_ucode->uc_addr),
102 	    cpu_ucode_size);
103 }
104 
105 /*
106  * Called per-CPU.
107  */
108 void
cpu_ucode_apply(struct cpu_info * ci)109 cpu_ucode_apply(struct cpu_info *ci)
110 {
111 	if (ci->ci_vendor == CPUV_INTEL)
112 		cpu_ucode_intel_apply(ci);
113 	else if (ci->ci_vendor == CPUV_AMD)
114 		cpu_ucode_amd_apply(ci);
115 }
116 
117 #define AMD_MAGIC 0x00414d44
118 
119 struct amd_equiv {
120 	uint32_t id;
121 	uint32_t a;
122 	uint32_t b;
123 	uint16_t eid;
124 	uint16_t c;
125 } __packed;
126 
127 struct amd_patch {
128 	uint32_t type;
129 	uint32_t len;
130 	uint32_t a;
131 	uint32_t level;
132 	uint8_t c[16];
133 	uint16_t eid;
134 } __packed;
135 
136 void
cpu_ucode_amd_apply(struct cpu_info * ci)137 cpu_ucode_amd_apply(struct cpu_info *ci)
138 {
139 	uint64_t level;
140 	uint32_t magic, tlen, i;
141 	uint16_t eid = 0;
142 	uint32_t sig, ebx, ecx, edx;
143 	uint64_t start = 0;
144 	uint32_t patch_len = 0;
145 
146 	if (cpu_ucode_data == NULL || cpu_ucode_size == 0) {
147 		DPRINTF(("%s: no microcode provided\n", __func__));
148 		return;
149 	}
150 
151 	/*
152 	 * Grab a mutex, because we are not allowed to run updates
153 	 * simultaneously on HT siblings.
154 	 */
155 	mtx_enter(&cpu_ucode_mtx);
156 
157 	CPUID(1, sig, ebx, ecx, edx);
158 
159 	level = rdmsr(MSR_PATCH_LEVEL);
160 	DPRINTF(("%s: cur patch level 0x%llx\n", __func__, level));
161 
162 	memcpy(&magic, cpu_ucode_data, 4);
163 	if (magic != AMD_MAGIC) {
164 		DPRINTF(("%s: bad magic %x\n", __func__, magic));
165 		goto out;
166 	}
167 
168 	memcpy(&tlen, &cpu_ucode_data[8], 4);
169 
170 	/* find equivalence id matching our cpu signature */
171 	for (i = 12; i < 12 + tlen;) {
172 		struct amd_equiv ae;
173 		if (i + sizeof(ae) > cpu_ucode_size) {
174 			DPRINTF(("%s: truncated etable\n", __func__));
175 			goto out;
176 		}
177 		memcpy(&ae, &cpu_ucode_data[i], sizeof(ae));
178 		i += sizeof(ae);
179 		if (ae.id == sig)
180 			eid = ae.eid;
181 	}
182 
183 	/* look for newer patch with the equivalence id */
184 	while (i < cpu_ucode_size) {
185 		struct amd_patch ap;
186 		if (i + sizeof(ap) > cpu_ucode_size) {
187 			DPRINTF(("%s: truncated ptable\n", __func__));
188 			goto out;
189 		}
190 		memcpy(&ap, &cpu_ucode_data[i], sizeof(ap));
191 		if (ap.type == 1 && ap.eid == eid && ap.level > level) {
192 			start = (uint64_t)&cpu_ucode_data[i + 8];
193 			patch_len = ap.len;
194 		}
195 		if (i + ap.len + 8 > cpu_ucode_size) {
196 			DPRINTF(("%s: truncated patch\n", __func__));
197 			goto out;
198 		}
199 		i += ap.len + 8;
200 	}
201 
202 	if (start != 0) {
203 		/* alignment required on fam 15h */
204 		uint8_t *p = malloc(patch_len, M_TEMP, M_NOWAIT);
205 		if (p == NULL)
206 			goto out;
207 		memcpy(p, (uint8_t *)start, patch_len);
208 		start = (uint64_t)p;
209 		wrmsr(MSR_PATCH_LOADER, start);
210 		level = rdmsr(MSR_PATCH_LEVEL);
211 		DPRINTF(("%s: new patch level 0x%llx\n", __func__, level));
212 		free(p, M_TEMP, patch_len);
213 	}
214 out:
215 	mtx_leave(&cpu_ucode_mtx);
216 }
217 
218 void
cpu_ucode_intel_apply(struct cpu_info * ci)219 cpu_ucode_intel_apply(struct cpu_info *ci)
220 {
221 	struct intel_ucode_header *update;
222 	uint32_t old_rev, new_rev;
223 	paddr_t data;
224 
225 	if (cpu_ucode_data == NULL || cpu_ucode_size == 0) {
226 		DPRINTF(("%s: no microcode provided\n", __func__));
227 		return;
228 	}
229 
230 	/*
231 	 * Grab a mutex, because we are not allowed to run updates
232 	 * simultaneously on HT siblings.
233 	 */
234 	mtx_enter(&cpu_ucode_mtx);
235 
236 	old_rev = cpu_ucode_intel_rev();
237 	update = cpu_ucode_intel_applied;
238 	if (update == NULL)
239 		update = cpu_ucode_intel_find(cpu_ucode_data,
240 		    cpu_ucode_size, old_rev);
241 	if (update == NULL) {
242 		DPRINTF(("%s: no microcode update found\n", __func__));
243 		goto out;
244 	}
245 	if (update->update_revision == old_rev) {
246 		DPRINTF(("%s: microcode already up-to-date\n", __func__));
247 		goto out;
248 	}
249 
250 	/* Apply microcode. */
251 	data = (paddr_t)update;
252 	data += sizeof(struct intel_ucode_header);
253 	wbinvd();
254 	wrmsr(MSR_BIOS_UPDT_TRIG, data);
255 
256 	new_rev = cpu_ucode_intel_rev();
257 	if (new_rev != old_rev) {
258 		DPRINTF(("%s: microcode updated cpu %d rev %#x->%#x (%x)\n",
259 		    __func__, ci->ci_cpuid, old_rev, new_rev, update->date));
260 		if (cpu_ucode_intel_applied == NULL)
261 			cpu_ucode_intel_applied = update;
262 	} else {
263 		DPRINTF(("%s: microcode update failed cpu %d rev %#x->%#x != %#x\n",
264 		     __func__, ci->ci_cpuid, old_rev, update->update_revision, new_rev));
265 	}
266 
267 out:
268 	mtx_leave(&cpu_ucode_mtx);
269 }
270 
271 struct intel_ucode_header *
cpu_ucode_intel_find(char * data,size_t left,uint32_t current)272 cpu_ucode_intel_find(char *data, size_t left, uint32_t current)
273 {
274 	uint64_t platform_id = (rdmsr(MSR_PLATFORM_ID) >> 50) & 7;
275 	uint32_t sig, dummy1, dummy2, dummy3;
276 	uint32_t mask = 1UL << platform_id;
277 	struct intel_ucode_header *hdr;
278 	uint32_t total_size;
279 	int n = 0;
280 
281 	CPUID(1, sig, dummy1, dummy2, dummy3);
282 
283 	while (left > 0) {
284 		hdr = (struct intel_ucode_header *)data;
285 		if (left < sizeof(struct intel_ucode_header)) {
286 			DPRINTF(("%s:%d: not enough data for header (%zd)\n",
287 			    __func__, n, left));
288 			break;
289 		}
290 		/*
291 		 * Older microcode has an empty length.  In that case we
292 		 * have to use the default length of 2000.
293 		 */
294 		if (hdr->data_size)
295 			total_size = hdr->total_size;
296 		else
297 			total_size = INTEL_UCODE_DEFAULT_DATA_SIZE +
298 			     sizeof(struct intel_ucode_header);
299 		if (total_size > left) {
300 			DPRINTF(("%s:%d: size %u out of range (%zd)\n",
301 			    __func__, n, total_size, left));
302 			break;
303 		}
304 		if (cpu_ucode_intel_verify(hdr)) {
305 			DPRINTF(("%s:%d: broken data\n", __func__, n));
306 			break;
307 		}
308 		if (cpu_ucode_intel_match(hdr, sig, mask, current))
309 			return hdr;
310 		n++;
311 		left -= total_size;
312 		data += total_size;
313 	}
314 	DPRINTF(("%s: no update found\n", __func__));
315 	return NULL;
316 }
317 
318 int
cpu_ucode_intel_verify(struct intel_ucode_header * hdr)319 cpu_ucode_intel_verify(struct intel_ucode_header *hdr)
320 {
321 	uint32_t *data = (uint32_t *)hdr;
322 	size_t total_size;
323 	uint32_t sum;
324 	int i;
325 
326 	CTASSERT(sizeof(struct intel_ucode_header) == 48);
327 
328 	if ((paddr_t)data % 16 != 0) {
329 		DPRINTF(("%s: misaligned microcode update\n", __func__));
330 		return 1;
331 	}
332 	if (hdr->loader_rev != 1) {
333 		DPRINTF(("%s: unsupported loader rev\n", __func__));
334 		return 1;
335 	}
336 
337 	if (hdr->data_size)
338 		total_size = hdr->total_size;
339 	else
340 		total_size = INTEL_UCODE_DEFAULT_DATA_SIZE +
341 		    sizeof(struct intel_ucode_header);
342 	if (total_size % 4 != 0) {
343 		DPRINTF(("%s: inconsistent size\n", __func__));
344 		return 1;
345 	}
346 
347 	sum = 0;
348 	for (i = 0; i < total_size / 4; i++)
349 		sum += data[i];
350 	if (sum != 0) {
351 		DPRINTF(("%s: wrong checksum (%#x)\n", __func__, sum));
352 		return 1;
353 	}
354 
355 	return 0;
356 }
357 
358 int
cpu_ucode_intel_match(struct intel_ucode_header * hdr,uint32_t processor_sig,uint32_t processor_mask,uint32_t ucode_revision)359 cpu_ucode_intel_match(struct intel_ucode_header *hdr,
360     uint32_t processor_sig, uint32_t processor_mask,
361     uint32_t ucode_revision)
362 {
363 	struct intel_ucode_ext_sig_header *ehdr;
364 	struct intel_ucode_ext_sig *esig;
365 	uint32_t data_size, total_size;
366 	unsigned i;
367 
368 	data_size = hdr->data_size;
369 	total_size = hdr->total_size;
370 
371 	/*
372 	 * Older microcode has an empty length.  In that case we
373 	 * have to use the default length of 2000.
374 	 */
375 	if (!data_size) {
376 		data_size = INTEL_UCODE_DEFAULT_DATA_SIZE;
377 		total_size = INTEL_UCODE_DEFAULT_DATA_SIZE +
378 		    sizeof(struct intel_ucode_header);
379 	}
380 
381 	if (ucode_revision > hdr->update_revision)
382 		return 0;
383 	if (hdr->processor_sig == processor_sig &&
384 	    (hdr->processor_flags & processor_mask))
385 		return 1;
386 	if (total_size <= sizeof(struct intel_ucode_header) +
387 	    data_size + sizeof(struct intel_ucode_ext_sig_header))
388 		return 0;
389 
390 	ehdr = (void *)((char *)hdr + sizeof(struct intel_ucode_header) +
391 	    data_size);
392 	esig = (void *)&ehdr[1];
393 	for (i = 0; i < ehdr->ext_sig_count; i++) {
394 		if (esig[i].processor_sig == processor_sig &&
395 		    (esig[i].processor_flags & processor_mask))
396 			return 1;
397 	}
398 
399 	return 0;
400 }
401 
402 uint32_t
cpu_ucode_intel_rev(void)403 cpu_ucode_intel_rev(void)
404 {
405 	uint32_t eax, ebx, ecx, edx;
406 	uint64_t rev;
407 
408 	wrmsr(MSR_BIOS_SIGN, 0);
409 	CPUID(1, eax, ebx, ecx, edx);
410 	rev = rdmsr(MSR_BIOS_SIGN);
411 	return rev >> 32;
412 }
413