Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Fenghua Yu and committed by
H. Peter Anvin
9cd4d78e 0d91ea86

+122 -171
+85
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 */
+3
arch/x86/kernel/Makefile
··· 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
+4 -3
arch/x86/kernel/microcode_core.c
··· 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) ··· 380 383 static enum ucode_state microcode_init_cpu(int cpu, bool refresh_fw) 381 384 { 382 385 enum ucode_state ustate; 386 + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 387 + 388 + if (uci && uci->valid) 389 + return UCODE_OK; 383 390 384 391 if (collect_cpu_info(cpu)) 385 392 return UCODE_ERROR;
+30 -168
arch/x86/kernel/microcode_intel.c
··· 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 86 86 MODULE_DESCRIPTION("Microcode Update Driver"); 87 87 MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); 88 88 MODULE_LICENSE("GPL"); 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 89 143 90 static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) 144 91 { ··· 109 162 return 0; 110 163 } 111 164 112 - static inline int update_match_cpu(struct cpu_signature *csig, int sig, int pf) 113 - { 114 - return (!sigmatch(sig, csig->sig, pf, csig->pf)) ? 0 : 1; 115 - } 116 - 117 - static inline int 118 - update_match_revision(struct microcode_header_intel *mc_header, int rev) 119 - { 120 - return (mc_header->rev <= rev) ? 0 : 1; 121 - } 122 - 123 - static int microcode_sanity_check(void *mc) 124 - { 125 - unsigned long total_size, data_size, ext_table_size; 126 - struct microcode_header_intel *mc_header = mc; 127 - struct extended_sigtable *ext_header = NULL; 128 - int sum, orig_sum, ext_sigcount = 0, i; 129 - struct extended_signature *ext_sig; 130 - 131 - total_size = get_totalsize(mc_header); 132 - data_size = get_datasize(mc_header); 133 - 134 - if (data_size + MC_HEADER_SIZE > total_size) { 135 - pr_err("error! Bad data size in microcode data file\n"); 136 - return -EINVAL; 137 - } 138 - 139 - if (mc_header->ldrver != 1 || mc_header->hdrver != 1) { 140 - pr_err("error! Unknown microcode update format\n"); 141 - return -EINVAL; 142 - } 143 - ext_table_size = total_size - (MC_HEADER_SIZE + data_size); 144 - if (ext_table_size) { 145 - if ((ext_table_size < EXT_HEADER_SIZE) 146 - || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) { 147 - pr_err("error! Small exttable size in microcode data file\n"); 148 - return -EINVAL; 149 - } 150 - ext_header = mc + MC_HEADER_SIZE + data_size; 151 - if (ext_table_size != exttable_size(ext_header)) { 152 - pr_err("error! Bad exttable size in microcode data file\n"); 153 - return -EFAULT; 154 - } 155 - ext_sigcount = ext_header->count; 156 - } 157 - 158 - /* check extended table checksum */ 159 - if (ext_table_size) { 160 - int ext_table_sum = 0; 161 - int *ext_tablep = (int *)ext_header; 162 - 163 - i = ext_table_size / DWSIZE; 164 - while (i--) 165 - ext_table_sum += ext_tablep[i]; 166 - if (ext_table_sum) { 167 - pr_warning("aborting, bad extended signature table checksum\n"); 168 - return -EINVAL; 169 - } 170 - } 171 - 172 - /* calculate the checksum */ 173 - orig_sum = 0; 174 - i = (MC_HEADER_SIZE + data_size) / DWSIZE; 175 - while (i--) 176 - orig_sum += ((int *)mc)[i]; 177 - if (orig_sum) { 178 - pr_err("aborting, bad checksum\n"); 179 - return -EINVAL; 180 - } 181 - if (!ext_table_size) 182 - return 0; 183 - /* check extended signature checksum */ 184 - for (i = 0; i < ext_sigcount; i++) { 185 - ext_sig = (void *)ext_header + EXT_HEADER_SIZE + 186 - EXT_SIGNATURE_SIZE * i; 187 - sum = orig_sum 188 - - (mc_header->sig + mc_header->pf + mc_header->cksum) 189 - + (ext_sig->sig + ext_sig->pf + ext_sig->cksum); 190 - if (sum) { 191 - pr_err("aborting, bad checksum\n"); 192 - return -EINVAL; 193 - } 194 - } 195 - return 0; 196 - } 197 - 198 165 /* 199 166 * return 0 - no update found 200 167 * return 1 - found update 201 168 */ 202 - static int 203 - get_matching_microcode(struct cpu_signature *cpu_sig, void *mc, int rev) 169 + static int get_matching_mc(struct microcode_intel *mc_intel, int cpu) 204 170 { 205 - struct microcode_header_intel *mc_header = mc; 206 - struct extended_sigtable *ext_header; 207 - unsigned long total_size = get_totalsize(mc_header); 208 - int ext_sigcount, i; 209 - struct extended_signature *ext_sig; 171 + struct cpu_signature cpu_sig; 172 + unsigned int csig, cpf, crev; 210 173 211 - if (!update_match_revision(mc_header, rev)) 212 - return 0; 174 + collect_cpu_info(cpu, &cpu_sig); 213 175 214 - if (update_match_cpu(cpu_sig, mc_header->sig, mc_header->pf)) 215 - return 1; 176 + csig = cpu_sig.sig; 177 + cpf = cpu_sig.pf; 178 + crev = cpu_sig.rev; 216 179 217 - /* Look for ext. headers: */ 218 - if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE) 219 - return 0; 220 - 221 - ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE; 222 - ext_sigcount = ext_header->count; 223 - ext_sig = (void *)ext_header + EXT_HEADER_SIZE; 224 - 225 - for (i = 0; i < ext_sigcount; i++) { 226 - if (update_match_cpu(cpu_sig, ext_sig->sig, ext_sig->pf)) 227 - return 1; 228 - ext_sig++; 229 - } 230 - return 0; 180 + return get_matching_microcode(csig, cpf, mc_intel, crev); 231 181 } 232 182 233 - static int apply_microcode(int cpu) 183 + int apply_microcode(int cpu) 234 184 { 235 185 struct microcode_intel *mc_intel; 236 186 struct ucode_cpu_info *uci; ··· 142 298 BUG_ON(cpu_num != cpu); 143 299 144 300 if (mc_intel == NULL) 301 + return 0; 302 + 303 + /* 304 + * Microcode on this CPU could be updated earlier. Only apply the 305 + * microcode patch in mc_intel when it is newer than the one on this 306 + * CPU. 307 + */ 308 + if (get_matching_mc(mc_intel, cpu) == 0) 145 309 return 0; 146 310 147 311 /* write microcode via MSR 0x79 */ ··· 190 338 unsigned int leftover = size; 191 339 enum ucode_state state = UCODE_OK; 192 340 unsigned int curr_mc_size = 0; 341 + unsigned int csig, cpf; 193 342 194 343 while (leftover) { 195 344 struct microcode_header_intel mc_header; ··· 215 362 } 216 363 217 364 if (get_ucode_data(mc, ucode_ptr, mc_size) || 218 - microcode_sanity_check(mc) < 0) { 365 + microcode_sanity_check(mc, 1) < 0) { 219 366 break; 220 367 } 221 368 222 - if (get_matching_microcode(&uci->cpu_sig, mc, new_rev)) { 369 + csig = uci->cpu_sig.sig; 370 + cpf = uci->cpu_sig.pf; 371 + if (get_matching_microcode(csig, cpf, mc, new_rev)) { 223 372 vfree(new_mc); 224 373 new_rev = mc_header.rev; 225 374 new_mc = mc; ··· 247 392 248 393 vfree(uci->mc); 249 394 uci->mc = (struct microcode_intel *)new_mc; 395 + 396 + /* 397 + * If early loading microcode is supported, save this mc into 398 + * permanent memory. So it will be loaded early when a CPU is hot added 399 + * or resumes. 400 + */ 401 + save_mc_for_early(new_mc); 250 402 251 403 pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n", 252 404 cpu, new_rev, uci->cpu_sig.rev);