diff options
-rw-r--r-- | arch/x86/include/asm/cmdline.h | 6 | ||||
-rw-r--r-- | arch/x86/include/asm/microcode.h | 1 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/microcode/core.c | 6 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/microcode/core_early.c | 37 | ||||
-rw-r--r-- | arch/x86/lib/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/lib/cmdline.c | 84 |
6 files changed, 135 insertions, 1 deletions
diff --git a/arch/x86/include/asm/cmdline.h b/arch/x86/include/asm/cmdline.h new file mode 100644 index 000000000000..e01f7f7ccb0c --- /dev/null +++ b/arch/x86/include/asm/cmdline.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef _ASM_X86_CMDLINE_H | ||
2 | #define _ASM_X86_CMDLINE_H | ||
3 | |||
4 | int cmdline_find_option_bool(const char *cmdline_ptr, const char *option); | ||
5 | |||
6 | #endif /* _ASM_X86_CMDLINE_H */ | ||
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h index b59827e76529..64dc362506b7 100644 --- a/arch/x86/include/asm/microcode.h +++ b/arch/x86/include/asm/microcode.h | |||
@@ -25,6 +25,7 @@ struct cpu_signature { | |||
25 | struct device; | 25 | struct device; |
26 | 26 | ||
27 | enum ucode_state { UCODE_ERROR, UCODE_OK, UCODE_NFOUND }; | 27 | enum ucode_state { UCODE_ERROR, UCODE_OK, UCODE_NFOUND }; |
28 | extern bool dis_ucode_ldr; | ||
28 | 29 | ||
29 | struct microcode_ops { | 30 | struct microcode_ops { |
30 | enum ucode_state (*request_microcode_user) (int cpu, | 31 | enum ucode_state (*request_microcode_user) (int cpu, |
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 15c987698b0f..dd9d6190b08d 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c | |||
@@ -97,6 +97,9 @@ MODULE_LICENSE("GPL"); | |||
97 | 97 | ||
98 | static struct microcode_ops *microcode_ops; | 98 | static struct microcode_ops *microcode_ops; |
99 | 99 | ||
100 | bool dis_ucode_ldr; | ||
101 | module_param(dis_ucode_ldr, bool, 0); | ||
102 | |||
100 | /* | 103 | /* |
101 | * Synchronization. | 104 | * Synchronization. |
102 | * | 105 | * |
@@ -546,6 +549,9 @@ static int __init microcode_init(void) | |||
546 | struct cpuinfo_x86 *c = &cpu_data(0); | 549 | struct cpuinfo_x86 *c = &cpu_data(0); |
547 | int error; | 550 | int error; |
548 | 551 | ||
552 | if (dis_ucode_ldr) | ||
553 | return 0; | ||
554 | |||
549 | if (c->x86_vendor == X86_VENDOR_INTEL) | 555 | if (c->x86_vendor == X86_VENDOR_INTEL) |
550 | microcode_ops = init_intel_microcode(); | 556 | microcode_ops = init_intel_microcode(); |
551 | else if (c->x86_vendor == X86_VENDOR_AMD) | 557 | else if (c->x86_vendor == X86_VENDOR_AMD) |
diff --git a/arch/x86/kernel/cpu/microcode/core_early.c b/arch/x86/kernel/cpu/microcode/core_early.c index be7f8514f577..5f28a64e71ea 100644 --- a/arch/x86/kernel/cpu/microcode/core_early.c +++ b/arch/x86/kernel/cpu/microcode/core_early.c | |||
@@ -17,9 +17,11 @@ | |||
17 | * 2 of the License, or (at your option) any later version. | 17 | * 2 of the License, or (at your option) any later version. |
18 | */ | 18 | */ |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <asm/microcode.h> | ||
20 | #include <asm/microcode_intel.h> | 21 | #include <asm/microcode_intel.h> |
21 | #include <asm/microcode_amd.h> | 22 | #include <asm/microcode_amd.h> |
22 | #include <asm/processor.h> | 23 | #include <asm/processor.h> |
24 | #include <asm/cmdline.h> | ||
23 | 25 | ||
24 | #define QCHAR(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24)) | 26 | #define QCHAR(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24)) |
25 | #define CPUID_INTEL1 QCHAR('G', 'e', 'n', 'u') | 27 | #define CPUID_INTEL1 QCHAR('G', 'e', 'n', 'u') |
@@ -72,10 +74,33 @@ static int x86_family(void) | |||
72 | return x86; | 74 | return x86; |
73 | } | 75 | } |
74 | 76 | ||
77 | static bool __init check_loader_disabled_bsp(void) | ||
78 | { | ||
79 | #ifdef CONFIG_X86_32 | ||
80 | const char *cmdline = (const char *)__pa_nodebug(boot_command_line); | ||
81 | const char *opt = "dis_ucode_ldr"; | ||
82 | const char *option = (const char *)__pa_nodebug(opt); | ||
83 | bool *res = (bool *)__pa_nodebug(&dis_ucode_ldr); | ||
84 | |||
85 | #else /* CONFIG_X86_64 */ | ||
86 | const char *cmdline = boot_command_line; | ||
87 | const char *option = "dis_ucode_ldr"; | ||
88 | bool *res = &dis_ucode_ldr; | ||
89 | #endif | ||
90 | |||
91 | if (cmdline_find_option_bool(cmdline, option)) | ||
92 | *res = true; | ||
93 | |||
94 | return *res; | ||
95 | } | ||
96 | |||
75 | void __init load_ucode_bsp(void) | 97 | void __init load_ucode_bsp(void) |
76 | { | 98 | { |
77 | int vendor, x86; | 99 | int vendor, x86; |
78 | 100 | ||
101 | if (check_loader_disabled_bsp()) | ||
102 | return; | ||
103 | |||
79 | if (!have_cpuid_p()) | 104 | if (!have_cpuid_p()) |
80 | return; | 105 | return; |
81 | 106 | ||
@@ -96,10 +121,22 @@ void __init load_ucode_bsp(void) | |||
96 | } | 121 | } |
97 | } | 122 | } |
98 | 123 | ||
124 | static bool check_loader_disabled_ap(void) | ||
125 | { | ||
126 | #ifdef CONFIG_X86_32 | ||
127 | return __pa_nodebug(dis_ucode_ldr); | ||
128 | #else | ||
129 | return dis_ucode_ldr; | ||
130 | #endif | ||
131 | } | ||
132 | |||
99 | void load_ucode_ap(void) | 133 | void load_ucode_ap(void) |
100 | { | 134 | { |
101 | int vendor, x86; | 135 | int vendor, x86; |
102 | 136 | ||
137 | if (check_loader_disabled_ap()) | ||
138 | return; | ||
139 | |||
103 | if (!have_cpuid_p()) | 140 | if (!have_cpuid_p()) |
104 | return; | 141 | return; |
105 | 142 | ||
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index eabcb6e6a900..4d4f96a27638 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile | |||
@@ -16,7 +16,7 @@ clean-files := inat-tables.c | |||
16 | 16 | ||
17 | obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o | 17 | obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o |
18 | 18 | ||
19 | lib-y := delay.o misc.o | 19 | lib-y := delay.o misc.o cmdline.o |
20 | lib-y += thunk_$(BITS).o | 20 | lib-y += thunk_$(BITS).o |
21 | lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o | 21 | lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o |
22 | lib-y += memcpy_$(BITS).o | 22 | lib-y += memcpy_$(BITS).o |
diff --git a/arch/x86/lib/cmdline.c b/arch/x86/lib/cmdline.c new file mode 100644 index 000000000000..422db000d727 --- /dev/null +++ b/arch/x86/lib/cmdline.c | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * This file is part of the Linux kernel, and is made available under | ||
3 | * the terms of the GNU General Public License version 2. | ||
4 | * | ||
5 | * Misc librarized functions for cmdline poking. | ||
6 | */ | ||
7 | #include <linux/kernel.h> | ||
8 | #include <linux/string.h> | ||
9 | #include <linux/ctype.h> | ||
10 | #include <asm/setup.h> | ||
11 | |||
12 | static inline int myisspace(u8 c) | ||
13 | { | ||
14 | return c <= ' '; /* Close enough approximation */ | ||
15 | } | ||
16 | |||
17 | /** | ||
18 | * Find a boolean option (like quiet,noapic,nosmp....) | ||
19 | * | ||
20 | * @cmdline: the cmdline string | ||
21 | * @option: option string to look for | ||
22 | * | ||
23 | * Returns the position of that @option (starts counting with 1) | ||
24 | * or 0 on not found. | ||
25 | */ | ||
26 | int cmdline_find_option_bool(const char *cmdline, const char *option) | ||
27 | { | ||
28 | char c; | ||
29 | int len, pos = 0, wstart = 0; | ||
30 | const char *opptr = NULL; | ||
31 | enum { | ||
32 | st_wordstart = 0, /* Start of word/after whitespace */ | ||
33 | st_wordcmp, /* Comparing this word */ | ||
34 | st_wordskip, /* Miscompare, skip */ | ||
35 | } state = st_wordstart; | ||
36 | |||
37 | if (!cmdline) | ||
38 | return -1; /* No command line */ | ||
39 | |||
40 | len = min_t(int, strlen(cmdline), COMMAND_LINE_SIZE); | ||
41 | if (!len) | ||
42 | return 0; | ||
43 | |||
44 | while (len--) { | ||
45 | c = *(char *)cmdline++; | ||
46 | pos++; | ||
47 | |||
48 | switch (state) { | ||
49 | case st_wordstart: | ||
50 | if (!c) | ||
51 | return 0; | ||
52 | else if (myisspace(c)) | ||
53 | break; | ||
54 | |||
55 | state = st_wordcmp; | ||
56 | opptr = option; | ||
57 | wstart = pos; | ||
58 | /* fall through */ | ||
59 | |||
60 | case st_wordcmp: | ||
61 | if (!*opptr) | ||
62 | if (!c || myisspace(c)) | ||
63 | return wstart; | ||
64 | else | ||
65 | state = st_wordskip; | ||
66 | else if (!c) | ||
67 | return 0; | ||
68 | else if (c != *opptr++) | ||
69 | state = st_wordskip; | ||
70 | else if (!len) /* last word and is matching */ | ||
71 | return wstart; | ||
72 | break; | ||
73 | |||
74 | case st_wordskip: | ||
75 | if (!c) | ||
76 | return 0; | ||
77 | else if (myisspace(c)) | ||
78 | state = st_wordstart; | ||
79 | break; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | return 0; /* Buffer overrun */ | ||
84 | } | ||