aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/x86/early-microcode.txt11
-rw-r--r--arch/x86/Kconfig14
-rw-r--r--arch/x86/include/asm/microcode_amd.h14
-rw-r--r--arch/x86/kernel/Makefile1
-rw-r--r--arch/x86/kernel/microcode_amd.c22
-rw-r--r--arch/x86/kernel/microcode_amd_early.c222
-rw-r--r--arch/x86/kernel/microcode_core_early.c43
7 files changed, 310 insertions, 17 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 685692c94f05..28dba52af514 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_INTEL || MICROCODE_AMD) && 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
index a57d9b75f30b..24254aaa857f 100644
--- a/arch/x86/include/asm/microcode_amd.h
+++ b/arch/x86/include/asm/microcode_amd.h
@@ -61,4 +61,18 @@ extern int __apply_microcode_amd(struct microcode_amd *mc_amd);
61extern int apply_microcode_amd(int cpu); 61extern int apply_microcode_amd(int cpu);
62extern enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size); 62extern enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size);
63 63
64#ifdef CONFIG_MICROCODE_AMD_EARLY
65#ifdef CONFIG_X86_32
66#define MPB_MAX_SIZE PAGE_SIZE
67extern u8 __cpuinitdata 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
64#endif /* _ASM_X86_MICROCODE_AMD_H */ 78#endif /* _ASM_X86_MICROCODE_AMD_H */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 7bd3bd310106..6c3fceaf8ff3 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 8f11f8f90e98..47ebb1dbfbcb 100644
--- a/arch/x86/kernel/microcode_amd.c
+++ b/arch/x86/kernel/microcode_amd.c
@@ -126,9 +126,20 @@ static struct ucode_patch *find_patch(unsigned int cpu)
126static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) 126static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
127{ 127{
128 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;
129 131
130 csig->sig = cpuid_eax(0x00000001); 132 csig->sig = cpuid_eax(0x00000001);
131 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
132 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);
133 144
134 return 0; 145 return 0;
@@ -373,6 +384,17 @@ enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size)
373 if (ret != UCODE_OK) 384 if (ret != UCODE_OK)
374 cleanup(); 385 cleanup();
375 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
376 return ret; 398 return ret;
377} 399}
378 400
diff --git a/arch/x86/kernel/microcode_amd_early.c b/arch/x86/kernel/microcode_amd_early.c
new file mode 100644
index 000000000000..7e54d97c714a
--- /dev/null
+++ b/arch/x86/kernel/microcode_amd_early.c
@@ -0,0 +1,222 @@
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
13#include <asm/cpu.h>
14#include <asm/setup.h>
15#include <asm/microcode_amd.h>
16
17static bool ucode_loaded;
18static u32 ucode_new_rev;
19
20/*
21 * Microcode patch container file is prepended to the initrd in cpio format.
22 * See Documentation/x86/early-microcode.txt
23 */
24static __initdata char ucode_path[] = "kernel/x86/microcode/AuthenticAMD.bin";
25
26static struct cpio_data __init find_ucode_in_initrd(void)
27{
28 long offset = 0;
29 struct cpio_data cd;
30
31#ifdef CONFIG_X86_32
32 /*
33 * On 32-bit, early load occurs before paging is turned on so we need
34 * to use physical addresses.
35 */
36 if (!(read_cr0() & X86_CR0_PG)) {
37 struct boot_params *p;
38 p = (struct boot_params *)__pa_nodebug(&boot_params);
39 cd = find_cpio_data((char *)__pa_nodebug(ucode_path),
40 (void *)p->hdr.ramdisk_image, p->hdr.ramdisk_size,
41 &offset);
42 } else
43#endif
44 cd = find_cpio_data(ucode_path,
45 (void *)(boot_params.hdr.ramdisk_image + PAGE_OFFSET),
46 boot_params.hdr.ramdisk_size, &offset);
47
48 if (*(u32 *)cd.data != UCODE_MAGIC) {
49 cd.data = NULL;
50 cd.size = 0;
51 }
52
53 return cd;
54}
55
56/*
57 * Early load occurs before we can vmalloc(). So we look for the microcode
58 * patch container file in initrd, traverse equivalent cpu table, look for a
59 * matching microcode patch, and update, all in initrd memory in place.
60 * When vmalloc() is available for use later -- on 64-bit during first AP load,
61 * and on 32-bit during save_microcode_in_initrd_amd() -- we can call
62 * load_microcode_amd() to save equivalent cpu table and microcode patches in
63 * kernel heap memory.
64 */
65static void __init apply_ucode_in_initrd(void)
66{
67 struct cpio_data cd;
68 struct equiv_cpu_entry *eq;
69 u32 *header;
70 u8 *data;
71 u16 eq_id;
72 int offset, left;
73 u32 rev, dummy;
74 u32 *new_rev;
75
76#ifdef CONFIG_X86_32
77 new_rev = (u32 *)__pa_nodebug(&ucode_new_rev);
78#else
79 new_rev = &ucode_new_rev;
80#endif
81 cd = find_ucode_in_initrd();
82 if (!cd.data)
83 return;
84
85 data = cd.data;
86 left = cd.size;
87 header = (u32 *)data;
88
89 /* find equiv cpu table */
90
91 if (header[1] != UCODE_EQUIV_CPU_TABLE_TYPE || /* type */
92 header[2] == 0) /* size */
93 return;
94
95 eq = (struct equiv_cpu_entry *)(data + CONTAINER_HDR_SZ);
96 offset = header[2] + CONTAINER_HDR_SZ;
97 data += offset;
98 left -= offset;
99
100 eq_id = find_equiv_id(eq, cpuid_eax(0x00000001));
101 if (!eq_id)
102 return;
103
104 /* find ucode and update if needed */
105
106 rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
107
108 while (left > 0) {
109 struct microcode_amd *mc;
110
111 header = (u32 *)data;
112 if (header[0] != UCODE_UCODE_TYPE || /* type */
113 header[1] == 0) /* size */
114 break;
115
116 mc = (struct microcode_amd *)(data + SECTION_HDR_SIZE);
117 if (eq_id == mc->hdr.processor_rev_id && rev < mc->hdr.patch_id)
118 if (__apply_microcode_amd(mc) == 0) {
119 if (!(*new_rev))
120 *new_rev = mc->hdr.patch_id;
121 break;
122 }
123
124 offset = header[1] + SECTION_HDR_SIZE;
125 data += offset;
126 left -= offset;
127 }
128}
129
130void __init load_ucode_amd_bsp(void)
131{
132 apply_ucode_in_initrd();
133}
134
135#ifdef CONFIG_X86_32
136u8 __cpuinitdata amd_bsp_mpb[MPB_MAX_SIZE];
137
138/*
139 * On 32-bit, since AP's early load occurs before paging is turned on, we
140 * cannot traverse cpu_equiv_table and pcache in kernel heap memory. So during
141 * cold boot, AP will apply_ucode_in_initrd() just like the BSP. During
142 * save_microcode_in_initrd_amd() BSP's patch is copied to amd_bsp_mpb, which
143 * is used upon resume from suspend.
144 */
145void __cpuinit load_ucode_amd_ap(void)
146{
147 struct microcode_amd *mc;
148
149 mc = (struct microcode_amd *)__pa_nodebug(amd_bsp_mpb);
150 if (mc->hdr.patch_id && mc->hdr.processor_rev_id)
151 __apply_microcode_amd(mc);
152 else
153 apply_ucode_in_initrd();
154}
155
156static void __init collect_cpu_sig_on_bsp(void *arg)
157{
158 unsigned int cpu = smp_processor_id();
159 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
160 uci->cpu_sig.sig = cpuid_eax(0x00000001);
161}
162#else
163static void __cpuinit collect_cpu_info_amd_early(struct cpuinfo_x86 *c,
164 struct ucode_cpu_info *uci)
165{
166 u32 rev, eax;
167
168 rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax);
169 eax = cpuid_eax(0x00000001);
170
171 uci->cpu_sig.sig = eax;
172 uci->cpu_sig.rev = rev;
173 c->microcode = rev;
174 c->x86 = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);
175}
176
177void __cpuinit load_ucode_amd_ap(void)
178{
179 unsigned int cpu = smp_processor_id();
180
181 collect_cpu_info_amd_early(&cpu_data(cpu), ucode_cpu_info + cpu);
182
183 if (cpu && !ucode_loaded) {
184 struct cpio_data cd = find_ucode_in_initrd();
185 if (load_microcode_amd(0, cd.data, cd.size) != UCODE_OK)
186 return;
187 ucode_loaded = true;
188 }
189
190 apply_microcode_amd(cpu);
191}
192#endif
193
194int __init save_microcode_in_initrd_amd(void)
195{
196 enum ucode_state ret;
197 struct cpio_data cd;
198#ifdef CONFIG_X86_32
199 unsigned int bsp = boot_cpu_data.cpu_index;
200 struct ucode_cpu_info *uci = ucode_cpu_info + bsp;
201
202 if (!uci->cpu_sig.sig)
203 smp_call_function_single(bsp, collect_cpu_sig_on_bsp, NULL, 1);
204#endif
205 if (ucode_new_rev)
206 pr_info("microcode: updated early to new patch_level=0x%08x\n",
207 ucode_new_rev);
208
209 if (ucode_loaded)
210 return 0;
211
212 cd = find_ucode_in_initrd();
213 if (!cd.data)
214 return -EINVAL;
215
216 ret = load_microcode_amd(0, cd.data, cd.size);
217 if (ret != UCODE_OK)
218 return -EINVAL;
219
220 ucode_loaded = true;
221 return 0;
222}
diff --git a/arch/x86/kernel/microcode_core_early.c b/arch/x86/kernel/microcode_core_early.c
index 0d19ac5016a7..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,16 +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 }
100} 121}
101 122
102int __init save_microcode_in_initrd(void) 123int __init save_microcode_in_initrd(void)
103{ 124{
104 struct cpuinfo_x86 *c = &boot_cpu_data; 125 struct cpuinfo_x86 *c = &boot_cpu_data;
105 126
106 if (c->x86_vendor == X86_VENDOR_INTEL && c->x86 >= 6) 127 switch (c->x86_vendor) {
107 return save_microcode_in_initrd_intel(); 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 }
108 139
109 return 0; 140 return 0;
110} 141}