aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/microcode_amd.c
diff options
context:
space:
mode:
authorBorislav Petkov <borislav.petkov@amd.com>2012-08-01 10:16:13 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2012-08-22 19:16:29 -0400
commit2efb05e8e9fa3510044e007b90263c73b6a83f84 (patch)
tree7d291afac4924c6e4e75801a36b691a5073515e6 /arch/x86/kernel/microcode_amd.c
parenta3eb3b4da106a23b5d41bf915726172e31654a65 (diff)
x86, microcode, AMD: Rewrite patch application procedure
Limit the access to userspace only on the BSP where we load the container, verify the patches in it and put them in the patch cache. Then, at application time, we lookup the correct patch in the cache and use it. When we need to reload the userspace container, we do that over the reload interface: echo 1 > /sys/devices/system/cpu/microcode/reload which reloads (a possibly newer) container from userspace and applies then the newest patches from there. Signed-off-by: Borislav Petkov <borislav.petkov@amd.com> Link: http://lkml.kernel.org/r/1344361461-10076-13-git-send-email-bp@amd64.org Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/kernel/microcode_amd.c')
-rw-r--r--arch/x86/kernel/microcode_amd.c236
1 files changed, 121 insertions, 115 deletions
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
index cacdc9a5ee49..5511216b4434 100644
--- a/arch/x86/kernel/microcode_amd.c
+++ b/arch/x86/kernel/microcode_amd.c
@@ -75,9 +75,6 @@ struct microcode_amd {
75 75
76static struct equiv_cpu_entry *equiv_cpu_table; 76static struct equiv_cpu_entry *equiv_cpu_table;
77 77
78/* page-sized ucode patch buffer */
79void *patch;
80
81struct ucode_patch { 78struct ucode_patch {
82 struct list_head plist; 79 struct list_head plist;
83 void *data; 80 void *data;
@@ -184,7 +181,7 @@ static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
184 return 0; 181 return 0;
185} 182}
186 183
187static unsigned int verify_ucode_size(int cpu, u32 patch_size, 184static unsigned int verify_patch_size(int cpu, u32 patch_size,
188 unsigned int size) 185 unsigned int size)
189{ 186{
190 struct cpuinfo_x86 *c = &cpu_data(cpu); 187 struct cpuinfo_x86 *c = &cpu_data(cpu);
@@ -214,73 +211,25 @@ static unsigned int verify_ucode_size(int cpu, u32 patch_size,
214 return patch_size; 211 return patch_size;
215} 212}
216 213
217/*
218 * we signal a good patch is found by returning its size > 0
219 */
220static int get_matching_microcode(int cpu, const u8 *ucode_ptr,
221 unsigned int leftover_size, int rev,
222 unsigned int *current_size)
223{
224 struct microcode_header_amd *mc_hdr;
225 unsigned int actual_size, patch_size;
226 u16 equiv_cpu_id;
227
228 /* size of the current patch we're staring at */
229 patch_size = *(u32 *)(ucode_ptr + 4);
230 *current_size = patch_size + SECTION_HDR_SIZE;
231
232 equiv_cpu_id = find_equiv_id(cpu);
233 if (!equiv_cpu_id)
234 return 0;
235
236 /*
237 * let's look at the patch header itself now
238 */
239 mc_hdr = (struct microcode_header_amd *)(ucode_ptr + SECTION_HDR_SIZE);
240
241 if (mc_hdr->processor_rev_id != equiv_cpu_id)
242 return 0;
243
244 /* ucode might be chipset specific -- currently we don't support this */
245 if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) {
246 pr_err("CPU%d: chipset specific code not yet supported\n",
247 cpu);
248 return 0;
249 }
250
251 if (mc_hdr->patch_id <= rev)
252 return 0;
253
254 /*
255 * now that the header looks sane, verify its size
256 */
257 actual_size = verify_ucode_size(cpu, patch_size, leftover_size);
258 if (!actual_size)
259 return 0;
260
261 /* clear the patch buffer */
262 memset(patch, 0, PAGE_SIZE);
263
264 /* all looks ok, get the binary patch */
265 memcpy(patch, ucode_ptr + SECTION_HDR_SIZE, actual_size);
266
267 return actual_size;
268}
269
270static int apply_microcode_amd(int cpu) 214static int apply_microcode_amd(int cpu)
271{ 215{
272 u32 rev, dummy;
273 int cpu_num = raw_smp_processor_id();
274 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
275 struct microcode_amd *mc_amd = uci->mc;
276 struct cpuinfo_x86 *c = &cpu_data(cpu); 216 struct cpuinfo_x86 *c = &cpu_data(cpu);
217 struct microcode_amd *mc_amd;
218 struct ucode_cpu_info *uci;
219 struct ucode_patch *p;
220 u32 rev, dummy;
221
222 BUG_ON(raw_smp_processor_id() != cpu);
277 223
278 /* We should bind the task to the CPU */ 224 uci = ucode_cpu_info + cpu;
279 BUG_ON(cpu_num != cpu);
280 225
281 if (mc_amd == NULL) 226 p = find_patch(cpu);
227 if (!p)
282 return 0; 228 return 0;
283 229
230 mc_amd = p->data;
231 uci->mc = p->data;
232
284 rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); 233 rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
285 234
286 /* need to apply patch? */ 235 /* need to apply patch? */
@@ -336,61 +285,113 @@ static void free_equiv_cpu_table(void)
336 equiv_cpu_table = NULL; 285 equiv_cpu_table = NULL;
337} 286}
338 287
339static enum ucode_state 288static void cleanup(void)
340generic_load_microcode(int cpu, const u8 *data, size_t size)
341{ 289{
342 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 290 free_equiv_cpu_table();
343 struct microcode_header_amd *mc_hdr = NULL; 291 free_cache();
344 unsigned int mc_size, leftover, current_size = 0; 292}
293
294/*
295 * We return the current size even if some of the checks failed so that
296 * we can skip over the next patch. If we return a negative value, we
297 * signal a grave error like a memory allocation has failed and the
298 * driver cannot continue functioning normally. In such cases, we tear
299 * down everything we've used up so far and exit.
300 */
301static int verify_and_add_patch(unsigned int cpu, u8 *fw, unsigned int leftover)
302{
303 struct cpuinfo_x86 *c = &cpu_data(cpu);
304 struct microcode_header_amd *mc_hdr;
305 struct ucode_patch *patch;
306 unsigned int patch_size, crnt_size, ret;
307 u32 proc_fam;
308 u16 proc_id;
309
310 patch_size = *(u32 *)(fw + 4);
311 crnt_size = patch_size + SECTION_HDR_SIZE;
312 mc_hdr = (struct microcode_header_amd *)(fw + SECTION_HDR_SIZE);
313 proc_id = mc_hdr->processor_rev_id;
314
315 proc_fam = find_cpu_family_by_equiv_cpu(proc_id);
316 if (!proc_fam) {
317 pr_err("No patch family for equiv ID: 0x%04x\n", proc_id);
318 return crnt_size;
319 }
320
321 /* check if patch is for the current family */
322 proc_fam = ((proc_fam >> 8) & 0xf) + ((proc_fam >> 20) & 0xff);
323 if (proc_fam != c->x86)
324 return crnt_size;
325
326 if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) {
327 pr_err("Patch-ID 0x%08x: chipset-specific code unsupported.\n",
328 mc_hdr->patch_id);
329 return crnt_size;
330 }
331
332 ret = verify_patch_size(cpu, patch_size, leftover);
333 if (!ret) {
334 pr_err("Patch-ID 0x%08x: size mismatch.\n", mc_hdr->patch_id);
335 return crnt_size;
336 }
337
338 patch = kzalloc(sizeof(*patch), GFP_KERNEL);
339 if (!patch) {
340 pr_err("Patch allocation failure.\n");
341 return -EINVAL;
342 }
343
344 patch->data = kzalloc(patch_size, GFP_KERNEL);
345 if (!patch->data) {
346 pr_err("Patch data allocation failure.\n");
347 kfree(patch);
348 return -EINVAL;
349 }
350
351 /* All looks ok, copy patch... */
352 memcpy(patch->data, fw + SECTION_HDR_SIZE, patch_size);
353 INIT_LIST_HEAD(&patch->plist);
354 patch->patch_id = mc_hdr->patch_id;
355 patch->equiv_cpu = proc_id;
356
357 /* ... and add to cache. */
358 update_cache(patch);
359
360 return crnt_size;
361}
362
363static enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size)
364{
365 enum ucode_state ret = UCODE_ERROR;
366 unsigned int leftover;
367 u8 *fw = (u8 *)data;
368 int crnt_size = 0;
345 int offset; 369 int offset;
346 const u8 *ucode_ptr = data;
347 void *new_mc = NULL;
348 unsigned int new_rev = uci->cpu_sig.rev;
349 enum ucode_state state = UCODE_ERROR;
350 370
351 offset = install_equiv_cpu_table(ucode_ptr); 371 offset = install_equiv_cpu_table(data);
352 if (offset < 0) { 372 if (offset < 0) {
353 pr_err("failed to create equivalent cpu table\n"); 373 pr_err("failed to create equivalent cpu table\n");
354 goto out; 374 return ret;
355 } 375 }
356 ucode_ptr += offset; 376 fw += offset;
357 leftover = size - offset; 377 leftover = size - offset;
358 378
359 if (*(u32 *)ucode_ptr != UCODE_UCODE_TYPE) { 379 if (*(u32 *)fw != UCODE_UCODE_TYPE) {
360 pr_err("invalid type field in container file section header\n"); 380 pr_err("invalid type field in container file section header\n");
361 goto free_table; 381 free_equiv_cpu_table();
382 return ret;
362 } 383 }
363 384
364 while (leftover) { 385 while (leftover) {
365 mc_size = get_matching_microcode(cpu, ucode_ptr, leftover, 386 crnt_size = verify_and_add_patch(cpu, fw, leftover);
366 new_rev, &current_size); 387 if (crnt_size < 0)
367 if (mc_size) { 388 return ret;
368 mc_hdr = patch;
369 new_mc = patch;
370 new_rev = mc_hdr->patch_id;
371 goto out_ok;
372 }
373 389
374 ucode_ptr += current_size; 390 fw += crnt_size;
375 leftover -= current_size; 391 leftover -= crnt_size;
376 } 392 }
377 393
378 if (!new_mc) { 394 return UCODE_OK;
379 state = UCODE_NFOUND;
380 goto free_table;
381 }
382
383out_ok:
384 uci->mc = new_mc;
385 state = UCODE_OK;
386 pr_debug("CPU%d update ucode (0x%08x -> 0x%08x)\n",
387 cpu, uci->cpu_sig.rev, new_rev);
388
389free_table:
390 free_equiv_cpu_table();
391
392out:
393 return state;
394} 395}
395 396
396/* 397/*
@@ -401,7 +402,7 @@ out:
401 * 402 *
402 * This legacy file is always smaller than 2K in size. 403 * This legacy file is always smaller than 2K in size.
403 * 404 *
404 * Starting at family 15h they are in family specific firmware files: 405 * Beginning with family 15h, they are in family-specific firmware files:
405 * 406 *
406 * amd-ucode/microcode_amd_fam15h.bin 407 * amd-ucode/microcode_amd_fam15h.bin
407 * amd-ucode/microcode_amd_fam16h.bin 408 * amd-ucode/microcode_amd_fam16h.bin
@@ -413,9 +414,13 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device,
413 bool refresh_fw) 414 bool refresh_fw)
414{ 415{
415 char fw_name[36] = "amd-ucode/microcode_amd.bin"; 416 char fw_name[36] = "amd-ucode/microcode_amd.bin";
416 const struct firmware *fw;
417 enum ucode_state ret = UCODE_NFOUND;
418 struct cpuinfo_x86 *c = &cpu_data(cpu); 417 struct cpuinfo_x86 *c = &cpu_data(cpu);
418 enum ucode_state ret = UCODE_NFOUND;
419 const struct firmware *fw;
420
421 /* reload ucode container only on the boot cpu */
422 if (!refresh_fw || c->cpu_index != boot_cpu_data.cpu_index)
423 return UCODE_OK;
419 424
420 if (c->x86 >= 0x15) 425 if (c->x86 >= 0x15)
421 snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86); 426 snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86);
@@ -431,12 +436,17 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device,
431 goto fw_release; 436 goto fw_release;
432 } 437 }
433 438
434 ret = generic_load_microcode(cpu, fw->data, fw->size); 439 /* free old equiv table */
440 free_equiv_cpu_table();
441
442 ret = load_microcode_amd(cpu, fw->data, fw->size);
443 if (ret != UCODE_OK)
444 cleanup();
435 445
436fw_release: 446 fw_release:
437 release_firmware(fw); 447 release_firmware(fw);
438 448
439out: 449 out:
440 return ret; 450 return ret;
441} 451}
442 452
@@ -470,14 +480,10 @@ struct microcode_ops * __init init_amd_microcode(void)
470 return NULL; 480 return NULL;
471 } 481 }
472 482
473 patch = (void *)get_zeroed_page(GFP_KERNEL);
474 if (!patch)
475 return NULL;
476
477 return &microcode_amd_ops; 483 return &microcode_amd_ops;
478} 484}
479 485
480void __exit exit_amd_microcode(void) 486void __exit exit_amd_microcode(void)
481{ 487{
482 free_page((unsigned long)patch); 488 cleanup();
483} 489}