aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-07-02 19:28:10 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-02 19:28:10 -0400
commitfdd78889aad2ec85b2f5a8ed232215dca7a22a3b (patch)
treed99e66e9afe26bebf89204d15443c42b9345bc21
parentd652df0b2f0b9c2e655be0d6f90989fae0a511b4 (diff)
parent9608d33b8210c993af4430d661a6474946480c9b (diff)
Merge branch 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 microcode loading update from Ingo Molnar: "Two main changes that improve microcode loading on AMD CPUs: - Add support for all-in-one binary microcode files that concatenate the microcode images of multiple processor families, by Jacob Shin - Add early microcode loading (embedded in the initrd) support, also by Jacob Shin" * 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86, microcode, amd: Another early loading fixup x86, microcode, amd: Allow multiple families' bin files appended together x86, microcode, amd: Make find_ucode_in_initrd() __init x86, microcode, amd: Fix warnings and errors on with CONFIG_MICROCODE=m x86, microcode, amd: Early microcode patch loading support for AMD x86, microcode, amd: Refactor functions to prepare for early loading x86, microcode: Vendor abstract out save_microcode_in_initrd() x86, microcode, intel: Correct typo in printk
-rw-r--r--Documentation/x86/early-microcode.txt11
-rw-r--r--arch/x86/Kconfig14
-rw-r--r--arch/x86/include/asm/microcode_amd.h78
-rw-r--r--arch/x86/include/asm/microcode_intel.h2
-rw-r--r--arch/x86/kernel/Makefile1
-rw-r--r--arch/x86/kernel/microcode_amd.c133
-rw-r--r--arch/x86/kernel/microcode_amd_early.c302
-rw-r--r--arch/x86/kernel/microcode_core_early.c49
-rw-r--r--arch/x86/kernel/microcode_intel_early.c6
9 files changed, 509 insertions, 87 deletions
diff --git a/Documentation/x86/early-microcode.txt b/Documentation/x86/early-microcode.txt
index 4aaf0dfb0cb8..d62bea6796da 100644
--- a/Documentation/x86/early-microcode.txt
+++ b/Documentation/x86/early-microcode.txt
@@ -11,7 +11,8 @@ file and loaded to CPUs during boot time.
11The format of the combined initrd image is microcode in cpio format followed by 11The format of the combined initrd image is microcode in cpio format followed by
12the initrd image (maybe compressed). Kernel parses the combined initrd image 12the initrd image (maybe compressed). Kernel parses the combined initrd image
13during boot time. The microcode file in cpio name space is: 13during boot time. The microcode file in cpio name space is:
14kernel/x86/microcode/GenuineIntel.bin 14on Intel: kernel/x86/microcode/GenuineIntel.bin
15on AMD : kernel/x86/microcode/AuthenticAMD.bin
15 16
16During BSP boot (before SMP starts), if the kernel finds the microcode file in 17During BSP boot (before SMP starts), if the kernel finds the microcode file in
17the initrd file, it parses the microcode and saves matching microcode in memory. 18the initrd file, it parses the microcode and saves matching microcode in memory.
@@ -34,10 +35,8 @@ original initrd image /boot/initrd-3.5.0.img.
34 35
35mkdir initrd 36mkdir initrd
36cd initrd 37cd initrd
37mkdir kernel 38mkdir -p kernel/x86/microcode
38mkdir kernel/x86 39cp ../microcode.bin kernel/x86/microcode/GenuineIntel.bin (or AuthenticAMD.bin)
39mkdir kernel/x86/microcode 40find . | cpio -o -H newc >../ucode.cpio
40cp ../microcode.bin kernel/x86/microcode/GenuineIntel.bin
41find .|cpio -oc >../ucode.cpio
42cd .. 41cd ..
43cat ucode.cpio /boot/initrd-3.5.0.img >/boot/initrd-3.5.0.ucode.img 42cat ucode.cpio /boot/initrd-3.5.0.img >/boot/initrd-3.5.0.ucode.img
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index c49b4dc8ffe0..34d1db1e7f40 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1058,8 +1058,16 @@ config MICROCODE_INTEL_LIB
1058 depends on MICROCODE_INTEL 1058 depends on MICROCODE_INTEL
1059 1059
1060config MICROCODE_INTEL_EARLY 1060config MICROCODE_INTEL_EARLY
1061 def_bool n
1062
1063config MICROCODE_AMD_EARLY
1064 def_bool n
1065
1066config MICROCODE_EARLY
1061 bool "Early load microcode" 1067 bool "Early load microcode"
1062 depends on MICROCODE_INTEL && BLK_DEV_INITRD 1068 depends on MICROCODE=y && BLK_DEV_INITRD
1069 select MICROCODE_INTEL_EARLY if MICROCODE_INTEL
1070 select MICROCODE_AMD_EARLY if MICROCODE_AMD
1063 default y 1071 default y
1064 help 1072 help
1065 This option provides functionality to read additional microcode data 1073 This option provides functionality to read additional microcode data
@@ -1067,10 +1075,6 @@ config MICROCODE_INTEL_EARLY
1067 microcode to CPU's as early as possible. No functional change if no 1075 microcode to CPU's as early as possible. No functional change if no
1068 microcode data is glued to the initrd, therefore it's safe to say Y. 1076 microcode data is glued to the initrd, therefore it's safe to say Y.
1069 1077
1070config MICROCODE_EARLY
1071 def_bool y
1072 depends on MICROCODE_INTEL_EARLY
1073
1074config X86_MSR 1078config X86_MSR
1075 tristate "/dev/cpu/*/msr - Model-specific register support" 1079 tristate "/dev/cpu/*/msr - Model-specific register support"
1076 ---help--- 1080 ---help---
diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h
new file mode 100644
index 000000000000..c6b043f40271
--- /dev/null
+++ b/arch/x86/include/asm/microcode_amd.h
@@ -0,0 +1,78 @@
1#ifndef _ASM_X86_MICROCODE_AMD_H
2#define _ASM_X86_MICROCODE_AMD_H
3
4#include <asm/microcode.h>
5
6#define UCODE_MAGIC 0x00414d44
7#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
8#define UCODE_UCODE_TYPE 0x00000001
9
10#define SECTION_HDR_SIZE 8
11#define CONTAINER_HDR_SZ 12
12
13struct equiv_cpu_entry {
14 u32 installed_cpu;
15 u32 fixed_errata_mask;
16 u32 fixed_errata_compare;
17 u16 equiv_cpu;
18 u16 res;
19} __attribute__((packed));
20
21struct microcode_header_amd {
22 u32 data_code;
23 u32 patch_id;
24 u16 mc_patch_data_id;
25 u8 mc_patch_data_len;
26 u8 init_flag;
27 u32 mc_patch_data_checksum;
28 u32 nb_dev_id;
29 u32 sb_dev_id;
30 u16 processor_rev_id;
31 u8 nb_rev_id;
32 u8 sb_rev_id;
33 u8 bios_api_rev;
34 u8 reserved1[3];
35 u32 match_reg[8];
36} __attribute__((packed));
37
38struct microcode_amd {
39 struct microcode_header_amd hdr;
40 unsigned int mpb[0];
41};
42
43static inline u16 find_equiv_id(struct equiv_cpu_entry *equiv_cpu_table,
44 unsigned int sig)
45{
46 int i = 0;
47
48 if (!equiv_cpu_table)
49 return 0;
50
51 while (equiv_cpu_table[i].installed_cpu != 0) {
52 if (sig == equiv_cpu_table[i].installed_cpu)
53 return equiv_cpu_table[i].equiv_cpu;
54
55 i++;
56 }
57 return 0;
58}
59
60extern int __apply_microcode_amd(struct microcode_amd *mc_amd);
61extern int apply_microcode_amd(int cpu);
62extern enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size);
63
64#ifdef CONFIG_MICROCODE_AMD_EARLY
65#ifdef CONFIG_X86_32
66#define MPB_MAX_SIZE PAGE_SIZE
67extern u8 amd_bsp_mpb[MPB_MAX_SIZE];
68#endif
69extern void __init load_ucode_amd_bsp(void);
70extern void __cpuinit load_ucode_amd_ap(void);
71extern int __init save_microcode_in_initrd_amd(void);
72#else
73static inline void __init load_ucode_amd_bsp(void) {}
74static inline void __cpuinit load_ucode_amd_ap(void) {}
75static inline int __init save_microcode_in_initrd_amd(void) { return -EINVAL; }
76#endif
77
78#endif /* _ASM_X86_MICROCODE_AMD_H */
diff --git a/arch/x86/include/asm/microcode_intel.h b/arch/x86/include/asm/microcode_intel.h
index 5356f927d411..87a085333cbf 100644
--- a/arch/x86/include/asm/microcode_intel.h
+++ b/arch/x86/include/asm/microcode_intel.h
@@ -67,10 +67,12 @@ update_match_revision(struct microcode_header_intel *mc_header, int rev);
67extern void __init load_ucode_intel_bsp(void); 67extern void __init load_ucode_intel_bsp(void);
68extern void __cpuinit load_ucode_intel_ap(void); 68extern void __cpuinit load_ucode_intel_ap(void);
69extern void show_ucode_info_early(void); 69extern void show_ucode_info_early(void);
70extern int __init save_microcode_in_initrd_intel(void);
70#else 71#else
71static inline __init void load_ucode_intel_bsp(void) {} 72static inline __init void load_ucode_intel_bsp(void) {}
72static inline __cpuinit void load_ucode_intel_ap(void) {} 73static inline __cpuinit void load_ucode_intel_ap(void) {}
73static inline void show_ucode_info_early(void) {} 74static inline void show_ucode_info_early(void) {}
75static inline int __init save_microcode_in_initrd_intel(void) { return -EINVAL; }
74#endif 76#endif
75 77
76#if defined(CONFIG_MICROCODE_INTEL_EARLY) && defined(CONFIG_HOTPLUG_CPU) 78#if defined(CONFIG_MICROCODE_INTEL_EARLY) && defined(CONFIG_HOTPLUG_CPU)
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 4ce822ed58f5..612ed3435c0d 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -93,6 +93,7 @@ obj-$(CONFIG_MICROCODE_INTEL_LIB) += microcode_intel_lib.o
93microcode-y := microcode_core.o 93microcode-y := microcode_core.o
94microcode-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o 94microcode-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o
95microcode-$(CONFIG_MICROCODE_AMD) += microcode_amd.o 95microcode-$(CONFIG_MICROCODE_AMD) += microcode_amd.o
96obj-$(CONFIG_MICROCODE_AMD_EARLY) += microcode_amd_early.o
96obj-$(CONFIG_MICROCODE) += microcode.o 97obj-$(CONFIG_MICROCODE) += microcode.o
97 98
98obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o 99obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
index efdec7cd8e01..47ebb1dbfbcb 100644
--- a/arch/x86/kernel/microcode_amd.c
+++ b/arch/x86/kernel/microcode_amd.c
@@ -31,48 +31,12 @@
31#include <asm/microcode.h> 31#include <asm/microcode.h>
32#include <asm/processor.h> 32#include <asm/processor.h>
33#include <asm/msr.h> 33#include <asm/msr.h>
34#include <asm/microcode_amd.h>
34 35
35MODULE_DESCRIPTION("AMD Microcode Update Driver"); 36MODULE_DESCRIPTION("AMD Microcode Update Driver");
36MODULE_AUTHOR("Peter Oruba"); 37MODULE_AUTHOR("Peter Oruba");
37MODULE_LICENSE("GPL v2"); 38MODULE_LICENSE("GPL v2");
38 39
39#define UCODE_MAGIC 0x00414d44
40#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
41#define UCODE_UCODE_TYPE 0x00000001
42
43struct equiv_cpu_entry {
44 u32 installed_cpu;
45 u32 fixed_errata_mask;
46 u32 fixed_errata_compare;
47 u16 equiv_cpu;
48 u16 res;
49} __attribute__((packed));
50
51struct microcode_header_amd {
52 u32 data_code;
53 u32 patch_id;
54 u16 mc_patch_data_id;
55 u8 mc_patch_data_len;
56 u8 init_flag;
57 u32 mc_patch_data_checksum;
58 u32 nb_dev_id;
59 u32 sb_dev_id;
60 u16 processor_rev_id;
61 u8 nb_rev_id;
62 u8 sb_rev_id;
63 u8 bios_api_rev;
64 u8 reserved1[3];
65 u32 match_reg[8];
66} __attribute__((packed));
67
68struct microcode_amd {
69 struct microcode_header_amd hdr;
70 unsigned int mpb[0];
71};
72
73#define SECTION_HDR_SIZE 8
74#define CONTAINER_HDR_SZ 12
75
76static struct equiv_cpu_entry *equiv_cpu_table; 40static struct equiv_cpu_entry *equiv_cpu_table;
77 41
78struct ucode_patch { 42struct ucode_patch {
@@ -84,21 +48,10 @@ struct ucode_patch {
84 48
85static LIST_HEAD(pcache); 49static LIST_HEAD(pcache);
86 50
87static u16 find_equiv_id(unsigned int cpu) 51static u16 __find_equiv_id(unsigned int cpu)
88{ 52{
89 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 53 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
90 int i = 0; 54 return find_equiv_id(equiv_cpu_table, uci->cpu_sig.sig);
91
92 if (!equiv_cpu_table)
93 return 0;
94
95 while (equiv_cpu_table[i].installed_cpu != 0) {
96 if (uci->cpu_sig.sig == equiv_cpu_table[i].installed_cpu)
97 return equiv_cpu_table[i].equiv_cpu;
98
99 i++;
100 }
101 return 0;
102} 55}
103 56
104static u32 find_cpu_family_by_equiv_cpu(u16 equiv_cpu) 57static u32 find_cpu_family_by_equiv_cpu(u16 equiv_cpu)
@@ -163,7 +116,7 @@ static struct ucode_patch *find_patch(unsigned int cpu)
163{ 116{
164 u16 equiv_id; 117 u16 equiv_id;
165 118
166 equiv_id = find_equiv_id(cpu); 119 equiv_id = __find_equiv_id(cpu);
167 if (!equiv_id) 120 if (!equiv_id)
168 return NULL; 121 return NULL;
169 122
@@ -173,9 +126,20 @@ static struct ucode_patch *find_patch(unsigned int cpu)
173static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) 126static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
174{ 127{
175 struct cpuinfo_x86 *c = &cpu_data(cpu); 128 struct cpuinfo_x86 *c = &cpu_data(cpu);
129 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
130 struct ucode_patch *p;
176 131
177 csig->sig = cpuid_eax(0x00000001); 132 csig->sig = cpuid_eax(0x00000001);
178 csig->rev = c->microcode; 133 csig->rev = c->microcode;
134
135 /*
136 * a patch could have been loaded early, set uci->mc so that
137 * mc_bp_resume() can call apply_microcode()
138 */
139 p = find_patch(cpu);
140 if (p && (p->patch_id == csig->rev))
141 uci->mc = p->data;
142
179 pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev); 143 pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev);
180 144
181 return 0; 145 return 0;
@@ -215,7 +179,21 @@ static unsigned int verify_patch_size(int cpu, u32 patch_size,
215 return patch_size; 179 return patch_size;
216} 180}
217 181
218static int apply_microcode_amd(int cpu) 182int __apply_microcode_amd(struct microcode_amd *mc_amd)
183{
184 u32 rev, dummy;
185
186 wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code);
187
188 /* verify patch application was successful */
189 rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
190 if (rev != mc_amd->hdr.patch_id)
191 return -1;
192
193 return 0;
194}
195
196int apply_microcode_amd(int cpu)
219{ 197{
220 struct cpuinfo_x86 *c = &cpu_data(cpu); 198 struct cpuinfo_x86 *c = &cpu_data(cpu);
221 struct microcode_amd *mc_amd; 199 struct microcode_amd *mc_amd;
@@ -242,19 +220,15 @@ static int apply_microcode_amd(int cpu)
242 return 0; 220 return 0;
243 } 221 }
244 222
245 wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code); 223 if (__apply_microcode_amd(mc_amd))
246
247 /* verify patch application was successful */
248 rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
249 if (rev != mc_amd->hdr.patch_id) {
250 pr_err("CPU%d: update failed for patch_level=0x%08x\n", 224 pr_err("CPU%d: update failed for patch_level=0x%08x\n",
251 cpu, mc_amd->hdr.patch_id); 225 cpu, mc_amd->hdr.patch_id);
252 return -1; 226 else
253 } 227 pr_info("CPU%d: new patch_level=0x%08x\n", cpu,
228 mc_amd->hdr.patch_id);
254 229
255 pr_info("CPU%d: new patch_level=0x%08x\n", cpu, rev); 230 uci->cpu_sig.rev = mc_amd->hdr.patch_id;
256 uci->cpu_sig.rev = rev; 231 c->microcode = mc_amd->hdr.patch_id;
257 c->microcode = rev;
258 232
259 return 0; 233 return 0;
260} 234}
@@ -364,7 +338,7 @@ static int verify_and_add_patch(unsigned int cpu, u8 *fw, unsigned int leftover)
364 return crnt_size; 338 return crnt_size;
365} 339}
366 340
367static enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size) 341static enum ucode_state __load_microcode_amd(int cpu, const u8 *data, size_t size)
368{ 342{
369 enum ucode_state ret = UCODE_ERROR; 343 enum ucode_state ret = UCODE_ERROR;
370 unsigned int leftover; 344 unsigned int leftover;
@@ -398,6 +372,32 @@ static enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size)
398 return UCODE_OK; 372 return UCODE_OK;
399} 373}
400 374
375enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size)
376{
377 enum ucode_state ret;
378
379 /* free old equiv table */
380 free_equiv_cpu_table();
381
382 ret = __load_microcode_amd(cpu, data, size);
383
384 if (ret != UCODE_OK)
385 cleanup();
386
387#if defined(CONFIG_MICROCODE_AMD_EARLY) && defined(CONFIG_X86_32)
388 /* save BSP's matching patch for early load */
389 if (cpu_data(cpu).cpu_index == boot_cpu_data.cpu_index) {
390 struct ucode_patch *p = find_patch(cpu);
391 if (p) {
392 memset(amd_bsp_mpb, 0, MPB_MAX_SIZE);
393 memcpy(amd_bsp_mpb, p->data, min_t(u32, ksize(p->data),
394 MPB_MAX_SIZE));
395 }
396 }
397#endif
398 return ret;
399}
400
401/* 401/*
402 * AMD microcode firmware naming convention, up to family 15h they are in 402 * AMD microcode firmware naming convention, up to family 15h they are in
403 * the legacy file: 403 * the legacy file:
@@ -440,12 +440,7 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device,
440 goto fw_release; 440 goto fw_release;
441 } 441 }
442 442
443 /* free old equiv table */
444 free_equiv_cpu_table();
445
446 ret = load_microcode_amd(cpu, fw->data, fw->size); 443 ret = load_microcode_amd(cpu, fw->data, fw->size);
447 if (ret != UCODE_OK)
448 cleanup();
449 444
450 fw_release: 445 fw_release:
451 release_firmware(fw); 446 release_firmware(fw);
diff --git a/arch/x86/kernel/microcode_amd_early.c b/arch/x86/kernel/microcode_amd_early.c
new file mode 100644
index 000000000000..1ac6e9aee766
--- /dev/null
+++ b/arch/x86/kernel/microcode_amd_early.c
@@ -0,0 +1,302 @@
1/*
2 * Copyright (C) 2013 Advanced Micro Devices, Inc.
3 *
4 * Author: Jacob Shin <jacob.shin@amd.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/earlycpio.h>
12#include <linux/initrd.h>
13
14#include <asm/cpu.h>
15#include <asm/setup.h>
16#include <asm/microcode_amd.h>
17
18static bool ucode_loaded;
19static u32 ucode_new_rev;
20static unsigned long ucode_offset;
21static size_t ucode_size;
22
23/*
24 * Microcode patch container file is prepended to the initrd in cpio format.
25 * See Documentation/x86/early-microcode.txt
26 */
27static __initdata char ucode_path[] = "kernel/x86/microcode/AuthenticAMD.bin";
28
29static struct cpio_data __init find_ucode_in_initrd(void)
30{
31 long offset = 0;
32 char *path;
33 void *start;
34 size_t size;
35 unsigned long *uoffset;
36 size_t *usize;
37 struct cpio_data cd;
38
39#ifdef CONFIG_X86_32
40 struct boot_params *p;
41
42 /*
43 * On 32-bit, early load occurs before paging is turned on so we need
44 * to use physical addresses.
45 */
46 p = (struct boot_params *)__pa_nodebug(&boot_params);
47 path = (char *)__pa_nodebug(ucode_path);
48 start = (void *)p->hdr.ramdisk_image;
49 size = p->hdr.ramdisk_size;
50 uoffset = (unsigned long *)__pa_nodebug(&ucode_offset);
51 usize = (size_t *)__pa_nodebug(&ucode_size);
52#else
53 path = ucode_path;
54 start = (void *)(boot_params.hdr.ramdisk_image + PAGE_OFFSET);
55 size = boot_params.hdr.ramdisk_size;
56 uoffset = &ucode_offset;
57 usize = &ucode_size;
58#endif
59
60 cd = find_cpio_data(path, start, size, &offset);
61 if (!cd.data)
62 return cd;
63
64 if (*(u32 *)cd.data != UCODE_MAGIC) {
65 cd.data = NULL;
66 cd.size = 0;
67 return cd;
68 }
69
70 *uoffset = (u8 *)cd.data - (u8 *)start;
71 *usize = cd.size;
72
73 return cd;
74}
75
76/*
77 * Early load occurs before we can vmalloc(). So we look for the microcode
78 * patch container file in initrd, traverse equivalent cpu table, look for a
79 * matching microcode patch, and update, all in initrd memory in place.
80 * When vmalloc() is available for use later -- on 64-bit during first AP load,
81 * and on 32-bit during save_microcode_in_initrd_amd() -- we can call
82 * load_microcode_amd() to save equivalent cpu table and microcode patches in
83 * kernel heap memory.
84 */
85static void __cpuinit apply_ucode_in_initrd(void *ucode, size_t size)
86{
87 struct equiv_cpu_entry *eq;
88 u32 *header;
89 u8 *data;
90 u16 eq_id = 0;
91 int offset, left;
92 u32 rev, eax;
93 u32 *new_rev;
94 unsigned long *uoffset;
95 size_t *usize;
96
97#ifdef CONFIG_X86_32
98 new_rev = (u32 *)__pa_nodebug(&ucode_new_rev);
99 uoffset = (unsigned long *)__pa_nodebug(&ucode_offset);
100 usize = (size_t *)__pa_nodebug(&ucode_size);
101#else
102 new_rev = &ucode_new_rev;
103 uoffset = &ucode_offset;
104 usize = &ucode_size;
105#endif
106
107 data = ucode;
108 left = size;
109 header = (u32 *)data;
110
111 /* find equiv cpu table */
112
113 if (header[1] != UCODE_EQUIV_CPU_TABLE_TYPE || /* type */
114 header[2] == 0) /* size */
115 return;
116
117 eax = cpuid_eax(0x00000001);
118
119 while (left > 0) {
120 eq = (struct equiv_cpu_entry *)(data + CONTAINER_HDR_SZ);
121
122 offset = header[2] + CONTAINER_HDR_SZ;
123 data += offset;
124 left -= offset;
125
126 eq_id = find_equiv_id(eq, eax);
127 if (eq_id)
128 break;
129
130 /*
131 * support multiple container files appended together. if this
132 * one does not have a matching equivalent cpu entry, we fast
133 * forward to the next container file.
134 */
135 while (left > 0) {
136 header = (u32 *)data;
137 if (header[0] == UCODE_MAGIC &&
138 header[1] == UCODE_EQUIV_CPU_TABLE_TYPE)
139 break;
140
141 offset = header[1] + SECTION_HDR_SIZE;
142 data += offset;
143 left -= offset;
144 }
145
146 /* mark where the next microcode container file starts */
147 offset = data - (u8 *)ucode;
148 *uoffset += offset;
149 *usize -= offset;
150 ucode = data;
151 }
152
153 if (!eq_id) {
154 *usize = 0;
155 return;
156 }
157
158 /* find ucode and update if needed */
159
160 rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax);
161
162 while (left > 0) {
163 struct microcode_amd *mc;
164
165 header = (u32 *)data;
166 if (header[0] != UCODE_UCODE_TYPE || /* type */
167 header[1] == 0) /* size */
168 break;
169
170 mc = (struct microcode_amd *)(data + SECTION_HDR_SIZE);
171 if (eq_id == mc->hdr.processor_rev_id && rev < mc->hdr.patch_id)
172 if (__apply_microcode_amd(mc) == 0) {
173 rev = mc->hdr.patch_id;
174 *new_rev = rev;
175 }
176
177 offset = header[1] + SECTION_HDR_SIZE;
178 data += offset;
179 left -= offset;
180 }
181
182 /* mark where this microcode container file ends */
183 offset = *usize - (data - (u8 *)ucode);
184 *usize -= offset;
185
186 if (!(*new_rev))
187 *usize = 0;
188}
189
190void __init load_ucode_amd_bsp(void)
191{
192 struct cpio_data cd = find_ucode_in_initrd();
193 if (!cd.data)
194 return;
195
196 apply_ucode_in_initrd(cd.data, cd.size);
197}
198
199#ifdef CONFIG_X86_32
200u8 amd_bsp_mpb[MPB_MAX_SIZE];
201
202/*
203 * On 32-bit, since AP's early load occurs before paging is turned on, we
204 * cannot traverse cpu_equiv_table and pcache in kernel heap memory. So during
205 * cold boot, AP will apply_ucode_in_initrd() just like the BSP. During
206 * save_microcode_in_initrd_amd() BSP's patch is copied to amd_bsp_mpb, which
207 * is used upon resume from suspend.
208 */
209void __cpuinit load_ucode_amd_ap(void)
210{
211 struct microcode_amd *mc;
212 unsigned long *initrd;
213 unsigned long *uoffset;
214 size_t *usize;
215 void *ucode;
216
217 mc = (struct microcode_amd *)__pa(amd_bsp_mpb);
218 if (mc->hdr.patch_id && mc->hdr.processor_rev_id) {
219 __apply_microcode_amd(mc);
220 return;
221 }
222
223 initrd = (unsigned long *)__pa(&initrd_start);
224 uoffset = (unsigned long *)__pa(&ucode_offset);
225 usize = (size_t *)__pa(&ucode_size);
226
227 if (!*usize || !*initrd)
228 return;
229
230 ucode = (void *)((unsigned long)__pa(*initrd) + *uoffset);
231 apply_ucode_in_initrd(ucode, *usize);
232}
233
234static void __init collect_cpu_sig_on_bsp(void *arg)
235{
236 unsigned int cpu = smp_processor_id();
237 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
238 uci->cpu_sig.sig = cpuid_eax(0x00000001);
239}
240#else
241static void __cpuinit collect_cpu_info_amd_early(struct cpuinfo_x86 *c,
242 struct ucode_cpu_info *uci)
243{
244 u32 rev, eax;
245
246 rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax);
247 eax = cpuid_eax(0x00000001);
248
249 uci->cpu_sig.sig = eax;
250 uci->cpu_sig.rev = rev;
251 c->microcode = rev;
252 c->x86 = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);
253}
254
255void __cpuinit load_ucode_amd_ap(void)
256{
257 unsigned int cpu = smp_processor_id();
258
259 collect_cpu_info_amd_early(&cpu_data(cpu), ucode_cpu_info + cpu);
260
261 if (cpu && !ucode_loaded) {
262 void *ucode;
263
264 if (!ucode_size || !initrd_start)
265 return;
266
267 ucode = (void *)(initrd_start + ucode_offset);
268 if (load_microcode_amd(0, ucode, ucode_size) != UCODE_OK)
269 return;
270 ucode_loaded = true;
271 }
272
273 apply_microcode_amd(cpu);
274}
275#endif
276
277int __init save_microcode_in_initrd_amd(void)
278{
279 enum ucode_state ret;
280 void *ucode;
281#ifdef CONFIG_X86_32
282 unsigned int bsp = boot_cpu_data.cpu_index;
283 struct ucode_cpu_info *uci = ucode_cpu_info + bsp;
284
285 if (!uci->cpu_sig.sig)
286 smp_call_function_single(bsp, collect_cpu_sig_on_bsp, NULL, 1);
287#endif
288 if (ucode_new_rev)
289 pr_info("microcode: updated early to new patch_level=0x%08x\n",
290 ucode_new_rev);
291
292 if (ucode_loaded || !ucode_size || !initrd_start)
293 return 0;
294
295 ucode = (void *)(initrd_start + ucode_offset);
296 ret = load_microcode_amd(0, ucode, ucode_size);
297 if (ret != UCODE_OK)
298 return -EINVAL;
299
300 ucode_loaded = true;
301 return 0;
302}
diff --git a/arch/x86/kernel/microcode_core_early.c b/arch/x86/kernel/microcode_core_early.c
index 833d51d6ee06..86119f63db0c 100644
--- a/arch/x86/kernel/microcode_core_early.c
+++ b/arch/x86/kernel/microcode_core_early.c
@@ -18,6 +18,7 @@
18 */ 18 */
19#include <linux/module.h> 19#include <linux/module.h>
20#include <asm/microcode_intel.h> 20#include <asm/microcode_intel.h>
21#include <asm/microcode_amd.h>
21#include <asm/processor.h> 22#include <asm/processor.h>
22 23
23#define QCHAR(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24)) 24#define QCHAR(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24))
@@ -81,8 +82,18 @@ void __init load_ucode_bsp(void)
81 vendor = x86_vendor(); 82 vendor = x86_vendor();
82 x86 = x86_family(); 83 x86 = x86_family();
83 84
84 if (vendor == X86_VENDOR_INTEL && x86 >= 6) 85 switch (vendor) {
85 load_ucode_intel_bsp(); 86 case X86_VENDOR_INTEL:
87 if (x86 >= 6)
88 load_ucode_intel_bsp();
89 break;
90 case X86_VENDOR_AMD:
91 if (x86 >= 0x10)
92 load_ucode_amd_bsp();
93 break;
94 default:
95 break;
96 }
86} 97}
87 98
88void __cpuinit load_ucode_ap(void) 99void __cpuinit load_ucode_ap(void)
@@ -95,6 +106,36 @@ void __cpuinit load_ucode_ap(void)
95 vendor = x86_vendor(); 106 vendor = x86_vendor();
96 x86 = x86_family(); 107 x86 = x86_family();
97 108
98 if (vendor == X86_VENDOR_INTEL && x86 >= 6) 109 switch (vendor) {
99 load_ucode_intel_ap(); 110 case X86_VENDOR_INTEL:
111 if (x86 >= 6)
112 load_ucode_intel_ap();
113 break;
114 case X86_VENDOR_AMD:
115 if (x86 >= 0x10)
116 load_ucode_amd_ap();
117 break;
118 default:
119 break;
120 }
121}
122
123int __init save_microcode_in_initrd(void)
124{
125 struct cpuinfo_x86 *c = &boot_cpu_data;
126
127 switch (c->x86_vendor) {
128 case X86_VENDOR_INTEL:
129 if (c->x86 >= 6)
130 save_microcode_in_initrd_intel();
131 break;
132 case X86_VENDOR_AMD:
133 if (c->x86 >= 0x10)
134 save_microcode_in_initrd_amd();
135 break;
136 default:
137 break;
138 }
139
140 return 0;
100} 141}
diff --git a/arch/x86/kernel/microcode_intel_early.c b/arch/x86/kernel/microcode_intel_early.c
index 2e9e12871c2b..dabef95506f3 100644
--- a/arch/x86/kernel/microcode_intel_early.c
+++ b/arch/x86/kernel/microcode_intel_early.c
@@ -529,7 +529,7 @@ int save_mc_for_early(u8 *mc)
529 */ 529 */
530 ret = save_microcode(&mc_saved_data, mc_saved_tmp, mc_saved_count); 530 ret = save_microcode(&mc_saved_data, mc_saved_tmp, mc_saved_count);
531 if (ret) { 531 if (ret) {
532 pr_err("Can not save microcode patch.\n"); 532 pr_err("Cannot save microcode patch.\n");
533 goto out; 533 goto out;
534 } 534 }
535 535
@@ -699,7 +699,7 @@ static int __cpuinit apply_microcode_early(struct mc_saved_data *mc_saved_data,
699 * This function converts microcode patch offsets previously stored in 699 * This function converts microcode patch offsets previously stored in
700 * mc_saved_in_initrd to pointers and stores the pointers in mc_saved_data. 700 * mc_saved_in_initrd to pointers and stores the pointers in mc_saved_data.
701 */ 701 */
702int __init save_microcode_in_initrd(void) 702int __init save_microcode_in_initrd_intel(void)
703{ 703{
704 unsigned int count = mc_saved_data.mc_saved_count; 704 unsigned int count = mc_saved_data.mc_saved_count;
705 struct microcode_intel *mc_saved[MAX_UCODE_COUNT]; 705 struct microcode_intel *mc_saved[MAX_UCODE_COUNT];
@@ -711,7 +711,7 @@ int __init save_microcode_in_initrd(void)
711 microcode_pointer(mc_saved, mc_saved_in_initrd, initrd_start, count); 711 microcode_pointer(mc_saved, mc_saved_in_initrd, initrd_start, count);
712 ret = save_microcode(&mc_saved_data, mc_saved, count); 712 ret = save_microcode(&mc_saved_data, mc_saved, count);
713 if (ret) 713 if (ret)
714 pr_err("Can not save microcod patches from initrd"); 714 pr_err("Cannot save microcode patches from initrd.\n");
715 715
716 show_saved_mc(); 716 show_saved_mc();
717 717