diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-03 18:44:50 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-03 18:44:50 -0400 |
| commit | c33c40549ef8f080d8aa0545d043d9f01bf804a9 (patch) | |
| tree | 0cf57d089c915307895baa484ce2bfa827248649 | |
| parent | e30c631be68b3885aee1b813c427354c950f4146 (diff) | |
| parent | 65cef1311d5d212fd3d48a43678536dc878ca288 (diff) | |
Merge branch 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip into next
Pull x86 microcode changes from Ingo Molnar:
"A microcode-debugging boot flag plus related refactoring"
* 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86, microcode: Add a disable chicken bit
x86, boot: Carve out early cmdline parsing function
| -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 | |||
