diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-02 17:08:58 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-02 17:08:58 -0500 |
commit | 34e00accf612bc5448ae709245c2b408edf39f46 (patch) | |
tree | 12ec37e6c6484562d4c5a0e8657736cf4e4e33e4 | |
parent | 891aa1e0f13c3aaa756c69b343d6ab6f3357009b (diff) | |
parent | 0becc0ae5b42828785b589f686725ff5bc3b9b25 (diff) |
Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Ingo Molnar:
"Misc fixes:
- two microcode loader fixes
- two FPU xstate handling fixes
- an MCE timer handling related crash fix"
* 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/mce: Make timer handling more robust
x86/microcode: Do not access the initrd after it has been freed
x86/fpu/xstate: Fix xcomp_bv in XSAVES header
x86/fpu: Set the xcomp_bv when we fake up a XSAVES area
x86/microcode/intel: Drop stashed AP patch pointer optimization
-rw-r--r-- | arch/x86/include/asm/microcode.h | 1 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce.c | 31 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/microcode/amd.c | 5 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/microcode/core.c | 22 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/microcode/intel.c | 9 | ||||
-rw-r--r-- | arch/x86/kernel/fpu/core.c | 4 |
6 files changed, 37 insertions, 35 deletions
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h index 38711df3bcb5..2266f864b747 100644 --- a/arch/x86/include/asm/microcode.h +++ b/arch/x86/include/asm/microcode.h | |||
@@ -140,6 +140,7 @@ extern void __init load_ucode_bsp(void); | |||
140 | extern void load_ucode_ap(void); | 140 | extern void load_ucode_ap(void); |
141 | void reload_early_microcode(void); | 141 | void reload_early_microcode(void); |
142 | extern bool get_builtin_firmware(struct cpio_data *cd, const char *name); | 142 | extern bool get_builtin_firmware(struct cpio_data *cd, const char *name); |
143 | extern bool initrd_gone; | ||
143 | #else | 144 | #else |
144 | static inline int __init microcode_init(void) { return 0; }; | 145 | static inline int __init microcode_init(void) { return 0; }; |
145 | static inline void __init load_ucode_bsp(void) { } | 146 | static inline void __init load_ucode_bsp(void) { } |
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 00ef43233e03..537c6647d84c 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c | |||
@@ -1373,20 +1373,15 @@ static unsigned long mce_adjust_timer_default(unsigned long interval) | |||
1373 | 1373 | ||
1374 | static unsigned long (*mce_adjust_timer)(unsigned long interval) = mce_adjust_timer_default; | 1374 | static unsigned long (*mce_adjust_timer)(unsigned long interval) = mce_adjust_timer_default; |
1375 | 1375 | ||
1376 | static void __restart_timer(struct timer_list *t, unsigned long interval) | 1376 | static void __start_timer(struct timer_list *t, unsigned long interval) |
1377 | { | 1377 | { |
1378 | unsigned long when = jiffies + interval; | 1378 | unsigned long when = jiffies + interval; |
1379 | unsigned long flags; | 1379 | unsigned long flags; |
1380 | 1380 | ||
1381 | local_irq_save(flags); | 1381 | local_irq_save(flags); |
1382 | 1382 | ||
1383 | if (timer_pending(t)) { | 1383 | if (!timer_pending(t) || time_before(when, t->expires)) |
1384 | if (time_before(when, t->expires)) | 1384 | mod_timer(t, round_jiffies(when)); |
1385 | mod_timer(t, when); | ||
1386 | } else { | ||
1387 | t->expires = round_jiffies(when); | ||
1388 | add_timer_on(t, smp_processor_id()); | ||
1389 | } | ||
1390 | 1385 | ||
1391 | local_irq_restore(flags); | 1386 | local_irq_restore(flags); |
1392 | } | 1387 | } |
@@ -1421,7 +1416,7 @@ static void mce_timer_fn(unsigned long data) | |||
1421 | 1416 | ||
1422 | done: | 1417 | done: |
1423 | __this_cpu_write(mce_next_interval, iv); | 1418 | __this_cpu_write(mce_next_interval, iv); |
1424 | __restart_timer(t, iv); | 1419 | __start_timer(t, iv); |
1425 | } | 1420 | } |
1426 | 1421 | ||
1427 | /* | 1422 | /* |
@@ -1432,7 +1427,7 @@ void mce_timer_kick(unsigned long interval) | |||
1432 | struct timer_list *t = this_cpu_ptr(&mce_timer); | 1427 | struct timer_list *t = this_cpu_ptr(&mce_timer); |
1433 | unsigned long iv = __this_cpu_read(mce_next_interval); | 1428 | unsigned long iv = __this_cpu_read(mce_next_interval); |
1434 | 1429 | ||
1435 | __restart_timer(t, interval); | 1430 | __start_timer(t, interval); |
1436 | 1431 | ||
1437 | if (interval < iv) | 1432 | if (interval < iv) |
1438 | __this_cpu_write(mce_next_interval, interval); | 1433 | __this_cpu_write(mce_next_interval, interval); |
@@ -1779,17 +1774,15 @@ static void __mcheck_cpu_clear_vendor(struct cpuinfo_x86 *c) | |||
1779 | } | 1774 | } |
1780 | } | 1775 | } |
1781 | 1776 | ||
1782 | static void mce_start_timer(unsigned int cpu, struct timer_list *t) | 1777 | static void mce_start_timer(struct timer_list *t) |
1783 | { | 1778 | { |
1784 | unsigned long iv = check_interval * HZ; | 1779 | unsigned long iv = check_interval * HZ; |
1785 | 1780 | ||
1786 | if (mca_cfg.ignore_ce || !iv) | 1781 | if (mca_cfg.ignore_ce || !iv) |
1787 | return; | 1782 | return; |
1788 | 1783 | ||
1789 | per_cpu(mce_next_interval, cpu) = iv; | 1784 | this_cpu_write(mce_next_interval, iv); |
1790 | 1785 | __start_timer(t, iv); | |
1791 | t->expires = round_jiffies(jiffies + iv); | ||
1792 | add_timer_on(t, cpu); | ||
1793 | } | 1786 | } |
1794 | 1787 | ||
1795 | static void __mcheck_cpu_setup_timer(void) | 1788 | static void __mcheck_cpu_setup_timer(void) |
@@ -1806,7 +1799,7 @@ static void __mcheck_cpu_init_timer(void) | |||
1806 | unsigned int cpu = smp_processor_id(); | 1799 | unsigned int cpu = smp_processor_id(); |
1807 | 1800 | ||
1808 | setup_pinned_timer(t, mce_timer_fn, cpu); | 1801 | setup_pinned_timer(t, mce_timer_fn, cpu); |
1809 | mce_start_timer(cpu, t); | 1802 | mce_start_timer(t); |
1810 | } | 1803 | } |
1811 | 1804 | ||
1812 | /* Handle unconfigured int18 (should never happen) */ | 1805 | /* Handle unconfigured int18 (should never happen) */ |
@@ -2566,7 +2559,7 @@ static int mce_cpu_dead(unsigned int cpu) | |||
2566 | 2559 | ||
2567 | static int mce_cpu_online(unsigned int cpu) | 2560 | static int mce_cpu_online(unsigned int cpu) |
2568 | { | 2561 | { |
2569 | struct timer_list *t = &per_cpu(mce_timer, cpu); | 2562 | struct timer_list *t = this_cpu_ptr(&mce_timer); |
2570 | int ret; | 2563 | int ret; |
2571 | 2564 | ||
2572 | mce_device_create(cpu); | 2565 | mce_device_create(cpu); |
@@ -2577,13 +2570,13 @@ static int mce_cpu_online(unsigned int cpu) | |||
2577 | return ret; | 2570 | return ret; |
2578 | } | 2571 | } |
2579 | mce_reenable_cpu(); | 2572 | mce_reenable_cpu(); |
2580 | mce_start_timer(cpu, t); | 2573 | mce_start_timer(t); |
2581 | return 0; | 2574 | return 0; |
2582 | } | 2575 | } |
2583 | 2576 | ||
2584 | static int mce_cpu_pre_down(unsigned int cpu) | 2577 | static int mce_cpu_pre_down(unsigned int cpu) |
2585 | { | 2578 | { |
2586 | struct timer_list *t = &per_cpu(mce_timer, cpu); | 2579 | struct timer_list *t = this_cpu_ptr(&mce_timer); |
2587 | 2580 | ||
2588 | mce_disable_cpu(); | 2581 | mce_disable_cpu(); |
2589 | del_timer_sync(t); | 2582 | del_timer_sync(t); |
diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index 6a31e2691f3a..079e81733a58 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c | |||
@@ -384,8 +384,9 @@ void load_ucode_amd_ap(unsigned int family) | |||
384 | reget: | 384 | reget: |
385 | if (!get_builtin_microcode(&cp, family)) { | 385 | if (!get_builtin_microcode(&cp, family)) { |
386 | #ifdef CONFIG_BLK_DEV_INITRD | 386 | #ifdef CONFIG_BLK_DEV_INITRD |
387 | cp = find_cpio_data(ucode_path, (void *)initrd_start, | 387 | if (!initrd_gone) |
388 | initrd_end - initrd_start, NULL); | 388 | cp = find_cpio_data(ucode_path, (void *)initrd_start, |
389 | initrd_end - initrd_start, NULL); | ||
389 | #endif | 390 | #endif |
390 | if (!(cp.data && cp.size)) { | 391 | if (!(cp.data && cp.size)) { |
391 | /* | 392 | /* |
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 2af69d27da62..73102d932760 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c | |||
@@ -46,6 +46,8 @@ | |||
46 | static struct microcode_ops *microcode_ops; | 46 | static struct microcode_ops *microcode_ops; |
47 | static bool dis_ucode_ldr = true; | 47 | static bool dis_ucode_ldr = true; |
48 | 48 | ||
49 | bool initrd_gone; | ||
50 | |||
49 | LIST_HEAD(microcode_cache); | 51 | LIST_HEAD(microcode_cache); |
50 | 52 | ||
51 | /* | 53 | /* |
@@ -190,21 +192,24 @@ void load_ucode_ap(void) | |||
190 | static int __init save_microcode_in_initrd(void) | 192 | static int __init save_microcode_in_initrd(void) |
191 | { | 193 | { |
192 | struct cpuinfo_x86 *c = &boot_cpu_data; | 194 | struct cpuinfo_x86 *c = &boot_cpu_data; |
195 | int ret = -EINVAL; | ||
193 | 196 | ||
194 | switch (c->x86_vendor) { | 197 | switch (c->x86_vendor) { |
195 | case X86_VENDOR_INTEL: | 198 | case X86_VENDOR_INTEL: |
196 | if (c->x86 >= 6) | 199 | if (c->x86 >= 6) |
197 | return save_microcode_in_initrd_intel(); | 200 | ret = save_microcode_in_initrd_intel(); |
198 | break; | 201 | break; |
199 | case X86_VENDOR_AMD: | 202 | case X86_VENDOR_AMD: |
200 | if (c->x86 >= 0x10) | 203 | if (c->x86 >= 0x10) |
201 | return save_microcode_in_initrd_amd(c->x86); | 204 | ret = save_microcode_in_initrd_amd(c->x86); |
202 | break; | 205 | break; |
203 | default: | 206 | default: |
204 | break; | 207 | break; |
205 | } | 208 | } |
206 | 209 | ||
207 | return -EINVAL; | 210 | initrd_gone = true; |
211 | |||
212 | return ret; | ||
208 | } | 213 | } |
209 | 214 | ||
210 | struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa) | 215 | struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa) |
@@ -247,9 +252,16 @@ struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa) | |||
247 | * has the virtual address of the beginning of the initrd. It also | 252 | * has the virtual address of the beginning of the initrd. It also |
248 | * possibly relocates the ramdisk. In either case, initrd_start contains | 253 | * possibly relocates the ramdisk. In either case, initrd_start contains |
249 | * the updated address so use that instead. | 254 | * the updated address so use that instead. |
255 | * | ||
256 | * initrd_gone is for the hotplug case where we've thrown out initrd | ||
257 | * already. | ||
250 | */ | 258 | */ |
251 | if (!use_pa && initrd_start) | 259 | if (!use_pa) { |
252 | start = initrd_start; | 260 | if (initrd_gone) |
261 | return (struct cpio_data){ NULL, 0, "" }; | ||
262 | if (initrd_start) | ||
263 | start = initrd_start; | ||
264 | } | ||
253 | 265 | ||
254 | return find_cpio_data(path, (void *)start, size, NULL); | 266 | return find_cpio_data(path, (void *)start, size, NULL); |
255 | #else /* !CONFIG_BLK_DEV_INITRD */ | 267 | #else /* !CONFIG_BLK_DEV_INITRD */ |
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 3f329b74e040..8325d8a09ab0 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c | |||
@@ -41,7 +41,7 @@ | |||
41 | 41 | ||
42 | static const char ucode_path[] = "kernel/x86/microcode/GenuineIntel.bin"; | 42 | static const char ucode_path[] = "kernel/x86/microcode/GenuineIntel.bin"; |
43 | 43 | ||
44 | /* Current microcode patch used in early patching */ | 44 | /* Current microcode patch used in early patching on the APs. */ |
45 | struct microcode_intel *intel_ucode_patch; | 45 | struct microcode_intel *intel_ucode_patch; |
46 | 46 | ||
47 | static inline bool cpu_signatures_match(unsigned int s1, unsigned int p1, | 47 | static inline bool cpu_signatures_match(unsigned int s1, unsigned int p1, |
@@ -607,12 +607,6 @@ int __init save_microcode_in_initrd_intel(void) | |||
607 | struct ucode_cpu_info uci; | 607 | struct ucode_cpu_info uci; |
608 | struct cpio_data cp; | 608 | struct cpio_data cp; |
609 | 609 | ||
610 | /* | ||
611 | * AP loading didn't find any microcode patch, no need to save anything. | ||
612 | */ | ||
613 | if (!intel_ucode_patch || IS_ERR(intel_ucode_patch)) | ||
614 | return 0; | ||
615 | |||
616 | if (!load_builtin_intel_microcode(&cp)) | 610 | if (!load_builtin_intel_microcode(&cp)) |
617 | cp = find_microcode_in_initrd(ucode_path, false); | 611 | cp = find_microcode_in_initrd(ucode_path, false); |
618 | 612 | ||
@@ -628,7 +622,6 @@ int __init save_microcode_in_initrd_intel(void) | |||
628 | return 0; | 622 | return 0; |
629 | } | 623 | } |
630 | 624 | ||
631 | |||
632 | /* | 625 | /* |
633 | * @res_patch, output: a pointer to the patch we found. | 626 | * @res_patch, output: a pointer to the patch we found. |
634 | */ | 627 | */ |
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index e4e97a5355ce..de7234401275 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <asm/fpu/regset.h> | 9 | #include <asm/fpu/regset.h> |
10 | #include <asm/fpu/signal.h> | 10 | #include <asm/fpu/signal.h> |
11 | #include <asm/fpu/types.h> | 11 | #include <asm/fpu/types.h> |
12 | #include <asm/fpu/xstate.h> | ||
12 | #include <asm/traps.h> | 13 | #include <asm/traps.h> |
13 | 14 | ||
14 | #include <linux/hardirq.h> | 15 | #include <linux/hardirq.h> |
@@ -183,7 +184,8 @@ void fpstate_init(union fpregs_state *state) | |||
183 | * it will #GP. Make sure it is replaced after the memset(). | 184 | * it will #GP. Make sure it is replaced after the memset(). |
184 | */ | 185 | */ |
185 | if (static_cpu_has(X86_FEATURE_XSAVES)) | 186 | if (static_cpu_has(X86_FEATURE_XSAVES)) |
186 | state->xsave.header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT; | 187 | state->xsave.header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT | |
188 | xfeatures_mask; | ||
187 | 189 | ||
188 | if (static_cpu_has(X86_FEATURE_FXSR)) | 190 | if (static_cpu_has(X86_FEATURE_FXSR)) |
189 | fpstate_init_fxstate(&state->fxsave); | 191 | fpstate_init_fxstate(&state->fxsave); |