diff options
-rw-r--r-- | MAINTAINERS | 5 | ||||
-rw-r--r-- | arch/x86/Kconfig | 46 | ||||
-rw-r--r-- | arch/x86/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/kernel/microcode.c | 480 | ||||
-rw-r--r-- | arch/x86/kernel/microcode_amd.c | 520 | ||||
-rw-r--r-- | arch/x86/kernel/microcode_intel.c | 545 | ||||
-rw-r--r-- | include/asm-x86/microcode.h | 87 | ||||
-rw-r--r-- | include/asm-x86/processor.h | 35 |
8 files changed, 1245 insertions, 475 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index deedc0d827b5..4bfa468ceae2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -384,6 +384,11 @@ M: joerg.roedel@amd.com | |||
384 | L: iommu@lists.linux-foundation.org | 384 | L: iommu@lists.linux-foundation.org |
385 | S: Supported | 385 | S: Supported |
386 | 386 | ||
387 | AMD MICROCODE UPDATE SUPPORT | ||
388 | P: Peter Oruba | ||
389 | M: peter.oruba@amd.com | ||
390 | S: Supported | ||
391 | |||
387 | AMS (Apple Motion Sensor) DRIVER | 392 | AMS (Apple Motion Sensor) DRIVER |
388 | P: Stelian Pop | 393 | P: Stelian Pop |
389 | M: stelian@popies.net | 394 | M: stelian@popies.net |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 3d0f2b6a5a16..0e5bf1eddcea 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -783,23 +783,51 @@ config X86_REBOOTFIXUPS | |||
783 | Say N otherwise. | 783 | Say N otherwise. |
784 | 784 | ||
785 | config MICROCODE | 785 | config MICROCODE |
786 | tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support" | 786 | tristate "/dev/cpu/microcode - microcode support" |
787 | select FW_LOADER | 787 | select FW_LOADER |
788 | ---help--- | 788 | ---help--- |
789 | If you say Y here, you will be able to update the microcode on | 789 | If you say Y here, you will be able to update the microcode on |
790 | Intel processors in the IA32 family, e.g. Pentium Pro, Pentium II, | 790 | certain Intel and AMD processors. The Intel support is for the |
791 | Pentium III, Pentium 4, Xeon etc. You will obviously need the | 791 | IA32 family, e.g. Pentium Pro, Pentium II, Pentium III, |
792 | actual microcode binary data itself which is not shipped with the | 792 | Pentium 4, Xeon etc. The AMD support is for family 0x10 and |
793 | Linux kernel. | 793 | 0x11 processors, e.g. Opteron, Phenom and Turion 64 Ultra. |
794 | You will obviously need the actual microcode binary data itself | ||
795 | which is not shipped with the Linux kernel. | ||
794 | 796 | ||
795 | For latest news and information on obtaining all the required | 797 | This option selects the general module only, you need to select |
796 | ingredients for this driver, check: | 798 | at least one vendor specific module as well. |
797 | <http://www.urbanmyth.org/microcode/>. | ||
798 | 799 | ||
799 | To compile this driver as a module, choose M here: the | 800 | To compile this driver as a module, choose M here: the |
800 | module will be called microcode. | 801 | module will be called microcode. |
801 | 802 | ||
802 | config MICROCODE_OLD_INTERFACE | 803 | config MICROCODE_INTEL |
804 | tristate "Intel microcode patch loading support" | ||
805 | depends on MICROCODE | ||
806 | default MICROCODE | ||
807 | select FW_LOADER | ||
808 | --help--- | ||
809 | This options enables microcode patch loading support for Intel | ||
810 | processors. | ||
811 | |||
812 | For latest news and information on obtaining all the required | ||
813 | Intel ingredients for this driver, check: | ||
814 | <http://www.urbanmyth.org/microcode/>. | ||
815 | |||
816 | This driver is only available as a module: the module | ||
817 | will be called microcode_intel. | ||
818 | |||
819 | config MICROCODE_AMD | ||
820 | tristate "AMD microcode patch loading support" | ||
821 | depends on MICROCODE | ||
822 | select FW_LOADER | ||
823 | --help--- | ||
824 | If you select this option, microcode patch loading support for AMD | ||
825 | processors will be enabled. | ||
826 | |||
827 | This driver is only available as a module: the module | ||
828 | will be called microcode_amd. | ||
829 | |||
830 | config MICROCODE_OLD_INTERFACE | ||
803 | def_bool y | 831 | def_bool y |
804 | depends on MICROCODE | 832 | depends on MICROCODE |
805 | 833 | ||
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 3db651fc8ec5..be454f348c3b 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -52,6 +52,8 @@ obj-$(CONFIG_MCA) += mca_32.o | |||
52 | obj-$(CONFIG_X86_MSR) += msr.o | 52 | obj-$(CONFIG_X86_MSR) += msr.o |
53 | obj-$(CONFIG_X86_CPUID) += cpuid.o | 53 | obj-$(CONFIG_X86_CPUID) += cpuid.o |
54 | obj-$(CONFIG_MICROCODE) += microcode.o | 54 | obj-$(CONFIG_MICROCODE) += microcode.o |
55 | obj-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o | ||
56 | obj-$(CONFIG_MICROCODE_AMD) += microcode_amd.o | ||
55 | obj-$(CONFIG_PCI) += early-quirks.o | 57 | obj-$(CONFIG_PCI) += early-quirks.o |
56 | apm-y := apm_32.o | 58 | apm-y := apm_32.o |
57 | obj-$(CONFIG_APM) += apm.o | 59 | obj-$(CONFIG_APM) += apm.o |
diff --git a/arch/x86/kernel/microcode.c b/arch/x86/kernel/microcode.c index 652fa5c38ebe..28dba1a6e4aa 100644 --- a/arch/x86/kernel/microcode.c +++ b/arch/x86/kernel/microcode.c | |||
@@ -93,293 +93,28 @@ | |||
93 | #include <asm/msr.h> | 93 | #include <asm/msr.h> |
94 | #include <asm/uaccess.h> | 94 | #include <asm/uaccess.h> |
95 | #include <asm/processor.h> | 95 | #include <asm/processor.h> |
96 | #include <asm/microcode.h> | ||
96 | 97 | ||
97 | MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver"); | 98 | MODULE_DESCRIPTION("Microcode Update Driver"); |
98 | MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); | 99 | MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); |
99 | MODULE_LICENSE("GPL"); | 100 | MODULE_LICENSE("GPL"); |
100 | 101 | ||
101 | #define MICROCODE_VERSION "1.14a" | 102 | #define MICROCODE_VERSION "2.00" |
102 | 103 | ||
103 | #define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */ | 104 | struct microcode_ops *microcode_ops; |
104 | #define MC_HEADER_SIZE (sizeof (microcode_header_t)) /* 48 bytes */ | ||
105 | #define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) /* 2048 bytes */ | ||
106 | #define EXT_HEADER_SIZE (sizeof (struct extended_sigtable)) /* 20 bytes */ | ||
107 | #define EXT_SIGNATURE_SIZE (sizeof (struct extended_signature)) /* 12 bytes */ | ||
108 | #define DWSIZE (sizeof (u32)) | ||
109 | #define get_totalsize(mc) \ | ||
110 | (((microcode_t *)mc)->hdr.totalsize ? \ | ||
111 | ((microcode_t *)mc)->hdr.totalsize : DEFAULT_UCODE_TOTALSIZE) | ||
112 | #define get_datasize(mc) \ | ||
113 | (((microcode_t *)mc)->hdr.datasize ? \ | ||
114 | ((microcode_t *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE) | ||
115 | |||
116 | #define sigmatch(s1, s2, p1, p2) \ | ||
117 | (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0)))) | ||
118 | |||
119 | #define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE) | ||
120 | |||
121 | /* serialize access to the physical write to MSR 0x79 */ | ||
122 | static DEFINE_SPINLOCK(microcode_update_lock); | ||
123 | 105 | ||
124 | /* no concurrent ->write()s are allowed on /dev/cpu/microcode */ | 106 | /* no concurrent ->write()s are allowed on /dev/cpu/microcode */ |
125 | static DEFINE_MUTEX(microcode_mutex); | 107 | DEFINE_MUTEX(microcode_mutex); |
126 | 108 | EXPORT_SYMBOL_GPL(microcode_mutex); | |
127 | static struct ucode_cpu_info { | ||
128 | int valid; | ||
129 | unsigned int sig; | ||
130 | unsigned int pf; | ||
131 | unsigned int rev; | ||
132 | microcode_t *mc; | ||
133 | } ucode_cpu_info[NR_CPUS]; | ||
134 | |||
135 | static void collect_cpu_info(int cpu_num) | ||
136 | { | ||
137 | struct cpuinfo_x86 *c = &cpu_data(cpu_num); | ||
138 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; | ||
139 | unsigned int val[2]; | ||
140 | |||
141 | /* We should bind the task to the CPU */ | ||
142 | BUG_ON(raw_smp_processor_id() != cpu_num); | ||
143 | uci->pf = uci->rev = 0; | ||
144 | uci->mc = NULL; | ||
145 | uci->valid = 1; | ||
146 | |||
147 | if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 || | ||
148 | cpu_has(c, X86_FEATURE_IA64)) { | ||
149 | printk(KERN_ERR "microcode: CPU%d not a capable Intel " | ||
150 | "processor\n", cpu_num); | ||
151 | uci->valid = 0; | ||
152 | return; | ||
153 | } | ||
154 | |||
155 | uci->sig = cpuid_eax(0x00000001); | ||
156 | |||
157 | if ((c->x86_model >= 5) || (c->x86 > 6)) { | ||
158 | /* get processor flags from MSR 0x17 */ | ||
159 | rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); | ||
160 | uci->pf = 1 << ((val[1] >> 18) & 7); | ||
161 | } | ||
162 | |||
163 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); | ||
164 | /* see notes above for revision 1.07. Apparent chip bug */ | ||
165 | sync_core(); | ||
166 | /* get the current revision from MSR 0x8B */ | ||
167 | rdmsr(MSR_IA32_UCODE_REV, val[0], uci->rev); | ||
168 | pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n", | ||
169 | uci->sig, uci->pf, uci->rev); | ||
170 | } | ||
171 | |||
172 | static inline int microcode_update_match(int cpu_num, | ||
173 | microcode_header_t *mc_header, int sig, int pf) | ||
174 | { | ||
175 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; | ||
176 | |||
177 | if (!sigmatch(sig, uci->sig, pf, uci->pf) | ||
178 | || mc_header->rev <= uci->rev) | ||
179 | return 0; | ||
180 | return 1; | ||
181 | } | ||
182 | |||
183 | static int microcode_sanity_check(void *mc) | ||
184 | { | ||
185 | microcode_header_t *mc_header = mc; | ||
186 | struct extended_sigtable *ext_header = NULL; | ||
187 | struct extended_signature *ext_sig; | ||
188 | unsigned long total_size, data_size, ext_table_size; | ||
189 | int sum, orig_sum, ext_sigcount = 0, i; | ||
190 | |||
191 | total_size = get_totalsize(mc_header); | ||
192 | data_size = get_datasize(mc_header); | ||
193 | if (data_size + MC_HEADER_SIZE > total_size) { | ||
194 | printk(KERN_ERR "microcode: error! " | ||
195 | "Bad data size in microcode data file\n"); | ||
196 | return -EINVAL; | ||
197 | } | ||
198 | |||
199 | if (mc_header->ldrver != 1 || mc_header->hdrver != 1) { | ||
200 | printk(KERN_ERR "microcode: error! " | ||
201 | "Unknown microcode update format\n"); | ||
202 | return -EINVAL; | ||
203 | } | ||
204 | ext_table_size = total_size - (MC_HEADER_SIZE + data_size); | ||
205 | if (ext_table_size) { | ||
206 | if ((ext_table_size < EXT_HEADER_SIZE) | ||
207 | || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) { | ||
208 | printk(KERN_ERR "microcode: error! " | ||
209 | "Small exttable size in microcode data file\n"); | ||
210 | return -EINVAL; | ||
211 | } | ||
212 | ext_header = mc + MC_HEADER_SIZE + data_size; | ||
213 | if (ext_table_size != exttable_size(ext_header)) { | ||
214 | printk(KERN_ERR "microcode: error! " | ||
215 | "Bad exttable size in microcode data file\n"); | ||
216 | return -EFAULT; | ||
217 | } | ||
218 | ext_sigcount = ext_header->count; | ||
219 | } | ||
220 | |||
221 | /* check extended table checksum */ | ||
222 | if (ext_table_size) { | ||
223 | int ext_table_sum = 0; | ||
224 | int *ext_tablep = (int *)ext_header; | ||
225 | |||
226 | i = ext_table_size / DWSIZE; | ||
227 | while (i--) | ||
228 | ext_table_sum += ext_tablep[i]; | ||
229 | if (ext_table_sum) { | ||
230 | printk(KERN_WARNING "microcode: aborting, " | ||
231 | "bad extended signature table checksum\n"); | ||
232 | return -EINVAL; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | /* calculate the checksum */ | ||
237 | orig_sum = 0; | ||
238 | i = (MC_HEADER_SIZE + data_size) / DWSIZE; | ||
239 | while (i--) | ||
240 | orig_sum += ((int *)mc)[i]; | ||
241 | if (orig_sum) { | ||
242 | printk(KERN_ERR "microcode: aborting, bad checksum\n"); | ||
243 | return -EINVAL; | ||
244 | } | ||
245 | if (!ext_table_size) | ||
246 | return 0; | ||
247 | /* check extended signature checksum */ | ||
248 | for (i = 0; i < ext_sigcount; i++) { | ||
249 | ext_sig = (void *)ext_header + EXT_HEADER_SIZE + | ||
250 | EXT_SIGNATURE_SIZE * i; | ||
251 | sum = orig_sum | ||
252 | - (mc_header->sig + mc_header->pf + mc_header->cksum) | ||
253 | + (ext_sig->sig + ext_sig->pf + ext_sig->cksum); | ||
254 | if (sum) { | ||
255 | printk(KERN_ERR "microcode: aborting, bad checksum\n"); | ||
256 | return -EINVAL; | ||
257 | } | ||
258 | } | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | /* | ||
263 | * return 0 - no update found | ||
264 | * return 1 - found update | ||
265 | * return < 0 - error | ||
266 | */ | ||
267 | static int get_maching_microcode(void *mc, int cpu) | ||
268 | { | ||
269 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
270 | microcode_header_t *mc_header = mc; | ||
271 | struct extended_sigtable *ext_header; | ||
272 | unsigned long total_size = get_totalsize(mc_header); | ||
273 | int ext_sigcount, i; | ||
274 | struct extended_signature *ext_sig; | ||
275 | void *new_mc; | ||
276 | |||
277 | if (microcode_update_match(cpu, mc_header, | ||
278 | mc_header->sig, mc_header->pf)) | ||
279 | goto find; | ||
280 | |||
281 | if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE) | ||
282 | return 0; | ||
283 | |||
284 | ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE; | ||
285 | ext_sigcount = ext_header->count; | ||
286 | ext_sig = (void *)ext_header + EXT_HEADER_SIZE; | ||
287 | for (i = 0; i < ext_sigcount; i++) { | ||
288 | if (microcode_update_match(cpu, mc_header, | ||
289 | ext_sig->sig, ext_sig->pf)) | ||
290 | goto find; | ||
291 | ext_sig++; | ||
292 | } | ||
293 | return 0; | ||
294 | find: | ||
295 | pr_debug("microcode: CPU%d found a matching microcode update with" | ||
296 | " version 0x%x (current=0x%x)\n", cpu, mc_header->rev,uci->rev); | ||
297 | new_mc = vmalloc(total_size); | ||
298 | if (!new_mc) { | ||
299 | printk(KERN_ERR "microcode: error! Can not allocate memory\n"); | ||
300 | return -ENOMEM; | ||
301 | } | ||
302 | |||
303 | /* free previous update file */ | ||
304 | vfree(uci->mc); | ||
305 | |||
306 | memcpy(new_mc, mc, total_size); | ||
307 | uci->mc = new_mc; | ||
308 | return 1; | ||
309 | } | ||
310 | 109 | ||
311 | static void apply_microcode(int cpu) | 110 | struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; |
312 | { | 111 | EXPORT_SYMBOL_GPL(ucode_cpu_info); |
313 | unsigned long flags; | ||
314 | unsigned int val[2]; | ||
315 | int cpu_num = raw_smp_processor_id(); | ||
316 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; | ||
317 | |||
318 | /* We should bind the task to the CPU */ | ||
319 | BUG_ON(cpu_num != cpu); | ||
320 | |||
321 | if (uci->mc == NULL) | ||
322 | return; | ||
323 | |||
324 | /* serialize access to the physical write to MSR 0x79 */ | ||
325 | spin_lock_irqsave(µcode_update_lock, flags); | ||
326 | |||
327 | /* write microcode via MSR 0x79 */ | ||
328 | wrmsr(MSR_IA32_UCODE_WRITE, | ||
329 | (unsigned long) uci->mc->bits, | ||
330 | (unsigned long) uci->mc->bits >> 16 >> 16); | ||
331 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); | ||
332 | |||
333 | /* see notes above for revision 1.07. Apparent chip bug */ | ||
334 | sync_core(); | ||
335 | |||
336 | /* get the current revision from MSR 0x8B */ | ||
337 | rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); | ||
338 | |||
339 | spin_unlock_irqrestore(µcode_update_lock, flags); | ||
340 | if (val[1] != uci->mc->hdr.rev) { | ||
341 | printk(KERN_ERR "microcode: CPU%d update from revision " | ||
342 | "0x%x to 0x%x failed\n", cpu_num, uci->rev, val[1]); | ||
343 | return; | ||
344 | } | ||
345 | printk(KERN_INFO "microcode: CPU%d updated from revision " | ||
346 | "0x%x to 0x%x, date = %08x \n", | ||
347 | cpu_num, uci->rev, val[1], uci->mc->hdr.date); | ||
348 | uci->rev = val[1]; | ||
349 | } | ||
350 | 112 | ||
351 | #ifdef CONFIG_MICROCODE_OLD_INTERFACE | 113 | #ifdef CONFIG_MICROCODE_OLD_INTERFACE |
352 | static void __user *user_buffer; /* user area microcode data buffer */ | 114 | void __user *user_buffer; /* user area microcode data buffer */ |
353 | static unsigned int user_buffer_size; /* it's size */ | 115 | EXPORT_SYMBOL_GPL(user_buffer); |
354 | 116 | unsigned int user_buffer_size; /* it's size */ | |
355 | static long get_next_ucode(void **mc, long offset) | 117 | EXPORT_SYMBOL_GPL(user_buffer_size); |
356 | { | ||
357 | microcode_header_t mc_header; | ||
358 | unsigned long total_size; | ||
359 | |||
360 | /* No more data */ | ||
361 | if (offset >= user_buffer_size) | ||
362 | return 0; | ||
363 | if (copy_from_user(&mc_header, user_buffer + offset, MC_HEADER_SIZE)) { | ||
364 | printk(KERN_ERR "microcode: error! Can not read user data\n"); | ||
365 | return -EFAULT; | ||
366 | } | ||
367 | total_size = get_totalsize(&mc_header); | ||
368 | if (offset + total_size > user_buffer_size) { | ||
369 | printk(KERN_ERR "microcode: error! Bad total size in microcode " | ||
370 | "data file\n"); | ||
371 | return -EINVAL; | ||
372 | } | ||
373 | *mc = vmalloc(total_size); | ||
374 | if (!*mc) | ||
375 | return -ENOMEM; | ||
376 | if (copy_from_user(*mc, user_buffer + offset, total_size)) { | ||
377 | printk(KERN_ERR "microcode: error! Can not read user data\n"); | ||
378 | vfree(*mc); | ||
379 | return -EFAULT; | ||
380 | } | ||
381 | return offset + total_size; | ||
382 | } | ||
383 | 118 | ||
384 | static int do_microcode_update (void) | 119 | static int do_microcode_update (void) |
385 | { | 120 | { |
@@ -391,8 +126,8 @@ static int do_microcode_update (void) | |||
391 | 126 | ||
392 | old = current->cpus_allowed; | 127 | old = current->cpus_allowed; |
393 | 128 | ||
394 | while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) { | 129 | while ((cursor = microcode_ops->get_next_ucode(&new_mc, cursor)) > 0) { |
395 | error = microcode_sanity_check(new_mc); | 130 | error = microcode_ops->microcode_sanity_check(new_mc); |
396 | if (error) | 131 | if (error) |
397 | goto out; | 132 | goto out; |
398 | /* | 133 | /* |
@@ -405,11 +140,12 @@ static int do_microcode_update (void) | |||
405 | if (!uci->valid) | 140 | if (!uci->valid) |
406 | continue; | 141 | continue; |
407 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | 142 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); |
408 | error = get_maching_microcode(new_mc, cpu); | 143 | error = microcode_ops->get_matching_microcode(new_mc, |
144 | cpu); | ||
409 | if (error < 0) | 145 | if (error < 0) |
410 | goto out; | 146 | goto out; |
411 | if (error == 1) | 147 | if (error == 1) |
412 | apply_microcode(cpu); | 148 | microcode_ops->apply_microcode(cpu); |
413 | } | 149 | } |
414 | vfree(new_mc); | 150 | vfree(new_mc); |
415 | } | 151 | } |
@@ -491,131 +227,9 @@ MODULE_ALIAS_MISCDEV(MICROCODE_MINOR); | |||
491 | #define microcode_dev_exit() do { } while(0) | 227 | #define microcode_dev_exit() do { } while(0) |
492 | #endif | 228 | #endif |
493 | 229 | ||
494 | static long get_next_ucode_from_buffer(void **mc, const u8 *buf, | ||
495 | unsigned long size, long offset) | ||
496 | { | ||
497 | microcode_header_t *mc_header; | ||
498 | unsigned long total_size; | ||
499 | |||
500 | /* No more data */ | ||
501 | if (offset >= size) | ||
502 | return 0; | ||
503 | mc_header = (microcode_header_t *)(buf + offset); | ||
504 | total_size = get_totalsize(mc_header); | ||
505 | |||
506 | if (offset + total_size > size) { | ||
507 | printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); | ||
508 | return -EINVAL; | ||
509 | } | ||
510 | |||
511 | *mc = vmalloc(total_size); | ||
512 | if (!*mc) { | ||
513 | printk(KERN_ERR "microcode: error! Can not allocate memory\n"); | ||
514 | return -ENOMEM; | ||
515 | } | ||
516 | memcpy(*mc, buf + offset, total_size); | ||
517 | return offset + total_size; | ||
518 | } | ||
519 | |||
520 | /* fake device for request_firmware */ | 230 | /* fake device for request_firmware */ |
521 | static struct platform_device *microcode_pdev; | 231 | struct platform_device *microcode_pdev; |
522 | 232 | EXPORT_SYMBOL_GPL(microcode_pdev); | |
523 | static int cpu_request_microcode(int cpu) | ||
524 | { | ||
525 | char name[30]; | ||
526 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
527 | const struct firmware *firmware; | ||
528 | const u8 *buf; | ||
529 | unsigned long size; | ||
530 | long offset = 0; | ||
531 | int error; | ||
532 | void *mc; | ||
533 | |||
534 | /* We should bind the task to the CPU */ | ||
535 | BUG_ON(cpu != raw_smp_processor_id()); | ||
536 | sprintf(name,"intel-ucode/%02x-%02x-%02x", | ||
537 | c->x86, c->x86_model, c->x86_mask); | ||
538 | error = request_firmware(&firmware, name, µcode_pdev->dev); | ||
539 | if (error) { | ||
540 | pr_debug("microcode: data file %s load failed\n", name); | ||
541 | return error; | ||
542 | } | ||
543 | buf = firmware->data; | ||
544 | size = firmware->size; | ||
545 | while ((offset = get_next_ucode_from_buffer(&mc, buf, size, offset)) | ||
546 | > 0) { | ||
547 | error = microcode_sanity_check(mc); | ||
548 | if (error) | ||
549 | break; | ||
550 | error = get_maching_microcode(mc, cpu); | ||
551 | if (error < 0) | ||
552 | break; | ||
553 | /* | ||
554 | * It's possible the data file has multiple matching ucode, | ||
555 | * lets keep searching till the latest version | ||
556 | */ | ||
557 | if (error == 1) { | ||
558 | apply_microcode(cpu); | ||
559 | error = 0; | ||
560 | } | ||
561 | vfree(mc); | ||
562 | } | ||
563 | if (offset > 0) | ||
564 | vfree(mc); | ||
565 | if (offset < 0) | ||
566 | error = offset; | ||
567 | release_firmware(firmware); | ||
568 | |||
569 | return error; | ||
570 | } | ||
571 | |||
572 | static int apply_microcode_check_cpu(int cpu) | ||
573 | { | ||
574 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
575 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
576 | cpumask_t old; | ||
577 | unsigned int val[2]; | ||
578 | int err = 0; | ||
579 | |||
580 | /* Check if the microcode is available */ | ||
581 | if (!uci->mc) | ||
582 | return 0; | ||
583 | |||
584 | old = current->cpus_allowed; | ||
585 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | ||
586 | |||
587 | /* Check if the microcode we have in memory matches the CPU */ | ||
588 | if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 || | ||
589 | cpu_has(c, X86_FEATURE_IA64) || uci->sig != cpuid_eax(0x00000001)) | ||
590 | err = -EINVAL; | ||
591 | |||
592 | if (!err && ((c->x86_model >= 5) || (c->x86 > 6))) { | ||
593 | /* get processor flags from MSR 0x17 */ | ||
594 | rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); | ||
595 | if (uci->pf != (1 << ((val[1] >> 18) & 7))) | ||
596 | err = -EINVAL; | ||
597 | } | ||
598 | |||
599 | if (!err) { | ||
600 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); | ||
601 | /* see notes above for revision 1.07. Apparent chip bug */ | ||
602 | sync_core(); | ||
603 | /* get the current revision from MSR 0x8B */ | ||
604 | rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); | ||
605 | if (uci->rev != val[1]) | ||
606 | err = -EINVAL; | ||
607 | } | ||
608 | |||
609 | if (!err) | ||
610 | apply_microcode(cpu); | ||
611 | else | ||
612 | printk(KERN_ERR "microcode: Could not apply microcode to CPU%d:" | ||
613 | " sig=0x%x, pf=0x%x, rev=0x%x\n", | ||
614 | cpu, uci->sig, uci->pf, uci->rev); | ||
615 | |||
616 | set_cpus_allowed_ptr(current, &old); | ||
617 | return err; | ||
618 | } | ||
619 | 233 | ||
620 | static void microcode_init_cpu(int cpu, int resume) | 234 | static void microcode_init_cpu(int cpu, int resume) |
621 | { | 235 | { |
@@ -626,24 +240,13 @@ static void microcode_init_cpu(int cpu, int resume) | |||
626 | 240 | ||
627 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | 241 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); |
628 | mutex_lock(µcode_mutex); | 242 | mutex_lock(µcode_mutex); |
629 | collect_cpu_info(cpu); | 243 | microcode_ops->collect_cpu_info(cpu); |
630 | if (uci->valid && system_state == SYSTEM_RUNNING && !resume) | 244 | if (uci->valid && system_state == SYSTEM_RUNNING && !resume) |
631 | cpu_request_microcode(cpu); | 245 | microcode_ops->cpu_request_microcode(cpu); |
632 | mutex_unlock(µcode_mutex); | 246 | mutex_unlock(µcode_mutex); |
633 | set_cpus_allowed_ptr(current, &old); | 247 | set_cpus_allowed_ptr(current, &old); |
634 | } | 248 | } |
635 | 249 | ||
636 | static void microcode_fini_cpu(int cpu) | ||
637 | { | ||
638 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
639 | |||
640 | mutex_lock(µcode_mutex); | ||
641 | uci->valid = 0; | ||
642 | vfree(uci->mc); | ||
643 | uci->mc = NULL; | ||
644 | mutex_unlock(µcode_mutex); | ||
645 | } | ||
646 | |||
647 | static ssize_t reload_store(struct sys_device *dev, | 250 | static ssize_t reload_store(struct sys_device *dev, |
648 | struct sysdev_attribute *attr, | 251 | struct sysdev_attribute *attr, |
649 | const char *buf, size_t sz) | 252 | const char *buf, size_t sz) |
@@ -664,7 +267,7 @@ static ssize_t reload_store(struct sys_device *dev, | |||
664 | 267 | ||
665 | mutex_lock(µcode_mutex); | 268 | mutex_lock(µcode_mutex); |
666 | if (uci->valid) | 269 | if (uci->valid) |
667 | err = cpu_request_microcode(cpu); | 270 | err = microcode_ops->cpu_request_microcode(cpu); |
668 | mutex_unlock(µcode_mutex); | 271 | mutex_unlock(µcode_mutex); |
669 | put_online_cpus(); | 272 | put_online_cpus(); |
670 | set_cpus_allowed_ptr(current, &old); | 273 | set_cpus_allowed_ptr(current, &old); |
@@ -739,7 +342,7 @@ static int mc_sysdev_remove(struct sys_device *sys_dev) | |||
739 | return 0; | 342 | return 0; |
740 | 343 | ||
741 | pr_debug("microcode: CPU%d removed\n", cpu); | 344 | pr_debug("microcode: CPU%d removed\n", cpu); |
742 | microcode_fini_cpu(cpu); | 345 | microcode_ops->microcode_fini_cpu(cpu); |
743 | sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); | 346 | sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); |
744 | return 0; | 347 | return 0; |
745 | } | 348 | } |
@@ -752,7 +355,7 @@ static int mc_sysdev_resume(struct sys_device *dev) | |||
752 | return 0; | 355 | return 0; |
753 | pr_debug("microcode: CPU%d resumed\n", cpu); | 356 | pr_debug("microcode: CPU%d resumed\n", cpu); |
754 | /* only CPU 0 will apply ucode here */ | 357 | /* only CPU 0 will apply ucode here */ |
755 | apply_microcode(0); | 358 | microcode_ops->apply_microcode(0); |
756 | return 0; | 359 | return 0; |
757 | } | 360 | } |
758 | 361 | ||
@@ -772,7 +375,7 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) | |||
772 | switch (action) { | 375 | switch (action) { |
773 | case CPU_UP_CANCELED_FROZEN: | 376 | case CPU_UP_CANCELED_FROZEN: |
774 | /* The CPU refused to come up during a system resume */ | 377 | /* The CPU refused to come up during a system resume */ |
775 | microcode_fini_cpu(cpu); | 378 | microcode_ops->microcode_fini_cpu(cpu); |
776 | break; | 379 | break; |
777 | case CPU_ONLINE: | 380 | case CPU_ONLINE: |
778 | case CPU_DOWN_FAILED: | 381 | case CPU_DOWN_FAILED: |
@@ -780,9 +383,9 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) | |||
780 | break; | 383 | break; |
781 | case CPU_ONLINE_FROZEN: | 384 | case CPU_ONLINE_FROZEN: |
782 | /* System-wide resume is in progress, try to apply microcode */ | 385 | /* System-wide resume is in progress, try to apply microcode */ |
783 | if (apply_microcode_check_cpu(cpu)) { | 386 | if (microcode_ops->apply_microcode_check_cpu(cpu)) { |
784 | /* The application of microcode failed */ | 387 | /* The application of microcode failed */ |
785 | microcode_fini_cpu(cpu); | 388 | microcode_ops->microcode_fini_cpu(cpu); |
786 | __mc_sysdev_add(sys_dev, 1); | 389 | __mc_sysdev_add(sys_dev, 1); |
787 | break; | 390 | break; |
788 | } | 391 | } |
@@ -806,12 +409,17 @@ static struct notifier_block __refdata mc_cpu_notifier = { | |||
806 | .notifier_call = mc_cpu_callback, | 409 | .notifier_call = mc_cpu_callback, |
807 | }; | 410 | }; |
808 | 411 | ||
809 | static int __init microcode_init (void) | 412 | int microcode_init(void *opaque, struct module *module) |
810 | { | 413 | { |
414 | struct microcode_ops *ops = (struct microcode_ops *)opaque; | ||
811 | int error; | 415 | int error; |
812 | 416 | ||
813 | printk(KERN_INFO | 417 | if (microcode_ops) { |
814 | "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@aivazian.fsnet.co.uk>\n"); | 418 | printk(KERN_ERR "microcode: already loaded the other module\n"); |
419 | return -EEXIST; | ||
420 | } | ||
421 | |||
422 | microcode_ops = ops; | ||
815 | 423 | ||
816 | error = microcode_dev_init(); | 424 | error = microcode_dev_init(); |
817 | if (error) | 425 | if (error) |
@@ -833,10 +441,17 @@ static int __init microcode_init (void) | |||
833 | } | 441 | } |
834 | 442 | ||
835 | register_hotcpu_notifier(&mc_cpu_notifier); | 443 | register_hotcpu_notifier(&mc_cpu_notifier); |
444 | |||
445 | printk(KERN_INFO | ||
446 | "Microcode Update Driver: v" MICROCODE_VERSION | ||
447 | " <tigran@aivazian.fsnet.co.uk>" | ||
448 | " <peter.oruba@amd.com>\n"); | ||
449 | |||
836 | return 0; | 450 | return 0; |
837 | } | 451 | } |
452 | EXPORT_SYMBOL_GPL(microcode_init); | ||
838 | 453 | ||
839 | static void __exit microcode_exit (void) | 454 | void __exit microcode_exit (void) |
840 | { | 455 | { |
841 | microcode_dev_exit(); | 456 | microcode_dev_exit(); |
842 | 457 | ||
@@ -847,7 +462,10 @@ static void __exit microcode_exit (void) | |||
847 | put_online_cpus(); | 462 | put_online_cpus(); |
848 | 463 | ||
849 | platform_device_unregister(microcode_pdev); | 464 | platform_device_unregister(microcode_pdev); |
850 | } | ||
851 | 465 | ||
852 | module_init(microcode_init) | 466 | microcode_ops = NULL; |
853 | module_exit(microcode_exit) | 467 | |
468 | printk(KERN_INFO | ||
469 | "Microcode Update Driver: v" MICROCODE_VERSION " removed.\n"); | ||
470 | } | ||
471 | EXPORT_SYMBOL_GPL(microcode_exit); | ||
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c new file mode 100644 index 000000000000..07e52beacb44 --- /dev/null +++ b/arch/x86/kernel/microcode_amd.c | |||
@@ -0,0 +1,520 @@ | |||
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 0x11 processors. | ||
12 | * | ||
13 | * Licensed unter the terms of the GNU General Public | ||
14 | * License version 2. See file COPYING for details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/capability.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/sched.h> | ||
21 | #include <linux/cpumask.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/vmalloc.h> | ||
25 | #include <linux/miscdevice.h> | ||
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/mm.h> | ||
28 | #include <linux/fs.h> | ||
29 | #include <linux/mutex.h> | ||
30 | #include <linux/cpu.h> | ||
31 | #include <linux/firmware.h> | ||
32 | #include <linux/platform_device.h> | ||
33 | #include <linux/pci.h> | ||
34 | #include <linux/pci_ids.h> | ||
35 | |||
36 | #include <asm/msr.h> | ||
37 | #include <asm/uaccess.h> | ||
38 | #include <asm/processor.h> | ||
39 | #include <asm/microcode.h> | ||
40 | |||
41 | MODULE_DESCRIPTION("AMD Microcode Update Driver"); | ||
42 | MODULE_AUTHOR("Peter Oruba <peter.oruba@amd.com>"); | ||
43 | MODULE_LICENSE("GPL v2"); | ||
44 | |||
45 | #define UCODE_MAGIC 0x00414d44 | ||
46 | #define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000 | ||
47 | #define UCODE_UCODE_TYPE 0x00000001 | ||
48 | |||
49 | #define UCODE_MAX_SIZE (2048) | ||
50 | #define DEFAULT_UCODE_DATASIZE (896) /* 896 bytes */ | ||
51 | #define MC_HEADER_SIZE (sizeof(struct microcode_header_amd)) /* 64 bytes */ | ||
52 | #define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) /* 960 bytes */ | ||
53 | #define DWSIZE (sizeof(u32)) | ||
54 | /* For now we support a fixed ucode total size only */ | ||
55 | #define get_totalsize(mc) \ | ||
56 | ((((struct microcode_amd *)mc)->hdr.mc_patch_data_len * 28) \ | ||
57 | + MC_HEADER_SIZE) | ||
58 | |||
59 | extern int microcode_init(void *opaque, struct module *module); | ||
60 | extern void microcode_exit(void); | ||
61 | |||
62 | /* serialize access to the physical write */ | ||
63 | static DEFINE_SPINLOCK(microcode_update_lock); | ||
64 | |||
65 | /* no concurrent ->write()s are allowed on /dev/cpu/microcode */ | ||
66 | extern struct mutex (microcode_mutex); | ||
67 | |||
68 | struct equiv_cpu_entry *equiv_cpu_table; | ||
69 | |||
70 | extern struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; | ||
71 | |||
72 | static void collect_cpu_info_amd(int cpu) | ||
73 | { | ||
74 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
75 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
76 | |||
77 | /* We should bind the task to the CPU */ | ||
78 | BUG_ON(raw_smp_processor_id() != cpu); | ||
79 | uci->rev = 0; | ||
80 | uci->pf = 0; | ||
81 | uci->mc.mc_amd = NULL; | ||
82 | uci->valid = 1; | ||
83 | |||
84 | if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) { | ||
85 | printk(KERN_ERR "microcode: CPU%d not a capable AMD processor\n", | ||
86 | cpu); | ||
87 | uci->valid = 0; | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | asm volatile("movl %1, %%ecx; rdmsr" | ||
92 | : "=a" (uci->rev) | ||
93 | : "i" (0x0000008B) : "ecx"); | ||
94 | |||
95 | printk(KERN_INFO "microcode: collect_cpu_info_amd : patch_id=0x%x\n", | ||
96 | uci->rev); | ||
97 | } | ||
98 | |||
99 | static int get_matching_microcode_amd(void *mc, int cpu) | ||
100 | { | ||
101 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
102 | struct microcode_header_amd *mc_header = mc; | ||
103 | unsigned long total_size = get_totalsize(mc_header); | ||
104 | void *new_mc; | ||
105 | struct pci_dev *nb_pci_dev, *sb_pci_dev; | ||
106 | unsigned int current_cpu_id; | ||
107 | unsigned int equiv_cpu_id = 0x00; | ||
108 | unsigned int i = 0; | ||
109 | |||
110 | /* We should bind the task to the CPU */ | ||
111 | BUG_ON(cpu != raw_smp_processor_id()); | ||
112 | |||
113 | /* This is a tricky part. We might be called from a write operation */ | ||
114 | /* to the device file instead of the usual process of firmware */ | ||
115 | /* loading. This routine needs to be able to distinguish both */ | ||
116 | /* cases. This is done by checking if there alread is a equivalent */ | ||
117 | /* CPU table installed. If not, we're written through */ | ||
118 | /* /dev/cpu/microcode. */ | ||
119 | /* Since we ignore all checks. The error case in which going through */ | ||
120 | /* firmware loading and that table is not loaded has already been */ | ||
121 | /* checked earlier. */ | ||
122 | if (equiv_cpu_table == NULL) { | ||
123 | printk(KERN_INFO "microcode: CPU%d microcode update with " | ||
124 | "version 0x%x (current=0x%x)\n", | ||
125 | cpu, mc_header->patch_id, uci->rev); | ||
126 | goto out; | ||
127 | } | ||
128 | |||
129 | current_cpu_id = cpuid_eax(0x00000001); | ||
130 | |||
131 | while (equiv_cpu_table[i].installed_cpu != 0) { | ||
132 | if (current_cpu_id == equiv_cpu_table[i].installed_cpu) { | ||
133 | equiv_cpu_id = equiv_cpu_table[i].equiv_cpu; | ||
134 | break; | ||
135 | } | ||
136 | i++; | ||
137 | } | ||
138 | |||
139 | if (!equiv_cpu_id) { | ||
140 | printk(KERN_ERR "microcode: CPU%d cpu_id " | ||
141 | "not found in equivalent cpu table \n", cpu); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | if ((mc_header->processor_rev_id[0]) != (equiv_cpu_id & 0xff)) { | ||
146 | printk(KERN_ERR | ||
147 | "microcode: CPU%d patch does not match " | ||
148 | "(patch is %x, cpu extended is %x) \n", | ||
149 | cpu, mc_header->processor_rev_id[0], | ||
150 | (equiv_cpu_id & 0xff)); | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | if ((mc_header->processor_rev_id[1]) != ((equiv_cpu_id >> 16) & 0xff)) { | ||
155 | printk(KERN_ERR "microcode: CPU%d patch does not match " | ||
156 | "(patch is %x, cpu base id is %x) \n", | ||
157 | cpu, mc_header->processor_rev_id[1], | ||
158 | ((equiv_cpu_id >> 16) & 0xff)); | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | /* ucode may be northbridge specific */ | ||
164 | if (mc_header->nb_dev_id) { | ||
165 | nb_pci_dev = pci_get_device(PCI_VENDOR_ID_AMD, | ||
166 | (mc_header->nb_dev_id & 0xff), | ||
167 | NULL); | ||
168 | if ((!nb_pci_dev) || | ||
169 | (mc_header->nb_rev_id != nb_pci_dev->revision)) { | ||
170 | printk(KERN_ERR "microcode: CPU%d NB mismatch \n", cpu); | ||
171 | pci_dev_put(nb_pci_dev); | ||
172 | return 0; | ||
173 | } | ||
174 | pci_dev_put(nb_pci_dev); | ||
175 | } | ||
176 | |||
177 | /* ucode may be southbridge specific */ | ||
178 | if (mc_header->sb_dev_id) { | ||
179 | sb_pci_dev = pci_get_device(PCI_VENDOR_ID_AMD, | ||
180 | (mc_header->sb_dev_id & 0xff), | ||
181 | NULL); | ||
182 | if ((!sb_pci_dev) || | ||
183 | (mc_header->sb_rev_id != sb_pci_dev->revision)) { | ||
184 | printk(KERN_ERR "microcode: CPU%d SB mismatch \n", cpu); | ||
185 | pci_dev_put(sb_pci_dev); | ||
186 | return 0; | ||
187 | } | ||
188 | pci_dev_put(sb_pci_dev); | ||
189 | } | ||
190 | |||
191 | if (mc_header->patch_id <= uci->rev) | ||
192 | return 0; | ||
193 | |||
194 | printk(KERN_INFO "microcode: CPU%d found a matching microcode " | ||
195 | "update with version 0x%x (current=0x%x)\n", | ||
196 | cpu, mc_header->patch_id, uci->rev); | ||
197 | |||
198 | out: | ||
199 | new_mc = vmalloc(UCODE_MAX_SIZE); | ||
200 | if (!new_mc) { | ||
201 | printk(KERN_ERR "microcode: error, can't allocate memory\n"); | ||
202 | return -ENOMEM; | ||
203 | } | ||
204 | memset(new_mc, 0, UCODE_MAX_SIZE); | ||
205 | |||
206 | /* free previous update file */ | ||
207 | vfree(uci->mc.mc_amd); | ||
208 | |||
209 | memcpy(new_mc, mc, total_size); | ||
210 | |||
211 | uci->mc.mc_amd = new_mc; | ||
212 | return 1; | ||
213 | } | ||
214 | |||
215 | static void apply_microcode_amd(int cpu) | ||
216 | { | ||
217 | unsigned long flags; | ||
218 | unsigned int eax, edx; | ||
219 | unsigned int rev; | ||
220 | int cpu_num = raw_smp_processor_id(); | ||
221 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; | ||
222 | |||
223 | /* We should bind the task to the CPU */ | ||
224 | BUG_ON(cpu_num != cpu); | ||
225 | |||
226 | if (uci->mc.mc_amd == NULL) | ||
227 | return; | ||
228 | |||
229 | spin_lock_irqsave(µcode_update_lock, flags); | ||
230 | |||
231 | edx = (unsigned int)(((unsigned long) | ||
232 | &(uci->mc.mc_amd->hdr.data_code)) >> 32); | ||
233 | eax = (unsigned int)(((unsigned long) | ||
234 | &(uci->mc.mc_amd->hdr.data_code)) & 0xffffffffL); | ||
235 | |||
236 | asm volatile("movl %0, %%ecx; wrmsr" : | ||
237 | : "i" (0xc0010020), "a" (eax), "d" (edx) : "ecx"); | ||
238 | |||
239 | /* get patch id after patching */ | ||
240 | asm volatile("movl %1, %%ecx; rdmsr" | ||
241 | : "=a" (rev) | ||
242 | : "i" (0x0000008B) : "ecx"); | ||
243 | |||
244 | spin_unlock_irqrestore(µcode_update_lock, flags); | ||
245 | |||
246 | /* check current patch id and patch's id for match */ | ||
247 | if (rev != uci->mc.mc_amd->hdr.patch_id) { | ||
248 | printk(KERN_ERR "microcode: CPU%d update from revision " | ||
249 | "0x%x to 0x%x failed\n", cpu_num, | ||
250 | uci->mc.mc_amd->hdr.patch_id, rev); | ||
251 | return; | ||
252 | } | ||
253 | |||
254 | printk(KERN_INFO "microcode: CPU%d updated from revision " | ||
255 | "0x%x to 0x%x \n", | ||
256 | cpu_num, uci->rev, uci->mc.mc_amd->hdr.patch_id); | ||
257 | |||
258 | uci->rev = rev; | ||
259 | } | ||
260 | |||
261 | #ifdef CONFIG_MICROCODE_OLD_INTERFACE | ||
262 | extern void __user *user_buffer; /* user area microcode data buffer */ | ||
263 | extern unsigned int user_buffer_size; /* it's size */ | ||
264 | |||
265 | static long get_next_ucode_amd(void **mc, long offset) | ||
266 | { | ||
267 | struct microcode_header_amd mc_header; | ||
268 | unsigned long total_size; | ||
269 | |||
270 | /* No more data */ | ||
271 | if (offset >= user_buffer_size) | ||
272 | return 0; | ||
273 | if (copy_from_user(&mc_header, user_buffer + offset, MC_HEADER_SIZE)) { | ||
274 | printk(KERN_ERR "microcode: error! Can not read user data\n"); | ||
275 | return -EFAULT; | ||
276 | } | ||
277 | total_size = get_totalsize(&mc_header); | ||
278 | if (offset + total_size > user_buffer_size) { | ||
279 | printk(KERN_ERR "microcode: error! Bad total size in microcode " | ||
280 | "data file\n"); | ||
281 | return -EINVAL; | ||
282 | } | ||
283 | *mc = vmalloc(UCODE_MAX_SIZE); | ||
284 | if (!*mc) | ||
285 | return -ENOMEM; | ||
286 | memset(*mc, 0, UCODE_MAX_SIZE); | ||
287 | |||
288 | if (copy_from_user(*mc, user_buffer + offset, total_size)) { | ||
289 | printk(KERN_ERR "microcode: error! Can not read user data\n"); | ||
290 | vfree(*mc); | ||
291 | return -EFAULT; | ||
292 | } | ||
293 | return offset + total_size; | ||
294 | } | ||
295 | #else | ||
296 | #define get_next_ucode_amd() NULL | ||
297 | #endif | ||
298 | |||
299 | static long get_next_ucode_from_buffer_amd(void **mc, void *buf, | ||
300 | unsigned long size, long offset) | ||
301 | { | ||
302 | struct microcode_header_amd *mc_header; | ||
303 | unsigned long total_size; | ||
304 | unsigned char *buf_pos = buf; | ||
305 | |||
306 | /* No more data */ | ||
307 | if (offset >= size) | ||
308 | return 0; | ||
309 | |||
310 | if (buf_pos[offset] != UCODE_UCODE_TYPE) { | ||
311 | printk(KERN_ERR "microcode: error! " | ||
312 | "Wrong microcode payload type field\n"); | ||
313 | return -EINVAL; | ||
314 | } | ||
315 | |||
316 | mc_header = (struct microcode_header_amd *)(&buf_pos[offset+8]); | ||
317 | |||
318 | total_size = (unsigned long) (buf_pos[offset+4] + | ||
319 | (buf_pos[offset+5] << 8)); | ||
320 | |||
321 | printk(KERN_INFO "microcode: size %lu, total_size %lu, offset %ld\n", | ||
322 | size, total_size, offset); | ||
323 | |||
324 | if (offset + total_size > size) { | ||
325 | printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); | ||
326 | return -EINVAL; | ||
327 | } | ||
328 | |||
329 | *mc = vmalloc(UCODE_MAX_SIZE); | ||
330 | if (!*mc) { | ||
331 | printk(KERN_ERR "microcode: error! " | ||
332 | "Can not allocate memory for microcode patch\n"); | ||
333 | return -ENOMEM; | ||
334 | } | ||
335 | |||
336 | memset(*mc, 0, UCODE_MAX_SIZE); | ||
337 | memcpy(*mc, buf + offset + 8, total_size); | ||
338 | |||
339 | return offset + total_size + 8; | ||
340 | } | ||
341 | |||
342 | static long install_equiv_cpu_table(void *buf, unsigned long size, long offset) | ||
343 | { | ||
344 | unsigned int *buf_pos = buf; | ||
345 | |||
346 | /* No more data */ | ||
347 | if (offset >= size) | ||
348 | return 0; | ||
349 | |||
350 | if (buf_pos[1] != UCODE_EQUIV_CPU_TABLE_TYPE) { | ||
351 | printk(KERN_ERR "microcode: error! " | ||
352 | "Wrong microcode equivalnet cpu table type field\n"); | ||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | if (size == 0) { | ||
357 | printk(KERN_ERR "microcode: error! " | ||
358 | "Wrong microcode equivalnet cpu table length\n"); | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | equiv_cpu_table = (struct equiv_cpu_entry *) vmalloc(size); | ||
363 | if (!equiv_cpu_table) { | ||
364 | printk(KERN_ERR "microcode: error, can't allocate memory for equiv CPU table\n"); | ||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | memset(equiv_cpu_table, 0, size); | ||
369 | memcpy(equiv_cpu_table, &buf_pos[3], size); | ||
370 | |||
371 | return size + 12; /* add header length */ | ||
372 | } | ||
373 | |||
374 | /* fake device for request_firmware */ | ||
375 | extern struct platform_device *microcode_pdev; | ||
376 | |||
377 | static int cpu_request_microcode_amd(int cpu) | ||
378 | { | ||
379 | char name[30]; | ||
380 | const struct firmware *firmware; | ||
381 | void *buf; | ||
382 | unsigned int *buf_pos; | ||
383 | unsigned long size; | ||
384 | long offset = 0; | ||
385 | int error; | ||
386 | void *mc; | ||
387 | |||
388 | /* We should bind the task to the CPU */ | ||
389 | BUG_ON(cpu != raw_smp_processor_id()); | ||
390 | |||
391 | sprintf(name, "amd-ucode/microcode_amd.bin"); | ||
392 | error = request_firmware(&firmware, "amd-ucode/microcode_amd.bin", | ||
393 | µcode_pdev->dev); | ||
394 | if (error) { | ||
395 | printk(KERN_ERR "microcode: ucode data file %s load failed\n", | ||
396 | name); | ||
397 | return error; | ||
398 | } | ||
399 | |||
400 | buf_pos = buf = firmware->data; | ||
401 | size = firmware->size; | ||
402 | |||
403 | if (buf_pos[0] != UCODE_MAGIC) { | ||
404 | printk(KERN_ERR "microcode: error! Wrong microcode patch file magic\n"); | ||
405 | return -EINVAL; | ||
406 | } | ||
407 | |||
408 | offset = install_equiv_cpu_table(buf, buf_pos[2], offset); | ||
409 | |||
410 | if (!offset) { | ||
411 | printk(KERN_ERR "microcode: installing equivalent cpu table failed\n"); | ||
412 | return -EINVAL; | ||
413 | } | ||
414 | |||
415 | while ((offset = | ||
416 | get_next_ucode_from_buffer_amd(&mc, buf, size, offset)) > 0) { | ||
417 | error = get_matching_microcode_amd(mc, cpu); | ||
418 | if (error < 0) | ||
419 | break; | ||
420 | /* | ||
421 | * It's possible the data file has multiple matching ucode, | ||
422 | * lets keep searching till the latest version | ||
423 | */ | ||
424 | if (error == 1) { | ||
425 | apply_microcode_amd(cpu); | ||
426 | error = 0; | ||
427 | } | ||
428 | vfree(mc); | ||
429 | } | ||
430 | if (offset > 0) { | ||
431 | vfree(mc); | ||
432 | vfree(equiv_cpu_table); | ||
433 | equiv_cpu_table = NULL; | ||
434 | } | ||
435 | if (offset < 0) | ||
436 | error = offset; | ||
437 | release_firmware(firmware); | ||
438 | |||
439 | return error; | ||
440 | } | ||
441 | |||
442 | static int apply_microcode_check_cpu_amd(int cpu) | ||
443 | { | ||
444 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
445 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
446 | unsigned int rev; | ||
447 | cpumask_t old; | ||
448 | int err = 0; | ||
449 | |||
450 | /* Check if the microcode is available */ | ||
451 | if (!uci->mc.mc_amd) | ||
452 | return 0; | ||
453 | |||
454 | old = current->cpus_allowed; | ||
455 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | ||
456 | |||
457 | /* Check if the microcode we have in memory matches the CPU */ | ||
458 | if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 16) | ||
459 | err = -EINVAL; | ||
460 | |||
461 | if (!err) { | ||
462 | asm volatile("movl %1, %%ecx; rdmsr" | ||
463 | : "=a" (rev) | ||
464 | : "i" (0x0000008B) : "ecx"); | ||
465 | |||
466 | if (uci->rev != rev) | ||
467 | err = -EINVAL; | ||
468 | } | ||
469 | |||
470 | if (!err) | ||
471 | apply_microcode_amd(cpu); | ||
472 | else | ||
473 | printk(KERN_ERR "microcode: Could not apply microcode to CPU%d:" | ||
474 | " rev=0x%x\n", | ||
475 | cpu, uci->rev); | ||
476 | |||
477 | set_cpus_allowed(current, old); | ||
478 | return err; | ||
479 | } | ||
480 | |||
481 | static void microcode_fini_cpu_amd(int cpu) | ||
482 | { | ||
483 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
484 | |||
485 | mutex_lock(µcode_mutex); | ||
486 | uci->valid = 0; | ||
487 | vfree(uci->mc.mc_amd); | ||
488 | uci->mc.mc_amd = NULL; | ||
489 | mutex_unlock(µcode_mutex); | ||
490 | } | ||
491 | |||
492 | static struct microcode_ops microcode_amd_ops = { | ||
493 | .get_next_ucode = get_next_ucode_amd, | ||
494 | .get_matching_microcode = get_matching_microcode_amd, | ||
495 | .microcode_sanity_check = NULL, | ||
496 | .apply_microcode_check_cpu = apply_microcode_check_cpu_amd, | ||
497 | .cpu_request_microcode = cpu_request_microcode_amd, | ||
498 | .collect_cpu_info = collect_cpu_info_amd, | ||
499 | .apply_microcode = apply_microcode_amd, | ||
500 | .microcode_fini_cpu = microcode_fini_cpu_amd, | ||
501 | }; | ||
502 | |||
503 | static int __init microcode_amd_module_init(void) | ||
504 | { | ||
505 | struct cpuinfo_x86 *c = &cpu_data(get_cpu()); | ||
506 | |||
507 | equiv_cpu_table = NULL; | ||
508 | if (c->x86_vendor == X86_VENDOR_AMD) | ||
509 | return microcode_init(µcode_amd_ops, THIS_MODULE); | ||
510 | else | ||
511 | return -ENODEV; | ||
512 | } | ||
513 | |||
514 | static void __exit microcode_amd_module_exit(void) | ||
515 | { | ||
516 | microcode_exit(); | ||
517 | } | ||
518 | |||
519 | module_init(microcode_amd_module_init) | ||
520 | module_exit(microcode_amd_module_exit) | ||
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c new file mode 100644 index 000000000000..6da4a85ff465 --- /dev/null +++ b/arch/x86/kernel/microcode_intel.c | |||
@@ -0,0 +1,545 @@ | |||
1 | /* | ||
2 | * Intel CPU Microcode Update Driver for Linux | ||
3 | * | ||
4 | * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk> | ||
5 | * 2006 Shaohua Li <shaohua.li@intel.com> | ||
6 | * | ||
7 | * This driver allows to upgrade microcode on Intel processors | ||
8 | * belonging to IA-32 family - PentiumPro, Pentium II, | ||
9 | * Pentium III, Xeon, Pentium 4, etc. | ||
10 | * | ||
11 | * Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture | ||
12 | * Software Developer's Manual | ||
13 | * Order Number 253668 or free download from: | ||
14 | * | ||
15 | * http://developer.intel.com/design/pentium4/manuals/253668.htm | ||
16 | * | ||
17 | * For more information, go to http://www.urbanmyth.org/microcode | ||
18 | * | ||
19 | * This program is free software; you can redistribute it and/or | ||
20 | * modify it under the terms of the GNU General Public License | ||
21 | * as published by the Free Software Foundation; either version | ||
22 | * 2 of the License, or (at your option) any later version. | ||
23 | * | ||
24 | * 1.0 16 Feb 2000, Tigran Aivazian <tigran@sco.com> | ||
25 | * Initial release. | ||
26 | * 1.01 18 Feb 2000, Tigran Aivazian <tigran@sco.com> | ||
27 | * Added read() support + cleanups. | ||
28 | * 1.02 21 Feb 2000, Tigran Aivazian <tigran@sco.com> | ||
29 | * Added 'device trimming' support. open(O_WRONLY) zeroes | ||
30 | * and frees the saved copy of applied microcode. | ||
31 | * 1.03 29 Feb 2000, Tigran Aivazian <tigran@sco.com> | ||
32 | * Made to use devfs (/dev/cpu/microcode) + cleanups. | ||
33 | * 1.04 06 Jun 2000, Simon Trimmer <simon@veritas.com> | ||
34 | * Added misc device support (now uses both devfs and misc). | ||
35 | * Added MICROCODE_IOCFREE ioctl to clear memory. | ||
36 | * 1.05 09 Jun 2000, Simon Trimmer <simon@veritas.com> | ||
37 | * Messages for error cases (non Intel & no suitable microcode). | ||
38 | * 1.06 03 Aug 2000, Tigran Aivazian <tigran@veritas.com> | ||
39 | * Removed ->release(). Removed exclusive open and status bitmap. | ||
40 | * Added microcode_rwsem to serialize read()/write()/ioctl(). | ||
41 | * Removed global kernel lock usage. | ||
42 | * 1.07 07 Sep 2000, Tigran Aivazian <tigran@veritas.com> | ||
43 | * Write 0 to 0x8B msr and then cpuid before reading revision, | ||
44 | * so that it works even if there were no update done by the | ||
45 | * BIOS. Otherwise, reading from 0x8B gives junk (which happened | ||
46 | * to be 0 on my machine which is why it worked even when I | ||
47 | * disabled update by the BIOS) | ||
48 | * Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix. | ||
49 | * 1.08 11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and | ||
50 | * Tigran Aivazian <tigran@veritas.com> | ||
51 | * Intel Pentium 4 processor support and bugfixes. | ||
52 | * 1.09 30 Oct 2001, Tigran Aivazian <tigran@veritas.com> | ||
53 | * Bugfix for HT (Hyper-Threading) enabled processors | ||
54 | * whereby processor resources are shared by all logical processors | ||
55 | * in a single CPU package. | ||
56 | * 1.10 28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and | ||
57 | * Tigran Aivazian <tigran@veritas.com>, | ||
58 | * Serialize updates as required on HT processors due to speculative | ||
59 | * nature of implementation. | ||
60 | * 1.11 22 Mar 2002 Tigran Aivazian <tigran@veritas.com> | ||
61 | * Fix the panic when writing zero-length microcode chunk. | ||
62 | * 1.12 29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>, | ||
63 | * Jun Nakajima <jun.nakajima@intel.com> | ||
64 | * Support for the microcode updates in the new format. | ||
65 | * 1.13 10 Oct 2003 Tigran Aivazian <tigran@veritas.com> | ||
66 | * Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl | ||
67 | * because we no longer hold a copy of applied microcode | ||
68 | * in kernel memory. | ||
69 | * 1.14 25 Jun 2004 Tigran Aivazian <tigran@veritas.com> | ||
70 | * Fix sigmatch() macro to handle old CPUs with pf == 0. | ||
71 | * Thanks to Stuart Swales for pointing out this bug. | ||
72 | */ | ||
73 | |||
74 | //#define DEBUG /* pr_debug */ | ||
75 | #include <linux/capability.h> | ||
76 | #include <linux/kernel.h> | ||
77 | #include <linux/init.h> | ||
78 | #include <linux/sched.h> | ||
79 | #include <linux/smp_lock.h> | ||
80 | #include <linux/cpumask.h> | ||
81 | #include <linux/module.h> | ||
82 | #include <linux/slab.h> | ||
83 | #include <linux/vmalloc.h> | ||
84 | #include <linux/miscdevice.h> | ||
85 | #include <linux/spinlock.h> | ||
86 | #include <linux/mm.h> | ||
87 | #include <linux/fs.h> | ||
88 | #include <linux/mutex.h> | ||
89 | #include <linux/cpu.h> | ||
90 | #include <linux/firmware.h> | ||
91 | #include <linux/platform_device.h> | ||
92 | |||
93 | #include <asm/msr.h> | ||
94 | #include <asm/uaccess.h> | ||
95 | #include <asm/processor.h> | ||
96 | #include <asm/microcode.h> | ||
97 | |||
98 | MODULE_DESCRIPTION("Microcode Update Driver"); | ||
99 | MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); | ||
100 | MODULE_LICENSE("GPL"); | ||
101 | |||
102 | #define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */ | ||
103 | #define MC_HEADER_SIZE (sizeof(struct microcode_header_intel)) /* 48 bytes */ | ||
104 | #define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) /* 2048 bytes */ | ||
105 | #define EXT_HEADER_SIZE (sizeof(struct extended_sigtable)) /* 20 bytes */ | ||
106 | #define EXT_SIGNATURE_SIZE (sizeof(struct extended_signature)) /* 12 bytes */ | ||
107 | #define DWSIZE (sizeof(u32)) | ||
108 | #define get_totalsize(mc) \ | ||
109 | (((struct microcode_intel *)mc)->hdr.totalsize ? \ | ||
110 | ((struct microcode_intel *)mc)->hdr.totalsize : \ | ||
111 | DEFAULT_UCODE_TOTALSIZE) | ||
112 | |||
113 | #define get_datasize(mc) \ | ||
114 | (((struct microcode_intel *)mc)->hdr.datasize ? \ | ||
115 | ((struct microcode_intel *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE) | ||
116 | |||
117 | #define sigmatch(s1, s2, p1, p2) \ | ||
118 | (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0)))) | ||
119 | |||
120 | #define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE) | ||
121 | |||
122 | /* serialize access to the physical write to MSR 0x79 */ | ||
123 | static DEFINE_SPINLOCK(microcode_update_lock); | ||
124 | |||
125 | /* no concurrent ->write()s are allowed on /dev/cpu/microcode */ | ||
126 | extern struct mutex microcode_mutex; | ||
127 | |||
128 | extern struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; | ||
129 | |||
130 | static void collect_cpu_info(int cpu_num) | ||
131 | { | ||
132 | struct cpuinfo_x86 *c = &cpu_data(cpu_num); | ||
133 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; | ||
134 | unsigned int val[2]; | ||
135 | |||
136 | /* We should bind the task to the CPU */ | ||
137 | BUG_ON(raw_smp_processor_id() != cpu_num); | ||
138 | uci->pf = uci->rev = 0; | ||
139 | uci->mc.mc_intel = NULL; | ||
140 | uci->valid = 1; | ||
141 | |||
142 | if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 || | ||
143 | cpu_has(c, X86_FEATURE_IA64)) { | ||
144 | printk(KERN_ERR "microcode: CPU%d not a capable Intel " | ||
145 | "processor\n", cpu_num); | ||
146 | uci->valid = 0; | ||
147 | return; | ||
148 | } | ||
149 | |||
150 | uci->sig = cpuid_eax(0x00000001); | ||
151 | |||
152 | if ((c->x86_model >= 5) || (c->x86 > 6)) { | ||
153 | /* get processor flags from MSR 0x17 */ | ||
154 | rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); | ||
155 | uci->pf = 1 << ((val[1] >> 18) & 7); | ||
156 | } | ||
157 | |||
158 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); | ||
159 | /* see notes above for revision 1.07. Apparent chip bug */ | ||
160 | sync_core(); | ||
161 | /* get the current revision from MSR 0x8B */ | ||
162 | rdmsr(MSR_IA32_UCODE_REV, val[0], uci->rev); | ||
163 | pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n", | ||
164 | uci->sig, uci->pf, uci->rev); | ||
165 | } | ||
166 | |||
167 | static inline int microcode_update_match(int cpu_num, | ||
168 | struct microcode_header_intel *mc_header, int sig, int pf) | ||
169 | { | ||
170 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; | ||
171 | |||
172 | if (!sigmatch(sig, uci->sig, pf, uci->pf) | ||
173 | || mc_header->rev <= uci->rev) | ||
174 | return 0; | ||
175 | return 1; | ||
176 | } | ||
177 | |||
178 | static int microcode_sanity_check(void *mc) | ||
179 | { | ||
180 | struct microcode_header_intel *mc_header = mc; | ||
181 | struct extended_sigtable *ext_header = NULL; | ||
182 | struct extended_signature *ext_sig; | ||
183 | unsigned long total_size, data_size, ext_table_size; | ||
184 | int sum, orig_sum, ext_sigcount = 0, i; | ||
185 | |||
186 | total_size = get_totalsize(mc_header); | ||
187 | data_size = get_datasize(mc_header); | ||
188 | if (data_size + MC_HEADER_SIZE > total_size) { | ||
189 | printk(KERN_ERR "microcode: error! " | ||
190 | "Bad data size in microcode data file\n"); | ||
191 | return -EINVAL; | ||
192 | } | ||
193 | |||
194 | if (mc_header->ldrver != 1 || mc_header->hdrver != 1) { | ||
195 | printk(KERN_ERR "microcode: error! " | ||
196 | "Unknown microcode update format\n"); | ||
197 | return -EINVAL; | ||
198 | } | ||
199 | ext_table_size = total_size - (MC_HEADER_SIZE + data_size); | ||
200 | if (ext_table_size) { | ||
201 | if ((ext_table_size < EXT_HEADER_SIZE) | ||
202 | || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) { | ||
203 | printk(KERN_ERR "microcode: error! " | ||
204 | "Small exttable size in microcode data file\n"); | ||
205 | return -EINVAL; | ||
206 | } | ||
207 | ext_header = mc + MC_HEADER_SIZE + data_size; | ||
208 | if (ext_table_size != exttable_size(ext_header)) { | ||
209 | printk(KERN_ERR "microcode: error! " | ||
210 | "Bad exttable size in microcode data file\n"); | ||
211 | return -EFAULT; | ||
212 | } | ||
213 | ext_sigcount = ext_header->count; | ||
214 | } | ||
215 | |||
216 | /* check extended table checksum */ | ||
217 | if (ext_table_size) { | ||
218 | int ext_table_sum = 0; | ||
219 | int *ext_tablep = (int *)ext_header; | ||
220 | |||
221 | i = ext_table_size / DWSIZE; | ||
222 | while (i--) | ||
223 | ext_table_sum += ext_tablep[i]; | ||
224 | if (ext_table_sum) { | ||
225 | printk(KERN_WARNING "microcode: aborting, " | ||
226 | "bad extended signature table checksum\n"); | ||
227 | return -EINVAL; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | /* calculate the checksum */ | ||
232 | orig_sum = 0; | ||
233 | i = (MC_HEADER_SIZE + data_size) / DWSIZE; | ||
234 | while (i--) | ||
235 | orig_sum += ((int *)mc)[i]; | ||
236 | if (orig_sum) { | ||
237 | printk(KERN_ERR "microcode: aborting, bad checksum\n"); | ||
238 | return -EINVAL; | ||
239 | } | ||
240 | if (!ext_table_size) | ||
241 | return 0; | ||
242 | /* check extended signature checksum */ | ||
243 | for (i = 0; i < ext_sigcount; i++) { | ||
244 | ext_sig = (void *)ext_header + EXT_HEADER_SIZE + | ||
245 | EXT_SIGNATURE_SIZE * i; | ||
246 | sum = orig_sum | ||
247 | - (mc_header->sig + mc_header->pf + mc_header->cksum) | ||
248 | + (ext_sig->sig + ext_sig->pf + ext_sig->cksum); | ||
249 | if (sum) { | ||
250 | printk(KERN_ERR "microcode: aborting, bad checksum\n"); | ||
251 | return -EINVAL; | ||
252 | } | ||
253 | } | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * return 0 - no update found | ||
259 | * return 1 - found update | ||
260 | * return < 0 - error | ||
261 | */ | ||
262 | static int get_matching_microcode(void *mc, int cpu) | ||
263 | { | ||
264 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
265 | struct microcode_header_intel *mc_header = mc; | ||
266 | struct extended_sigtable *ext_header; | ||
267 | unsigned long total_size = get_totalsize(mc_header); | ||
268 | int ext_sigcount, i; | ||
269 | struct extended_signature *ext_sig; | ||
270 | void *new_mc; | ||
271 | |||
272 | if (microcode_update_match(cpu, mc_header, | ||
273 | mc_header->sig, mc_header->pf)) | ||
274 | goto find; | ||
275 | |||
276 | if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE) | ||
277 | return 0; | ||
278 | |||
279 | ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE; | ||
280 | ext_sigcount = ext_header->count; | ||
281 | ext_sig = (void *)ext_header + EXT_HEADER_SIZE; | ||
282 | for (i = 0; i < ext_sigcount; i++) { | ||
283 | if (microcode_update_match(cpu, mc_header, | ||
284 | ext_sig->sig, ext_sig->pf)) | ||
285 | goto find; | ||
286 | ext_sig++; | ||
287 | } | ||
288 | return 0; | ||
289 | find: | ||
290 | pr_debug("microcode: CPU%d found a matching microcode update with" | ||
291 | " version 0x%x (current=0x%x)\n", | ||
292 | cpu, mc_header->rev, uci->rev); | ||
293 | new_mc = vmalloc(total_size); | ||
294 | if (!new_mc) { | ||
295 | printk(KERN_ERR "microcode: error! Can not allocate memory\n"); | ||
296 | return -ENOMEM; | ||
297 | } | ||
298 | |||
299 | /* free previous update file */ | ||
300 | vfree(uci->mc.mc_intel); | ||
301 | |||
302 | memcpy(new_mc, mc, total_size); | ||
303 | uci->mc.mc_intel = new_mc; | ||
304 | return 1; | ||
305 | } | ||
306 | |||
307 | static void apply_microcode(int cpu) | ||
308 | { | ||
309 | unsigned long flags; | ||
310 | unsigned int val[2]; | ||
311 | int cpu_num = raw_smp_processor_id(); | ||
312 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; | ||
313 | |||
314 | /* We should bind the task to the CPU */ | ||
315 | BUG_ON(cpu_num != cpu); | ||
316 | |||
317 | if (uci->mc.mc_intel == NULL) | ||
318 | return; | ||
319 | |||
320 | /* serialize access to the physical write to MSR 0x79 */ | ||
321 | spin_lock_irqsave(µcode_update_lock, flags); | ||
322 | |||
323 | /* write microcode via MSR 0x79 */ | ||
324 | wrmsr(MSR_IA32_UCODE_WRITE, | ||
325 | (unsigned long) uci->mc.mc_intel->bits, | ||
326 | (unsigned long) uci->mc.mc_intel->bits >> 16 >> 16); | ||
327 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); | ||
328 | |||
329 | /* see notes above for revision 1.07. Apparent chip bug */ | ||
330 | sync_core(); | ||
331 | |||
332 | /* get the current revision from MSR 0x8B */ | ||
333 | rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); | ||
334 | |||
335 | spin_unlock_irqrestore(µcode_update_lock, flags); | ||
336 | if (val[1] != uci->mc.mc_intel->hdr.rev) { | ||
337 | printk(KERN_ERR "microcode: CPU%d update from revision " | ||
338 | "0x%x to 0x%x failed\n", cpu_num, uci->rev, val[1]); | ||
339 | return; | ||
340 | } | ||
341 | printk(KERN_INFO "microcode: CPU%d updated from revision " | ||
342 | "0x%x to 0x%x, date = %08x \n", | ||
343 | cpu_num, uci->rev, val[1], uci->mc.mc_intel->hdr.date); | ||
344 | uci->rev = val[1]; | ||
345 | } | ||
346 | |||
347 | #ifdef CONFIG_MICROCODE_OLD_INTERFACE | ||
348 | extern void __user *user_buffer; /* user area microcode data buffer */ | ||
349 | extern unsigned int user_buffer_size; /* it's size */ | ||
350 | |||
351 | static long get_next_ucode(void **mc, long offset) | ||
352 | { | ||
353 | struct microcode_header_intel mc_header; | ||
354 | unsigned long total_size; | ||
355 | |||
356 | /* No more data */ | ||
357 | if (offset >= user_buffer_size) | ||
358 | return 0; | ||
359 | if (copy_from_user(&mc_header, user_buffer + offset, MC_HEADER_SIZE)) { | ||
360 | printk(KERN_ERR "microcode: error! Can not read user data\n"); | ||
361 | return -EFAULT; | ||
362 | } | ||
363 | total_size = get_totalsize(&mc_header); | ||
364 | if (offset + total_size > user_buffer_size) { | ||
365 | printk(KERN_ERR "microcode: error! Bad total size in microcode " | ||
366 | "data file\n"); | ||
367 | return -EINVAL; | ||
368 | } | ||
369 | *mc = vmalloc(total_size); | ||
370 | if (!*mc) | ||
371 | return -ENOMEM; | ||
372 | if (copy_from_user(*mc, user_buffer + offset, total_size)) { | ||
373 | printk(KERN_ERR "microcode: error! Can not read user data\n"); | ||
374 | vfree(*mc); | ||
375 | return -EFAULT; | ||
376 | } | ||
377 | return offset + total_size; | ||
378 | } | ||
379 | #endif | ||
380 | |||
381 | static long get_next_ucode_from_buffer(void **mc, const u8 *buf, | ||
382 | unsigned long size, long offset) | ||
383 | { | ||
384 | struct microcode_header_intel *mc_header; | ||
385 | unsigned long total_size; | ||
386 | |||
387 | /* No more data */ | ||
388 | if (offset >= size) | ||
389 | return 0; | ||
390 | mc_header = (struct microcode_header_intel *)(buf + offset); | ||
391 | total_size = get_totalsize(mc_header); | ||
392 | |||
393 | if (offset + total_size > size) { | ||
394 | printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); | ||
395 | return -EINVAL; | ||
396 | } | ||
397 | |||
398 | *mc = vmalloc(total_size); | ||
399 | if (!*mc) { | ||
400 | printk(KERN_ERR "microcode: error! Can not allocate memory\n"); | ||
401 | return -ENOMEM; | ||
402 | } | ||
403 | memcpy(*mc, buf + offset, total_size); | ||
404 | return offset + total_size; | ||
405 | } | ||
406 | |||
407 | /* fake device for request_firmware */ | ||
408 | extern struct platform_device *microcode_pdev; | ||
409 | |||
410 | static int cpu_request_microcode(int cpu) | ||
411 | { | ||
412 | char name[30]; | ||
413 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
414 | const struct firmware *firmware; | ||
415 | const u8 *buf; | ||
416 | unsigned long size; | ||
417 | long offset = 0; | ||
418 | int error; | ||
419 | void *mc; | ||
420 | |||
421 | /* We should bind the task to the CPU */ | ||
422 | BUG_ON(cpu != raw_smp_processor_id()); | ||
423 | sprintf(name, "intel-ucode/%02x-%02x-%02x", | ||
424 | c->x86, c->x86_model, c->x86_mask); | ||
425 | error = request_firmware(&firmware, name, µcode_pdev->dev); | ||
426 | if (error) { | ||
427 | pr_debug("microcode: data file %s load failed\n", name); | ||
428 | return error; | ||
429 | } | ||
430 | buf = firmware->data; | ||
431 | size = firmware->size; | ||
432 | while ((offset = get_next_ucode_from_buffer(&mc, buf, size, offset)) | ||
433 | > 0) { | ||
434 | error = microcode_sanity_check(mc); | ||
435 | if (error) | ||
436 | break; | ||
437 | error = get_matching_microcode(mc, cpu); | ||
438 | if (error < 0) | ||
439 | break; | ||
440 | /* | ||
441 | * It's possible the data file has multiple matching ucode, | ||
442 | * lets keep searching till the latest version | ||
443 | */ | ||
444 | if (error == 1) { | ||
445 | apply_microcode(cpu); | ||
446 | error = 0; | ||
447 | } | ||
448 | vfree(mc); | ||
449 | } | ||
450 | if (offset > 0) | ||
451 | vfree(mc); | ||
452 | if (offset < 0) | ||
453 | error = offset; | ||
454 | release_firmware(firmware); | ||
455 | |||
456 | return error; | ||
457 | } | ||
458 | |||
459 | static int apply_microcode_check_cpu(int cpu) | ||
460 | { | ||
461 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
462 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
463 | cpumask_t old; | ||
464 | unsigned int val[2]; | ||
465 | int err = 0; | ||
466 | |||
467 | /* Check if the microcode is available */ | ||
468 | if (!uci->mc.mc_intel) | ||
469 | return 0; | ||
470 | |||
471 | old = current->cpus_allowed; | ||
472 | set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); | ||
473 | |||
474 | /* Check if the microcode we have in memory matches the CPU */ | ||
475 | if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 || | ||
476 | cpu_has(c, X86_FEATURE_IA64) || uci->sig != cpuid_eax(0x00000001)) | ||
477 | err = -EINVAL; | ||
478 | |||
479 | if (!err && ((c->x86_model >= 5) || (c->x86 > 6))) { | ||
480 | /* get processor flags from MSR 0x17 */ | ||
481 | rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); | ||
482 | if (uci->pf != (1 << ((val[1] >> 18) & 7))) | ||
483 | err = -EINVAL; | ||
484 | } | ||
485 | |||
486 | if (!err) { | ||
487 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); | ||
488 | /* see notes above for revision 1.07. Apparent chip bug */ | ||
489 | sync_core(); | ||
490 | /* get the current revision from MSR 0x8B */ | ||
491 | rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); | ||
492 | if (uci->rev != val[1]) | ||
493 | err = -EINVAL; | ||
494 | } | ||
495 | |||
496 | if (!err) | ||
497 | apply_microcode(cpu); | ||
498 | else | ||
499 | printk(KERN_ERR "microcode: Could not apply microcode to CPU%d:" | ||
500 | " sig=0x%x, pf=0x%x, rev=0x%x\n", | ||
501 | cpu, uci->sig, uci->pf, uci->rev); | ||
502 | |||
503 | set_cpus_allowed_ptr(current, &old); | ||
504 | return err; | ||
505 | } | ||
506 | |||
507 | static void microcode_fini_cpu(int cpu) | ||
508 | { | ||
509 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
510 | |||
511 | mutex_lock(µcode_mutex); | ||
512 | uci->valid = 0; | ||
513 | vfree(uci->mc.mc_intel); | ||
514 | uci->mc.mc_intel = NULL; | ||
515 | mutex_unlock(µcode_mutex); | ||
516 | } | ||
517 | |||
518 | static struct microcode_ops microcode_intel_ops = { | ||
519 | .get_next_ucode = get_next_ucode, | ||
520 | .get_matching_microcode = get_matching_microcode, | ||
521 | .microcode_sanity_check = microcode_sanity_check, | ||
522 | .apply_microcode_check_cpu = apply_microcode_check_cpu, | ||
523 | .cpu_request_microcode = cpu_request_microcode, | ||
524 | .collect_cpu_info = collect_cpu_info, | ||
525 | .apply_microcode = apply_microcode, | ||
526 | .microcode_fini_cpu = microcode_fini_cpu, | ||
527 | }; | ||
528 | |||
529 | static int __init microcode_intel_module_init(void) | ||
530 | { | ||
531 | struct cpuinfo_x86 *c = &cpu_data(get_cpu()); | ||
532 | |||
533 | if (c->x86_vendor == X86_VENDOR_INTEL) | ||
534 | return microcode_init(µcode_intel_ops, THIS_MODULE); | ||
535 | else | ||
536 | return -ENODEV; | ||
537 | } | ||
538 | |||
539 | static void __exit microcode_intel_module_exit(void) | ||
540 | { | ||
541 | microcode_exit(); | ||
542 | } | ||
543 | |||
544 | module_init(microcode_intel_module_init) | ||
545 | module_exit(microcode_intel_module_exit) | ||
diff --git a/include/asm-x86/microcode.h b/include/asm-x86/microcode.h new file mode 100644 index 000000000000..18b2aeec2adf --- /dev/null +++ b/include/asm-x86/microcode.h | |||
@@ -0,0 +1,87 @@ | |||
1 | extern int microcode_init(void *opaque, struct module *module); | ||
2 | extern void microcode_exit(void); | ||
3 | |||
4 | struct microcode_ops { | ||
5 | long (*get_next_ucode)(void **mc, long offset); | ||
6 | long (*microcode_get_next_ucode)(void **mc, long offset); | ||
7 | int (*get_matching_microcode)(void *mc, int cpu); | ||
8 | int (*apply_microcode_check_cpu)(int cpu); | ||
9 | int (*microcode_sanity_check)(void *mc); | ||
10 | int (*cpu_request_microcode)(int cpu); | ||
11 | void (*collect_cpu_info)(int cpu_num); | ||
12 | void (*apply_microcode)(int cpu); | ||
13 | void (*microcode_fini_cpu)(int cpu); | ||
14 | void (*clear_patch)(void *data); | ||
15 | }; | ||
16 | |||
17 | struct microcode_header_intel { | ||
18 | unsigned int hdrver; | ||
19 | unsigned int rev; | ||
20 | unsigned int date; | ||
21 | unsigned int sig; | ||
22 | unsigned int cksum; | ||
23 | unsigned int ldrver; | ||
24 | unsigned int pf; | ||
25 | unsigned int datasize; | ||
26 | unsigned int totalsize; | ||
27 | unsigned int reserved[3]; | ||
28 | }; | ||
29 | |||
30 | struct microcode_intel { | ||
31 | struct microcode_header_intel hdr; | ||
32 | unsigned int bits[0]; | ||
33 | }; | ||
34 | |||
35 | /* microcode format is extended from prescott processors */ | ||
36 | struct extended_signature { | ||
37 | unsigned int sig; | ||
38 | unsigned int pf; | ||
39 | unsigned int cksum; | ||
40 | }; | ||
41 | |||
42 | struct extended_sigtable { | ||
43 | unsigned int count; | ||
44 | unsigned int cksum; | ||
45 | unsigned int reserved[3]; | ||
46 | struct extended_signature sigs[0]; | ||
47 | }; | ||
48 | |||
49 | struct equiv_cpu_entry { | ||
50 | unsigned int installed_cpu; | ||
51 | unsigned int fixed_errata_mask; | ||
52 | unsigned int fixed_errata_compare; | ||
53 | unsigned int equiv_cpu; | ||
54 | }; | ||
55 | |||
56 | struct microcode_header_amd { | ||
57 | unsigned int data_code; | ||
58 | unsigned int patch_id; | ||
59 | unsigned char mc_patch_data_id[2]; | ||
60 | unsigned char mc_patch_data_len; | ||
61 | unsigned char init_flag; | ||
62 | unsigned int mc_patch_data_checksum; | ||
63 | unsigned int nb_dev_id; | ||
64 | unsigned int sb_dev_id; | ||
65 | unsigned char processor_rev_id[2]; | ||
66 | unsigned char nb_rev_id; | ||
67 | unsigned char sb_rev_id; | ||
68 | unsigned char bios_api_rev; | ||
69 | unsigned char reserved1[3]; | ||
70 | unsigned int match_reg[8]; | ||
71 | }; | ||
72 | |||
73 | struct microcode_amd { | ||
74 | struct microcode_header_amd hdr; | ||
75 | unsigned int mpb[0]; | ||
76 | }; | ||
77 | |||
78 | struct ucode_cpu_info { | ||
79 | int valid; | ||
80 | unsigned int sig; | ||
81 | unsigned int pf; | ||
82 | unsigned int rev; | ||
83 | union { | ||
84 | struct microcode_intel *mc_intel; | ||
85 | struct microcode_amd *mc_amd; | ||
86 | } mc; | ||
87 | }; | ||
diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h index 5f58da401b43..58a76f69ee31 100644 --- a/include/asm-x86/processor.h +++ b/include/asm-x86/processor.h | |||
@@ -561,41 +561,6 @@ static inline void clear_in_cr4(unsigned long mask) | |||
561 | write_cr4(cr4); | 561 | write_cr4(cr4); |
562 | } | 562 | } |
563 | 563 | ||
564 | struct microcode_header { | ||
565 | unsigned int hdrver; | ||
566 | unsigned int rev; | ||
567 | unsigned int date; | ||
568 | unsigned int sig; | ||
569 | unsigned int cksum; | ||
570 | unsigned int ldrver; | ||
571 | unsigned int pf; | ||
572 | unsigned int datasize; | ||
573 | unsigned int totalsize; | ||
574 | unsigned int reserved[3]; | ||
575 | }; | ||
576 | |||
577 | struct microcode { | ||
578 | struct microcode_header hdr; | ||
579 | unsigned int bits[0]; | ||
580 | }; | ||
581 | |||
582 | typedef struct microcode microcode_t; | ||
583 | typedef struct microcode_header microcode_header_t; | ||
584 | |||
585 | /* microcode format is extended from prescott processors */ | ||
586 | struct extended_signature { | ||
587 | unsigned int sig; | ||
588 | unsigned int pf; | ||
589 | unsigned int cksum; | ||
590 | }; | ||
591 | |||
592 | struct extended_sigtable { | ||
593 | unsigned int count; | ||
594 | unsigned int cksum; | ||
595 | unsigned int reserved[3]; | ||
596 | struct extended_signature sigs[0]; | ||
597 | }; | ||
598 | |||
599 | typedef struct { | 564 | typedef struct { |
600 | unsigned long seg; | 565 | unsigned long seg; |
601 | } mm_segment_t; | 566 | } mm_segment_t; |