/root/src/xen/xen/arch/x86/microcode_amd.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * AMD CPU Microcode Update Driver for Linux |
3 | | * Copyright (C) 2008 Advanced Micro Devices Inc. |
4 | | * |
5 | | * Author: Peter Oruba <peter.oruba@amd.com> |
6 | | * |
7 | | * Based on work by: |
8 | | * Tigran Aivazian <tigran@aivazian.fsnet.co.uk> |
9 | | * |
10 | | * This driver allows to upgrade microcode on AMD |
11 | | * family 0x10 and later. |
12 | | * |
13 | | * Licensed unter the terms of the GNU General Public |
14 | | * License version 2. See file COPYING for details. |
15 | | */ |
16 | | |
17 | | #include <xen/lib.h> |
18 | | #include <xen/kernel.h> |
19 | | #include <xen/init.h> |
20 | | #include <xen/sched.h> |
21 | | #include <xen/smp.h> |
22 | | #include <xen/spinlock.h> |
23 | | |
24 | | #include <asm/msr.h> |
25 | | #include <asm/processor.h> |
26 | | #include <asm/microcode.h> |
27 | | #include <asm/hvm/svm/svm.h> |
28 | | |
29 | 0 | #define pr_debug(x...) ((void)0) |
30 | | |
31 | 0 | #define CONT_HDR_SIZE 12 |
32 | 0 | #define SECTION_HDR_SIZE 8 |
33 | 0 | #define PATCH_HDR_SIZE 32 |
34 | | |
35 | | struct __packed equiv_cpu_entry { |
36 | | uint32_t installed_cpu; |
37 | | uint32_t fixed_errata_mask; |
38 | | uint32_t fixed_errata_compare; |
39 | | uint16_t equiv_cpu; |
40 | | uint16_t reserved; |
41 | | }; |
42 | | |
43 | | struct __packed microcode_header_amd { |
44 | | uint32_t data_code; |
45 | | uint32_t patch_id; |
46 | | uint8_t mc_patch_data_id[2]; |
47 | | uint8_t mc_patch_data_len; |
48 | | uint8_t init_flag; |
49 | | uint32_t mc_patch_data_checksum; |
50 | | uint32_t nb_dev_id; |
51 | | uint32_t sb_dev_id; |
52 | | uint16_t processor_rev_id; |
53 | | uint8_t nb_rev_id; |
54 | | uint8_t sb_rev_id; |
55 | | uint8_t bios_api_rev; |
56 | | uint8_t reserved1[3]; |
57 | | uint32_t match_reg[8]; |
58 | | }; |
59 | | |
60 | 0 | #define UCODE_MAGIC 0x00414d44 |
61 | 0 | #define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000 |
62 | 0 | #define UCODE_UCODE_TYPE 0x00000001 |
63 | | |
64 | | struct microcode_amd { |
65 | | void *mpb; |
66 | | size_t mpb_size; |
67 | | struct equiv_cpu_entry *equiv_cpu_table; |
68 | | size_t equiv_cpu_table_size; |
69 | | }; |
70 | | |
71 | | struct mpbhdr { |
72 | | uint32_t type; |
73 | | uint32_t len; |
74 | | uint8_t data[]; |
75 | | }; |
76 | | |
77 | | /* serialize access to the physical write */ |
78 | | static DEFINE_SPINLOCK(microcode_update_lock); |
79 | | |
80 | | /* See comment in start_update() for cases when this routine fails */ |
81 | | static int collect_cpu_info(unsigned int cpu, struct cpu_signature *csig) |
82 | 0 | { |
83 | 0 | struct cpuinfo_x86 *c = &cpu_data[cpu]; |
84 | 0 |
|
85 | 0 | memset(csig, 0, sizeof(*csig)); |
86 | 0 |
|
87 | 0 | if ( (c->x86_vendor != X86_VENDOR_AMD) || (c->x86 < 0x10) ) |
88 | 0 | { |
89 | 0 | printk(KERN_ERR "microcode: CPU%d not a capable AMD processor\n", |
90 | 0 | cpu); |
91 | 0 | return -EINVAL; |
92 | 0 | } |
93 | 0 |
|
94 | 0 | rdmsrl(MSR_AMD_PATCHLEVEL, csig->rev); |
95 | 0 |
|
96 | 0 | pr_debug("microcode: CPU%d collect_cpu_info: patch_id=%#x\n", |
97 | 0 | cpu, csig->rev); |
98 | 0 |
|
99 | 0 | return 0; |
100 | 0 | } |
101 | | |
102 | | static bool_t verify_patch_size(uint32_t patch_size) |
103 | 0 | { |
104 | 0 | uint32_t max_size; |
105 | 0 |
|
106 | 0 | #define F1XH_MPB_MAX_SIZE 2048 |
107 | 0 | #define F14H_MPB_MAX_SIZE 1824 |
108 | 0 | #define F15H_MPB_MAX_SIZE 4096 |
109 | 0 | #define F16H_MPB_MAX_SIZE 3458 |
110 | 0 |
|
111 | 0 | switch (boot_cpu_data.x86) |
112 | 0 | { |
113 | 0 | case 0x14: |
114 | 0 | max_size = F14H_MPB_MAX_SIZE; |
115 | 0 | break; |
116 | 0 | case 0x15: |
117 | 0 | max_size = F15H_MPB_MAX_SIZE; |
118 | 0 | break; |
119 | 0 | case 0x16: |
120 | 0 | max_size = F16H_MPB_MAX_SIZE; |
121 | 0 | break; |
122 | 0 | default: |
123 | 0 | max_size = F1XH_MPB_MAX_SIZE; |
124 | 0 | break; |
125 | 0 | } |
126 | 0 |
|
127 | 0 | return (patch_size <= max_size); |
128 | 0 | } |
129 | | |
130 | | static bool_t find_equiv_cpu_id(const struct equiv_cpu_entry *equiv_cpu_table, |
131 | | unsigned int current_cpu_id, |
132 | | unsigned int *equiv_cpu_id) |
133 | 0 | { |
134 | 0 | unsigned int i; |
135 | 0 |
|
136 | 0 | if ( !equiv_cpu_table ) |
137 | 0 | return 0; |
138 | 0 |
|
139 | 0 | for ( i = 0; equiv_cpu_table[i].installed_cpu != 0; i++ ) |
140 | 0 | { |
141 | 0 | if ( current_cpu_id == equiv_cpu_table[i].installed_cpu ) |
142 | 0 | { |
143 | 0 | *equiv_cpu_id = equiv_cpu_table[i].equiv_cpu & 0xffff; |
144 | 0 | return 1; |
145 | 0 | } |
146 | 0 | } |
147 | 0 |
|
148 | 0 | return 0; |
149 | 0 | } |
150 | | |
151 | | static bool_t microcode_fits(const struct microcode_amd *mc_amd, |
152 | | unsigned int cpu) |
153 | 0 | { |
154 | 0 | struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu); |
155 | 0 | const struct microcode_header_amd *mc_header = mc_amd->mpb; |
156 | 0 | const struct equiv_cpu_entry *equiv_cpu_table = mc_amd->equiv_cpu_table; |
157 | 0 | unsigned int current_cpu_id; |
158 | 0 | unsigned int equiv_cpu_id; |
159 | 0 |
|
160 | 0 | /* We should bind the task to the CPU */ |
161 | 0 | BUG_ON(cpu != raw_smp_processor_id()); |
162 | 0 |
|
163 | 0 | current_cpu_id = cpuid_eax(0x00000001); |
164 | 0 |
|
165 | 0 | if ( !find_equiv_cpu_id(equiv_cpu_table, current_cpu_id, &equiv_cpu_id) ) |
166 | 0 | return 0; |
167 | 0 |
|
168 | 0 | if ( (mc_header->processor_rev_id) != equiv_cpu_id ) |
169 | 0 | return 0; |
170 | 0 |
|
171 | 0 | if ( !verify_patch_size(mc_amd->mpb_size) ) |
172 | 0 | { |
173 | 0 | pr_debug("microcode: patch size mismatch\n"); |
174 | 0 | return 0; |
175 | 0 | } |
176 | 0 |
|
177 | 0 | if ( mc_header->patch_id <= uci->cpu_sig.rev ) |
178 | 0 | { |
179 | 0 | pr_debug("microcode: patch is already at required level or greater.\n"); |
180 | 0 | return 0; |
181 | 0 | } |
182 | 0 |
|
183 | 0 | pr_debug("microcode: CPU%d found a matching microcode update with version %#x (current=%#x)\n", |
184 | 0 | cpu, mc_header->patch_id, uci->cpu_sig.rev); |
185 | 0 |
|
186 | 0 | return 1; |
187 | 0 | } |
188 | | |
189 | | static int apply_microcode(unsigned int cpu) |
190 | 0 | { |
191 | 0 | unsigned long flags; |
192 | 0 | struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu); |
193 | 0 | uint32_t rev; |
194 | 0 | struct microcode_amd *mc_amd = uci->mc.mc_amd; |
195 | 0 | struct microcode_header_amd *hdr; |
196 | 0 | int hw_err; |
197 | 0 |
|
198 | 0 | /* We should bind the task to the CPU */ |
199 | 0 | BUG_ON(raw_smp_processor_id() != cpu); |
200 | 0 |
|
201 | 0 | if ( mc_amd == NULL ) |
202 | 0 | return -EINVAL; |
203 | 0 |
|
204 | 0 | hdr = mc_amd->mpb; |
205 | 0 | if ( hdr == NULL ) |
206 | 0 | return -EINVAL; |
207 | 0 |
|
208 | 0 | spin_lock_irqsave(µcode_update_lock, flags); |
209 | 0 |
|
210 | 0 | hw_err = wrmsr_safe(MSR_AMD_PATCHLOADER, (unsigned long)hdr); |
211 | 0 |
|
212 | 0 | /* get patch id after patching */ |
213 | 0 | rdmsrl(MSR_AMD_PATCHLEVEL, rev); |
214 | 0 |
|
215 | 0 | spin_unlock_irqrestore(µcode_update_lock, flags); |
216 | 0 |
|
217 | 0 | /* check current patch id and patch's id for match */ |
218 | 0 | if ( hw_err || (rev != hdr->patch_id) ) |
219 | 0 | { |
220 | 0 | printk(KERN_ERR "microcode: CPU%d update from revision " |
221 | 0 | "%#x to %#x failed\n", cpu, rev, hdr->patch_id); |
222 | 0 | return -EIO; |
223 | 0 | } |
224 | 0 |
|
225 | 0 | printk(KERN_WARNING "microcode: CPU%d updated from revision %#x to %#x\n", |
226 | 0 | cpu, uci->cpu_sig.rev, hdr->patch_id); |
227 | 0 |
|
228 | 0 | uci->cpu_sig.rev = rev; |
229 | 0 |
|
230 | 0 | return 0; |
231 | 0 | } |
232 | | |
233 | | static int get_ucode_from_buffer_amd( |
234 | | struct microcode_amd *mc_amd, |
235 | | const void *buf, |
236 | | size_t bufsize, |
237 | | size_t *offset) |
238 | 0 | { |
239 | 0 | const struct mpbhdr *mpbuf = buf + *offset; |
240 | 0 |
|
241 | 0 | /* No more data */ |
242 | 0 | if ( *offset >= bufsize ) |
243 | 0 | { |
244 | 0 | printk(KERN_ERR "microcode: Microcode buffer overrun\n"); |
245 | 0 | return -EINVAL; |
246 | 0 | } |
247 | 0 |
|
248 | 0 | if ( mpbuf->type != UCODE_UCODE_TYPE ) |
249 | 0 | { |
250 | 0 | printk(KERN_ERR "microcode: Wrong microcode payload type field\n"); |
251 | 0 | return -EINVAL; |
252 | 0 | } |
253 | 0 |
|
254 | 0 | if ( (*offset + mpbuf->len) > bufsize ) |
255 | 0 | { |
256 | 0 | printk(KERN_ERR "microcode: Bad data in microcode data file\n"); |
257 | 0 | return -EINVAL; |
258 | 0 | } |
259 | 0 |
|
260 | 0 | if ( mc_amd->mpb_size < mpbuf->len ) |
261 | 0 | { |
262 | 0 | if ( mc_amd->mpb ) |
263 | 0 | { |
264 | 0 | xfree(mc_amd->mpb); |
265 | 0 | mc_amd->mpb_size = 0; |
266 | 0 | } |
267 | 0 | mc_amd->mpb = xmalloc_bytes(mpbuf->len); |
268 | 0 | if ( mc_amd->mpb == NULL ) |
269 | 0 | return -ENOMEM; |
270 | 0 | mc_amd->mpb_size = mpbuf->len; |
271 | 0 | } |
272 | 0 | memcpy(mc_amd->mpb, mpbuf->data, mpbuf->len); |
273 | 0 |
|
274 | 0 | pr_debug("microcode: CPU%d size %zu, block size %u offset %zu equivID %#x rev %#x\n", |
275 | 0 | raw_smp_processor_id(), bufsize, mpbuf->len, *offset, |
276 | 0 | ((struct microcode_header_amd *)mc_amd->mpb)->processor_rev_id, |
277 | 0 | ((struct microcode_header_amd *)mc_amd->mpb)->patch_id); |
278 | 0 |
|
279 | 0 | *offset += mpbuf->len + SECTION_HDR_SIZE; |
280 | 0 |
|
281 | 0 | return 0; |
282 | 0 | } |
283 | | |
284 | | static int install_equiv_cpu_table( |
285 | | struct microcode_amd *mc_amd, |
286 | | const void *data, |
287 | | size_t *offset) |
288 | 0 | { |
289 | 0 | const struct mpbhdr *mpbuf = data + *offset + 4; |
290 | 0 |
|
291 | 0 | *offset += mpbuf->len + CONT_HDR_SIZE; /* add header length */ |
292 | 0 |
|
293 | 0 | if ( mpbuf->type != UCODE_EQUIV_CPU_TABLE_TYPE ) |
294 | 0 | { |
295 | 0 | printk(KERN_ERR "microcode: Wrong microcode equivalent cpu table type field\n"); |
296 | 0 | return -EINVAL; |
297 | 0 | } |
298 | 0 |
|
299 | 0 | if ( mpbuf->len == 0 ) |
300 | 0 | { |
301 | 0 | printk(KERN_ERR "microcode: Wrong microcode equivalent cpu table length\n"); |
302 | 0 | return -EINVAL; |
303 | 0 | } |
304 | 0 |
|
305 | 0 | mc_amd->equiv_cpu_table = xmalloc_bytes(mpbuf->len); |
306 | 0 | if ( !mc_amd->equiv_cpu_table ) |
307 | 0 | { |
308 | 0 | printk(KERN_ERR "microcode: Cannot allocate memory for equivalent cpu table\n"); |
309 | 0 | return -ENOMEM; |
310 | 0 | } |
311 | 0 |
|
312 | 0 | memcpy(mc_amd->equiv_cpu_table, mpbuf->data, mpbuf->len); |
313 | 0 | mc_amd->equiv_cpu_table_size = mpbuf->len; |
314 | 0 |
|
315 | 0 | return 0; |
316 | 0 | } |
317 | | |
318 | | static int container_fast_forward(const void *data, size_t size_left, size_t *offset) |
319 | 0 | { |
320 | 0 | for ( ; ; ) |
321 | 0 | { |
322 | 0 | size_t size; |
323 | 0 | const uint32_t *header; |
324 | 0 |
|
325 | 0 | if ( size_left < SECTION_HDR_SIZE ) |
326 | 0 | return -EINVAL; |
327 | 0 |
|
328 | 0 | header = data + *offset; |
329 | 0 |
|
330 | 0 | if ( header[0] == UCODE_MAGIC && |
331 | 0 | header[1] == UCODE_EQUIV_CPU_TABLE_TYPE ) |
332 | 0 | break; |
333 | 0 |
|
334 | 0 | if ( header[0] != UCODE_UCODE_TYPE ) |
335 | 0 | return -EINVAL; |
336 | 0 | size = header[1] + SECTION_HDR_SIZE; |
337 | 0 | if ( size < PATCH_HDR_SIZE || size_left < size ) |
338 | 0 | return -EINVAL; |
339 | 0 |
|
340 | 0 | size_left -= size; |
341 | 0 | *offset += size; |
342 | 0 |
|
343 | 0 | if ( !size_left ) |
344 | 0 | return -ENODATA; |
345 | 0 | } |
346 | 0 |
|
347 | 0 | return 0; |
348 | 0 | } |
349 | | |
350 | | /* |
351 | | * The 'final_levels' of patch ids have been obtained empirically. |
352 | | * Refer bug https://bugzilla.suse.com/show_bug.cgi?id=913996 |
353 | | * for details of the issue. The short version is that people |
354 | | * using certain Fam10h systems noticed system hang issues when |
355 | | * trying to update microcode levels beyond the patch IDs below. |
356 | | * From internal discussions, we gathered that OS/hypervisor |
357 | | * cannot reliably perform microcode updates beyond these levels |
358 | | * due to hardware issues. Therefore, we need to abort microcode |
359 | | * update process if we hit any of these levels. |
360 | | */ |
361 | | static const unsigned int final_levels[] = { |
362 | | 0x01000098, |
363 | | 0x0100009f, |
364 | | 0x010000af |
365 | | }; |
366 | | |
367 | | static bool_t check_final_patch_levels(unsigned int cpu) |
368 | 0 | { |
369 | 0 | /* |
370 | 0 | * Check the current patch levels on the cpu. If they are equal to |
371 | 0 | * any of the 'final_levels', then we should not update the microcode |
372 | 0 | * patch on the cpu as system will hang otherwise. |
373 | 0 | */ |
374 | 0 | struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu); |
375 | 0 | unsigned int i; |
376 | 0 |
|
377 | 0 | if ( boot_cpu_data.x86 != 0x10 ) |
378 | 0 | return 0; |
379 | 0 |
|
380 | 0 | for ( i = 0; i < ARRAY_SIZE(final_levels); i++ ) |
381 | 0 | if ( uci->cpu_sig.rev == final_levels[i] ) |
382 | 0 | return 1; |
383 | 0 |
|
384 | 0 | return 0; |
385 | 0 | } |
386 | | |
387 | | static int cpu_request_microcode(unsigned int cpu, const void *buf, |
388 | | size_t bufsize) |
389 | 0 | { |
390 | 0 | struct microcode_amd *mc_amd, *mc_old; |
391 | 0 | size_t offset = 0; |
392 | 0 | size_t last_offset, applied_offset = 0; |
393 | 0 | int error = 0, save_error = 1; |
394 | 0 | struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu); |
395 | 0 | unsigned int current_cpu_id; |
396 | 0 | unsigned int equiv_cpu_id; |
397 | 0 |
|
398 | 0 | /* We should bind the task to the CPU */ |
399 | 0 | BUG_ON(cpu != raw_smp_processor_id()); |
400 | 0 |
|
401 | 0 | current_cpu_id = cpuid_eax(0x00000001); |
402 | 0 |
|
403 | 0 | if ( *(const uint32_t *)buf != UCODE_MAGIC ) |
404 | 0 | { |
405 | 0 | printk(KERN_ERR "microcode: Wrong microcode patch file magic\n"); |
406 | 0 | error = -EINVAL; |
407 | 0 | goto out; |
408 | 0 | } |
409 | 0 |
|
410 | 0 | if ( check_final_patch_levels(cpu) ) |
411 | 0 | { |
412 | 0 | printk(XENLOG_INFO |
413 | 0 | "microcode: Cannot update microcode patch on the cpu as we hit a final level\n"); |
414 | 0 | error = -EPERM; |
415 | 0 | goto out; |
416 | 0 | } |
417 | 0 |
|
418 | 0 | mc_amd = xmalloc(struct microcode_amd); |
419 | 0 | if ( !mc_amd ) |
420 | 0 | { |
421 | 0 | printk(KERN_ERR "microcode: Cannot allocate memory for microcode patch\n"); |
422 | 0 | error = -ENOMEM; |
423 | 0 | goto out; |
424 | 0 | } |
425 | 0 |
|
426 | 0 | /* |
427 | 0 | * Multiple container file support: |
428 | 0 | * 1. check if this container file has equiv_cpu_id match |
429 | 0 | * 2. If not, fast-fwd to next container file |
430 | 0 | */ |
431 | 0 | while ( offset < bufsize ) |
432 | 0 | { |
433 | 0 | error = install_equiv_cpu_table(mc_amd, buf, &offset); |
434 | 0 | if ( error ) |
435 | 0 | { |
436 | 0 | printk(KERN_ERR "microcode: installing equivalent cpu table failed\n"); |
437 | 0 | break; |
438 | 0 | } |
439 | 0 |
|
440 | 0 | /* |
441 | 0 | * Could happen as we advance 'offset' early |
442 | 0 | * in install_equiv_cpu_table |
443 | 0 | */ |
444 | 0 | if ( offset > bufsize ) |
445 | 0 | { |
446 | 0 | printk(KERN_ERR "microcode: Microcode buffer overrun\n"); |
447 | 0 | error = -EINVAL; |
448 | 0 | break; |
449 | 0 | } |
450 | 0 |
|
451 | 0 | if ( find_equiv_cpu_id(mc_amd->equiv_cpu_table, current_cpu_id, |
452 | 0 | &equiv_cpu_id) ) |
453 | 0 | break; |
454 | 0 |
|
455 | 0 | error = container_fast_forward(buf, bufsize - offset, &offset); |
456 | 0 | if ( error == -ENODATA ) |
457 | 0 | { |
458 | 0 | ASSERT(offset == bufsize); |
459 | 0 | break; |
460 | 0 | } |
461 | 0 | if ( error ) |
462 | 0 | { |
463 | 0 | printk(KERN_ERR "microcode: CPU%d incorrect or corrupt container file\n" |
464 | 0 | "microcode: Failed to update patch level. " |
465 | 0 | "Current lvl:%#x\n", cpu, uci->cpu_sig.rev); |
466 | 0 | break; |
467 | 0 | } |
468 | 0 | } |
469 | 0 |
|
470 | 0 | if ( error ) |
471 | 0 | { |
472 | 0 | xfree(mc_amd); |
473 | 0 | goto out; |
474 | 0 | } |
475 | 0 |
|
476 | 0 | mc_old = uci->mc.mc_amd; |
477 | 0 | /* implicitely validates uci->mc.mc_valid */ |
478 | 0 | uci->mc.mc_amd = mc_amd; |
479 | 0 |
|
480 | 0 | /* |
481 | 0 | * It's possible the data file has multiple matching ucode, |
482 | 0 | * lets keep searching till the latest version |
483 | 0 | */ |
484 | 0 | mc_amd->mpb = NULL; |
485 | 0 | mc_amd->mpb_size = 0; |
486 | 0 | last_offset = offset; |
487 | 0 | while ( (error = get_ucode_from_buffer_amd(mc_amd, buf, bufsize, |
488 | 0 | &offset)) == 0 ) |
489 | 0 | { |
490 | 0 | if ( microcode_fits(mc_amd, cpu) ) |
491 | 0 | { |
492 | 0 | error = apply_microcode(cpu); |
493 | 0 | if ( error ) |
494 | 0 | break; |
495 | 0 | applied_offset = last_offset; |
496 | 0 | } |
497 | 0 |
|
498 | 0 | last_offset = offset; |
499 | 0 |
|
500 | 0 | if ( offset >= bufsize ) |
501 | 0 | break; |
502 | 0 |
|
503 | 0 | /* |
504 | 0 | * 1. Given a situation where multiple containers exist and correct |
505 | 0 | * patch lives on a container that is not the last container. |
506 | 0 | * 2. We match equivalent ids using find_equiv_cpu_id() from the |
507 | 0 | * earlier while() (On this case, matches on earlier container |
508 | 0 | * file and we break) |
509 | 0 | * 3. Proceed to while ( (error = get_ucode_from_buffer_amd(mc_amd, |
510 | 0 | * buf, bufsize,&offset)) == 0 ) |
511 | 0 | * 4. Find correct patch using microcode_fits() and apply the patch |
512 | 0 | * (Assume: apply_microcode() is successful) |
513 | 0 | * 5. The while() loop from (3) continues to parse the binary as |
514 | 0 | * there is a subsequent container file, but... |
515 | 0 | * 6. ...a correct patch can only be on one container and not on any |
516 | 0 | * subsequent ones. (Refer docs for more info) Therefore, we |
517 | 0 | * don't have to parse a subsequent container. So, we can abort |
518 | 0 | * the process here. |
519 | 0 | * 7. This ensures that we retain a success value (= 0) to 'error' |
520 | 0 | * before if ( mpbuf->type != UCODE_UCODE_TYPE ) evaluates to |
521 | 0 | * false and returns -EINVAL. |
522 | 0 | */ |
523 | 0 | if ( offset + SECTION_HDR_SIZE <= bufsize && |
524 | 0 | *(const uint32_t *)(buf + offset) == UCODE_MAGIC ) |
525 | 0 | break; |
526 | 0 | } |
527 | 0 |
|
528 | 0 | /* On success keep the microcode patch for |
529 | 0 | * re-apply on resume. |
530 | 0 | */ |
531 | 0 | if ( applied_offset ) |
532 | 0 | { |
533 | 0 | save_error = get_ucode_from_buffer_amd( |
534 | 0 | mc_amd, buf, bufsize, &applied_offset); |
535 | 0 |
|
536 | 0 | if ( save_error ) |
537 | 0 | error = save_error; |
538 | 0 | } |
539 | 0 |
|
540 | 0 | if ( save_error ) |
541 | 0 | { |
542 | 0 | xfree(mc_amd); |
543 | 0 | uci->mc.mc_amd = mc_old; |
544 | 0 | } |
545 | 0 | else |
546 | 0 | xfree(mc_old); |
547 | 0 |
|
548 | 0 | out: |
549 | 0 | svm_host_osvw_init(); |
550 | 0 |
|
551 | 0 | /* |
552 | 0 | * In some cases we may return an error even if processor's microcode has |
553 | 0 | * been updated. For example, the first patch in a container file is loaded |
554 | 0 | * successfully but subsequent container file processing encounters a |
555 | 0 | * failure. |
556 | 0 | */ |
557 | 0 | return error; |
558 | 0 | } |
559 | | |
560 | | static int microcode_resume_match(unsigned int cpu, const void *mc) |
561 | 0 | { |
562 | 0 | struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu); |
563 | 0 | struct microcode_amd *mc_amd = uci->mc.mc_amd; |
564 | 0 | const struct microcode_amd *src = mc; |
565 | 0 |
|
566 | 0 | if ( !microcode_fits(src, cpu) ) |
567 | 0 | return 0; |
568 | 0 |
|
569 | 0 | if ( src != mc_amd ) |
570 | 0 | { |
571 | 0 | if ( mc_amd ) |
572 | 0 | { |
573 | 0 | xfree(mc_amd->equiv_cpu_table); |
574 | 0 | xfree(mc_amd->mpb); |
575 | 0 | xfree(mc_amd); |
576 | 0 | } |
577 | 0 |
|
578 | 0 | mc_amd = xmalloc(struct microcode_amd); |
579 | 0 | uci->mc.mc_amd = mc_amd; |
580 | 0 | if ( !mc_amd ) |
581 | 0 | return -ENOMEM; |
582 | 0 | mc_amd->equiv_cpu_table = xmalloc_bytes(src->equiv_cpu_table_size); |
583 | 0 | if ( !mc_amd->equiv_cpu_table ) |
584 | 0 | goto err1; |
585 | 0 | mc_amd->mpb = xmalloc_bytes(src->mpb_size); |
586 | 0 | if ( !mc_amd->mpb ) |
587 | 0 | goto err2; |
588 | 0 |
|
589 | 0 | mc_amd->equiv_cpu_table_size = src->equiv_cpu_table_size; |
590 | 0 | mc_amd->mpb_size = src->mpb_size; |
591 | 0 | memcpy(mc_amd->mpb, src->mpb, src->mpb_size); |
592 | 0 | memcpy(mc_amd->equiv_cpu_table, src->equiv_cpu_table, |
593 | 0 | src->equiv_cpu_table_size); |
594 | 0 | } |
595 | 0 |
|
596 | 0 | return 1; |
597 | 0 |
|
598 | 0 | err2: |
599 | 0 | xfree(mc_amd->equiv_cpu_table); |
600 | 0 | err1: |
601 | 0 | xfree(mc_amd); |
602 | 0 | uci->mc.mc_amd = NULL; |
603 | 0 | return -ENOMEM; |
604 | 0 | } |
605 | | |
606 | | static int start_update(void) |
607 | 0 | { |
608 | 0 | /* |
609 | 0 | * We assume here that svm_host_osvw_init() will be called on each cpu (from |
610 | 0 | * cpu_request_microcode()). |
611 | 0 | * |
612 | 0 | * Note that if collect_cpu_info() returns an error then |
613 | 0 | * cpu_request_microcode() will not invoked thus leaving OSVW bits not |
614 | 0 | * updated. Currently though collect_cpu_info() will not fail on processors |
615 | 0 | * supporting OSVW so we will not deal with this possibility. |
616 | 0 | */ |
617 | 0 | svm_host_osvw_reset(); |
618 | 0 |
|
619 | 0 | return 0; |
620 | 0 | } |
621 | | |
622 | | static const struct microcode_ops microcode_amd_ops = { |
623 | | .microcode_resume_match = microcode_resume_match, |
624 | | .cpu_request_microcode = cpu_request_microcode, |
625 | | .collect_cpu_info = collect_cpu_info, |
626 | | .apply_microcode = apply_microcode, |
627 | | .start_update = start_update, |
628 | | }; |
629 | | |
630 | | int __init microcode_init_amd(void) |
631 | 1 | { |
632 | 1 | if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD ) |
633 | 0 | microcode_ops = µcode_amd_ops; |
634 | 1 | return 0; |
635 | 1 | } |