]>
Commit | Line | Data |
---|---|---|
a8ebf6d1 FY |
1 | /* |
2 | * X86 CPU microcode early update for Linux | |
3 | * | |
4 | * Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com> | |
5 | * H Peter Anvin" <hpa@zytor.com> | |
760d765b | 6 | * (C) 2015 Borislav Petkov <bp@alien8.de> |
a8ebf6d1 FY |
7 | * |
8 | * This driver allows to early upgrade microcode on Intel processors | |
9 | * belonging to IA-32 family - PentiumPro, Pentium II, | |
10 | * Pentium III, Xeon, Pentium 4, etc. | |
11 | * | |
12 | * Reference: Section 9.11 of Volume 3, IA-32 Intel Architecture | |
13 | * Software Developer's Manual. | |
14 | * | |
15 | * This program is free software; you can redistribute it and/or | |
16 | * modify it under the terms of the GNU General Public License | |
17 | * as published by the Free Software Foundation; either version | |
18 | * 2 of the License, or (at your option) any later version. | |
19 | */ | |
20 | #include <linux/module.h> | |
760d765b | 21 | #include <linux/firmware.h> |
65cef131 | 22 | #include <asm/microcode.h> |
a8ebf6d1 | 23 | #include <asm/microcode_intel.h> |
757885e9 | 24 | #include <asm/microcode_amd.h> |
a8ebf6d1 | 25 | #include <asm/processor.h> |
65cef131 | 26 | #include <asm/cmdline.h> |
a8ebf6d1 | 27 | |
65cef131 BP |
28 | static bool __init check_loader_disabled_bsp(void) |
29 | { | |
30 | #ifdef CONFIG_X86_32 | |
31 | const char *cmdline = (const char *)__pa_nodebug(boot_command_line); | |
32 | const char *opt = "dis_ucode_ldr"; | |
33 | const char *option = (const char *)__pa_nodebug(opt); | |
34 | bool *res = (bool *)__pa_nodebug(&dis_ucode_ldr); | |
35 | ||
36 | #else /* CONFIG_X86_64 */ | |
37 | const char *cmdline = boot_command_line; | |
38 | const char *option = "dis_ucode_ldr"; | |
39 | bool *res = &dis_ucode_ldr; | |
40 | #endif | |
41 | ||
42 | if (cmdline_find_option_bool(cmdline, option)) | |
43 | *res = true; | |
44 | ||
45 | return *res; | |
46 | } | |
47 | ||
760d765b BP |
48 | extern struct builtin_fw __start_builtin_fw[]; |
49 | extern struct builtin_fw __end_builtin_fw[]; | |
50 | ||
51 | bool get_builtin_firmware(struct cpio_data *cd, const char *name) | |
52 | { | |
53 | #ifdef CONFIG_FW_LOADER | |
54 | struct builtin_fw *b_fw; | |
55 | ||
56 | for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) { | |
57 | if (!strcmp(name, b_fw->name)) { | |
58 | cd->size = b_fw->size; | |
59 | cd->data = b_fw->data; | |
60 | return true; | |
61 | } | |
62 | } | |
63 | #endif | |
64 | return false; | |
65 | } | |
66 | ||
a8ebf6d1 FY |
67 | void __init load_ucode_bsp(void) |
68 | { | |
7b179b8f AS |
69 | int vendor; |
70 | unsigned int family; | |
74c3e3fc | 71 | |
65cef131 BP |
72 | if (check_loader_disabled_bsp()) |
73 | return; | |
74 | ||
74c3e3fc PA |
75 | if (!have_cpuid_p()) |
76 | return; | |
a8ebf6d1 | 77 | |
74c3e3fc | 78 | vendor = x86_vendor(); |
58ce8d6d | 79 | family = x86_family(); |
74c3e3fc | 80 | |
757885e9 JS |
81 | switch (vendor) { |
82 | case X86_VENDOR_INTEL: | |
58ce8d6d | 83 | if (family >= 6) |
757885e9 JS |
84 | load_ucode_intel_bsp(); |
85 | break; | |
86 | case X86_VENDOR_AMD: | |
58ce8d6d | 87 | if (family >= 0x10) |
760d765b | 88 | load_ucode_amd_bsp(family); |
757885e9 JS |
89 | break; |
90 | default: | |
91 | break; | |
92 | } | |
a8ebf6d1 FY |
93 | } |
94 | ||
65cef131 BP |
95 | static bool check_loader_disabled_ap(void) |
96 | { | |
97 | #ifdef CONFIG_X86_32 | |
85be07c3 | 98 | return *((bool *)__pa_nodebug(&dis_ucode_ldr)); |
65cef131 BP |
99 | #else |
100 | return dis_ucode_ldr; | |
101 | #endif | |
102 | } | |
103 | ||
148f9bb8 | 104 | void load_ucode_ap(void) |
a8ebf6d1 | 105 | { |
58ce8d6d | 106 | int vendor, family; |
74c3e3fc | 107 | |
65cef131 BP |
108 | if (check_loader_disabled_ap()) |
109 | return; | |
110 | ||
74c3e3fc PA |
111 | if (!have_cpuid_p()) |
112 | return; | |
113 | ||
114 | vendor = x86_vendor(); | |
58ce8d6d | 115 | family = x86_family(); |
a8ebf6d1 | 116 | |
757885e9 JS |
117 | switch (vendor) { |
118 | case X86_VENDOR_INTEL: | |
58ce8d6d | 119 | if (family >= 6) |
757885e9 JS |
120 | load_ucode_intel_ap(); |
121 | break; | |
122 | case X86_VENDOR_AMD: | |
58ce8d6d | 123 | if (family >= 0x10) |
757885e9 JS |
124 | load_ucode_amd_ap(); |
125 | break; | |
126 | default: | |
127 | break; | |
128 | } | |
a8ebf6d1 | 129 | } |
f2b3ee82 JS |
130 | |
131 | int __init save_microcode_in_initrd(void) | |
132 | { | |
133 | struct cpuinfo_x86 *c = &boot_cpu_data; | |
134 | ||
757885e9 JS |
135 | switch (c->x86_vendor) { |
136 | case X86_VENDOR_INTEL: | |
137 | if (c->x86 >= 6) | |
138 | save_microcode_in_initrd_intel(); | |
139 | break; | |
140 | case X86_VENDOR_AMD: | |
141 | if (c->x86 >= 0x10) | |
142 | save_microcode_in_initrd_amd(); | |
143 | break; | |
144 | default: | |
145 | break; | |
146 | } | |
f2b3ee82 JS |
147 | |
148 | return 0; | |
149 | } | |
fbae4ba8 BP |
150 | |
151 | void reload_early_microcode(void) | |
152 | { | |
58ce8d6d | 153 | int vendor, family; |
fbae4ba8 BP |
154 | |
155 | vendor = x86_vendor(); | |
58ce8d6d | 156 | family = x86_family(); |
fbae4ba8 BP |
157 | |
158 | switch (vendor) { | |
159 | case X86_VENDOR_INTEL: | |
58ce8d6d | 160 | if (family >= 6) |
fbae4ba8 BP |
161 | reload_ucode_intel(); |
162 | break; | |
163 | case X86_VENDOR_AMD: | |
58ce8d6d | 164 | if (family >= 0x10) |
fbae4ba8 BP |
165 | reload_ucode_amd(); |
166 | break; | |
167 | default: | |
168 | break; | |
169 | } | |
170 | } |