Commit 9cd4d78e21cfdc709b1af516214ec4f69ee0e6bd

Authored by Fenghua Yu
Committed by H. Peter Anvin
1 parent 0d91ea86a8

x86/microcode_intel.h: Define functions and macros for early loading ucode

Define some functions and macros that will be used in early loading ucode. Some
of them are moved from microcode_intel.c driver in order to be called in early
boot phase before module can be called.

Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Link: http://lkml.kernel.org/r/1356075872-3054-3-git-send-email-fenghua.yu@intel.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>

Showing 4 changed files with 122 additions and 171 deletions Side-by-side Diff

arch/x86/include/asm/microcode_intel.h
  1 +#ifndef _ASM_X86_MICROCODE_INTEL_H
  2 +#define _ASM_X86_MICROCODE_INTEL_H
  3 +
  4 +#include <asm/microcode.h>
  5 +
  6 +struct microcode_header_intel {
  7 + unsigned int hdrver;
  8 + unsigned int rev;
  9 + unsigned int date;
  10 + unsigned int sig;
  11 + unsigned int cksum;
  12 + unsigned int ldrver;
  13 + unsigned int pf;
  14 + unsigned int datasize;
  15 + unsigned int totalsize;
  16 + unsigned int reserved[3];
  17 +};
  18 +
  19 +struct microcode_intel {
  20 + struct microcode_header_intel hdr;
  21 + unsigned int bits[0];
  22 +};
  23 +
  24 +/* microcode format is extended from prescott processors */
  25 +struct extended_signature {
  26 + unsigned int sig;
  27 + unsigned int pf;
  28 + unsigned int cksum;
  29 +};
  30 +
  31 +struct extended_sigtable {
  32 + unsigned int count;
  33 + unsigned int cksum;
  34 + unsigned int reserved[3];
  35 + struct extended_signature sigs[0];
  36 +};
  37 +
  38 +#define DEFAULT_UCODE_DATASIZE (2000)
  39 +#define MC_HEADER_SIZE (sizeof(struct microcode_header_intel))
  40 +#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
  41 +#define EXT_HEADER_SIZE (sizeof(struct extended_sigtable))
  42 +#define EXT_SIGNATURE_SIZE (sizeof(struct extended_signature))
  43 +#define DWSIZE (sizeof(u32))
  44 +
  45 +#define get_totalsize(mc) \
  46 + (((struct microcode_intel *)mc)->hdr.totalsize ? \
  47 + ((struct microcode_intel *)mc)->hdr.totalsize : \
  48 + DEFAULT_UCODE_TOTALSIZE)
  49 +
  50 +#define get_datasize(mc) \
  51 + (((struct microcode_intel *)mc)->hdr.datasize ? \
  52 + ((struct microcode_intel *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
  53 +
  54 +#define sigmatch(s1, s2, p1, p2) \
  55 + (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
  56 +
  57 +#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
  58 +
  59 +extern int
  60 +get_matching_microcode(unsigned int csig, int cpf, void *mc, int rev);
  61 +extern int microcode_sanity_check(void *mc, int print_err);
  62 +extern int get_matching_sig(unsigned int csig, int cpf, void *mc, int rev);
  63 +extern int
  64 +update_match_revision(struct microcode_header_intel *mc_header, int rev);
  65 +
  66 +#ifdef CONFIG_MICROCODE_INTEL_EARLY
  67 +extern void __init load_ucode_intel_bsp(void);
  68 +extern void __cpuinit load_ucode_intel_ap(void);
  69 +extern void show_ucode_info_early(void);
  70 +#else
  71 +static inline __init void load_ucode_intel_bsp(void) {}
  72 +static inline __cpuinit void load_ucode_intel_ap(void) {}
  73 +static inline void show_ucode_info_early(void) {}
  74 +#endif
  75 +
  76 +#if defined(CONFIG_MICROCODE_INTEL_EARLY) && defined(CONFIG_HOTPLUG_CPU)
  77 +extern int save_mc_for_early(u8 *mc);
  78 +#else
  79 +static inline int save_mc_for_early(u8 *mc)
  80 +{
  81 + return 0;
  82 +}
  83 +#endif
  84 +
  85 +#endif /* _ASM_X86_MICROCODE_INTEL_H */
arch/x86/kernel/Makefile
... ... @@ -88,6 +88,9 @@
88 88  
89 89 obj-$(CONFIG_PCSPKR_PLATFORM) += pcspeaker.o
90 90  
  91 +obj-$(CONFIG_MICROCODE_EARLY) += microcode_core_early.o
  92 +obj-$(CONFIG_MICROCODE_INTEL_EARLY) += microcode_intel_early.o
  93 +obj-$(CONFIG_MICROCODE_INTEL_LIB) += microcode_intel_lib.o
91 94 microcode-y := microcode_core.o
92 95 microcode-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o
93 96 microcode-$(CONFIG_MICROCODE_AMD) += microcode_amd.o
arch/x86/kernel/microcode_core.c
... ... @@ -364,10 +364,7 @@
364 364  
365 365 static void microcode_fini_cpu(int cpu)
366 366 {
367   - struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
368   -
369 367 microcode_ops->microcode_fini_cpu(cpu);
370   - uci->valid = 0;
371 368 }
372 369  
373 370 static enum ucode_state microcode_resume_cpu(int cpu)
... ... @@ -383,6 +380,10 @@
383 380 static enum ucode_state microcode_init_cpu(int cpu, bool refresh_fw)
384 381 {
385 382 enum ucode_state ustate;
  383 + struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
  384 +
  385 + if (uci && uci->valid)
  386 + return UCODE_OK;
386 387  
387 388 if (collect_cpu_info(cpu))
388 389 return UCODE_ERROR;
arch/x86/kernel/microcode_intel.c
... ... @@ -79,7 +79,7 @@
79 79 #include <linux/module.h>
80 80 #include <linux/vmalloc.h>
81 81  
82   -#include <asm/microcode.h>
  82 +#include <asm/microcode_intel.h>
83 83 #include <asm/processor.h>
84 84 #include <asm/msr.h>
85 85  
... ... @@ -87,59 +87,6 @@
87 87 MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
88 88 MODULE_LICENSE("GPL");
89 89  
90   -struct microcode_header_intel {
91   - unsigned int hdrver;
92   - unsigned int rev;
93   - unsigned int date;
94   - unsigned int sig;
95   - unsigned int cksum;
96   - unsigned int ldrver;
97   - unsigned int pf;
98   - unsigned int datasize;
99   - unsigned int totalsize;
100   - unsigned int reserved[3];
101   -};
102   -
103   -struct microcode_intel {
104   - struct microcode_header_intel hdr;
105   - unsigned int bits[0];
106   -};
107   -
108   -/* microcode format is extended from prescott processors */
109   -struct extended_signature {
110   - unsigned int sig;
111   - unsigned int pf;
112   - unsigned int cksum;
113   -};
114   -
115   -struct extended_sigtable {
116   - unsigned int count;
117   - unsigned int cksum;
118   - unsigned int reserved[3];
119   - struct extended_signature sigs[0];
120   -};
121   -
122   -#define DEFAULT_UCODE_DATASIZE (2000)
123   -#define MC_HEADER_SIZE (sizeof(struct microcode_header_intel))
124   -#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
125   -#define EXT_HEADER_SIZE (sizeof(struct extended_sigtable))
126   -#define EXT_SIGNATURE_SIZE (sizeof(struct extended_signature))
127   -#define DWSIZE (sizeof(u32))
128   -
129   -#define get_totalsize(mc) \
130   - (((struct microcode_intel *)mc)->hdr.totalsize ? \
131   - ((struct microcode_intel *)mc)->hdr.totalsize : \
132   - DEFAULT_UCODE_TOTALSIZE)
133   -
134   -#define get_datasize(mc) \
135   - (((struct microcode_intel *)mc)->hdr.datasize ? \
136   - ((struct microcode_intel *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
137   -
138   -#define sigmatch(s1, s2, p1, p2) \
139   - (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
140   -
141   -#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
142   -
143 90 static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
144 91 {
145 92 struct cpuinfo_x86 *c = &cpu_data(cpu_num);
146 93  
147 94  
148 95  
149 96  
150 97  
151 98  
... ... @@ -162,128 +109,25 @@
162 109 return 0;
163 110 }
164 111  
165   -static inline int update_match_cpu(struct cpu_signature *csig, int sig, int pf)
166   -{
167   - return (!sigmatch(sig, csig->sig, pf, csig->pf)) ? 0 : 1;
168   -}
169   -
170   -static inline int
171   -update_match_revision(struct microcode_header_intel *mc_header, int rev)
172   -{
173   - return (mc_header->rev <= rev) ? 0 : 1;
174   -}
175   -
176   -static int microcode_sanity_check(void *mc)
177   -{
178   - unsigned long total_size, data_size, ext_table_size;
179   - struct microcode_header_intel *mc_header = mc;
180   - struct extended_sigtable *ext_header = NULL;
181   - int sum, orig_sum, ext_sigcount = 0, i;
182   - struct extended_signature *ext_sig;
183   -
184   - total_size = get_totalsize(mc_header);
185   - data_size = get_datasize(mc_header);
186   -
187   - if (data_size + MC_HEADER_SIZE > total_size) {
188   - pr_err("error! Bad data size in microcode data file\n");
189   - return -EINVAL;
190   - }
191   -
192   - if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
193   - pr_err("error! Unknown microcode update format\n");
194   - return -EINVAL;
195   - }
196   - ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
197   - if (ext_table_size) {
198   - if ((ext_table_size < EXT_HEADER_SIZE)
199   - || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
200   - pr_err("error! Small exttable size in microcode data file\n");
201   - return -EINVAL;
202   - }
203   - ext_header = mc + MC_HEADER_SIZE + data_size;
204   - if (ext_table_size != exttable_size(ext_header)) {
205   - pr_err("error! Bad exttable size in microcode data file\n");
206   - return -EFAULT;
207   - }
208   - ext_sigcount = ext_header->count;
209   - }
210   -
211   - /* check extended table checksum */
212   - if (ext_table_size) {
213   - int ext_table_sum = 0;
214   - int *ext_tablep = (int *)ext_header;
215   -
216   - i = ext_table_size / DWSIZE;
217   - while (i--)
218   - ext_table_sum += ext_tablep[i];
219   - if (ext_table_sum) {
220   - pr_warning("aborting, bad extended signature table checksum\n");
221   - return -EINVAL;
222   - }
223   - }
224   -
225   - /* calculate the checksum */
226   - orig_sum = 0;
227   - i = (MC_HEADER_SIZE + data_size) / DWSIZE;
228   - while (i--)
229   - orig_sum += ((int *)mc)[i];
230   - if (orig_sum) {
231   - pr_err("aborting, bad checksum\n");
232   - return -EINVAL;
233   - }
234   - if (!ext_table_size)
235   - return 0;
236   - /* check extended signature checksum */
237   - for (i = 0; i < ext_sigcount; i++) {
238   - ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
239   - EXT_SIGNATURE_SIZE * i;
240   - sum = orig_sum
241   - - (mc_header->sig + mc_header->pf + mc_header->cksum)
242   - + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
243   - if (sum) {
244   - pr_err("aborting, bad checksum\n");
245   - return -EINVAL;
246   - }
247   - }
248   - return 0;
249   -}
250   -
251 112 /*
252 113 * return 0 - no update found
253 114 * return 1 - found update
254 115 */
255   -static int
256   -get_matching_microcode(struct cpu_signature *cpu_sig, void *mc, int rev)
  116 +static int get_matching_mc(struct microcode_intel *mc_intel, int cpu)
257 117 {
258   - struct microcode_header_intel *mc_header = mc;
259   - struct extended_sigtable *ext_header;
260   - unsigned long total_size = get_totalsize(mc_header);
261   - int ext_sigcount, i;
262   - struct extended_signature *ext_sig;
  118 + struct cpu_signature cpu_sig;
  119 + unsigned int csig, cpf, crev;
263 120  
264   - if (!update_match_revision(mc_header, rev))
265   - return 0;
  121 + collect_cpu_info(cpu, &cpu_sig);
266 122  
267   - if (update_match_cpu(cpu_sig, mc_header->sig, mc_header->pf))
268   - return 1;
  123 + csig = cpu_sig.sig;
  124 + cpf = cpu_sig.pf;
  125 + crev = cpu_sig.rev;
269 126  
270   - /* Look for ext. headers: */
271   - if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
272   - return 0;
273   -
274   - ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
275   - ext_sigcount = ext_header->count;
276   - ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
277   -
278   - for (i = 0; i < ext_sigcount; i++) {
279   - if (update_match_cpu(cpu_sig, ext_sig->sig, ext_sig->pf))
280   - return 1;
281   - ext_sig++;
282   - }
283   - return 0;
  127 + return get_matching_microcode(csig, cpf, mc_intel, crev);
284 128 }
285 129  
286   -static int apply_microcode(int cpu)
  130 +int apply_microcode(int cpu)
287 131 {
288 132 struct microcode_intel *mc_intel;
289 133 struct ucode_cpu_info *uci;
... ... @@ -300,6 +144,14 @@
300 144 if (mc_intel == NULL)
301 145 return 0;
302 146  
  147 + /*
  148 + * Microcode on this CPU could be updated earlier. Only apply the
  149 + * microcode patch in mc_intel when it is newer than the one on this
  150 + * CPU.
  151 + */
  152 + if (get_matching_mc(mc_intel, cpu) == 0)
  153 + return 0;
  154 +
303 155 /* write microcode via MSR 0x79 */
304 156 wrmsr(MSR_IA32_UCODE_WRITE,
305 157 (unsigned long) mc_intel->bits,
... ... @@ -338,6 +190,7 @@
338 190 unsigned int leftover = size;
339 191 enum ucode_state state = UCODE_OK;
340 192 unsigned int curr_mc_size = 0;
  193 + unsigned int csig, cpf;
341 194  
342 195 while (leftover) {
343 196 struct microcode_header_intel mc_header;
344 197  
... ... @@ -362,11 +215,13 @@
362 215 }
363 216  
364 217 if (get_ucode_data(mc, ucode_ptr, mc_size) ||
365   - microcode_sanity_check(mc) < 0) {
  218 + microcode_sanity_check(mc, 1) < 0) {
366 219 break;
367 220 }
368 221  
369   - if (get_matching_microcode(&uci->cpu_sig, mc, new_rev)) {
  222 + csig = uci->cpu_sig.sig;
  223 + cpf = uci->cpu_sig.pf;
  224 + if (get_matching_microcode(csig, cpf, mc, new_rev)) {
370 225 vfree(new_mc);
371 226 new_rev = mc_header.rev;
372 227 new_mc = mc;
... ... @@ -392,6 +247,13 @@
392 247  
393 248 vfree(uci->mc);
394 249 uci->mc = (struct microcode_intel *)new_mc;
  250 +
  251 + /*
  252 + * If early loading microcode is supported, save this mc into
  253 + * permanent memory. So it will be loaded early when a CPU is hot added
  254 + * or resumes.
  255 + */
  256 + save_mc_for_early(new_mc);
395 257  
396 258 pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n",
397 259 cpu, new_rev, uci->cpu_sig.rev);