3.16.61-rc1 review patch.  If anyone has any objections, please let me know.

------------------

From: Ville Syrjälä <ville.syrj...@linux.intel.com>

commit 6f6060a5c9cc76fdbc22748264e6aa3779ec2427 upstream.

APM_DO_POP_SEGS does not restore fs/gs which were zeroed by
APM_DO_ZERO_SEGS. Trying to access __preempt_count with
zeroed fs doesn't really work.

Move the ibrs call outside the APM_DO_SAVE_SEGS/APM_DO_RESTORE_SEGS
invocations so that fs is actually restored before calling
preempt_enable().

Fixes the following sort of oopses:
[    0.313581] general protection fault: 0000 [#1] PREEMPT SMP
[    0.313803] Modules linked in:
[    0.314040] CPU: 0 PID: 268 Comm: kapmd Not tainted 
4.16.0-rc1-triton-bisect-00090-gdd84441a7971 #19
[    0.316161] EIP: __apm_bios_call_simple+0xc8/0x170
[    0.316161] EFLAGS: 00210016 CPU: 0
[    0.316161] EAX: 00000102 EBX: 00000000 ECX: 00000102 EDX: 00000000
[    0.316161] ESI: 0000530e EDI: dea95f64 EBP: dea95f18 ESP: dea95ef0
[    0.316161]  DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068
[    0.316161] CR0: 80050033 CR2: 00000000 CR3: 015d3000 CR4: 000006d0
[    0.316161] Call Trace:
[    0.316161]  ? cpumask_weight.constprop.15+0x20/0x20
[    0.316161]  on_cpu0+0x44/0x70
[    0.316161]  apm+0x54e/0x720
[    0.316161]  ? __switch_to_asm+0x26/0x40
[    0.316161]  ? __schedule+0x17d/0x590
[    0.316161]  kthread+0xc0/0xf0
[    0.316161]  ? proc_apm_show+0x150/0x150
[    0.316161]  ? kthread_create_worker_on_cpu+0x20/0x20
[    0.316161]  ret_from_fork+0x2e/0x38
[    0.316161] Code: da 8e c2 8e e2 8e ea 57 55 2e ff 1d e0 bb 5d b1 0f 92 c3 
5d 5f 07 1f 89 47 0c 90 8d b4 26 00 00 00 00 90 8d b4 26 00 00 00 00 90 <64> ff 
0d 84 16 5c b1 74 7f 8b 45 dc 8e e0 8b 45 d8 8e e8 8b 45
[    0.316161] EIP: __apm_bios_call_simple+0xc8/0x170 SS:ESP: 0068:dea95ef0
[    0.316161] ---[ end trace 656253db2deaa12c ]---

Fixes: dd84441a7971 ("x86/speculation: Use IBRS if available before calling 
into firmware")
Signed-off-by: Ville Syrjälä <ville.syrj...@linux.intel.com>
Signed-off-by: Thomas Gleixner <t...@linutronix.de>
Cc:  David Woodhouse <d...@amazon.co.uk>
Cc:  "H. Peter Anvin" <h...@zytor.com>
Cc:  x...@kernel.org
Cc: David Woodhouse <d...@amazon.co.uk>
Cc: "H. Peter Anvin" <h...@zytor.com>
Link: 
https://lkml.kernel.org/r/20180709133534.5963-1-ville.syrj...@linux.intel.com
Signed-off-by: Ben Hutchings <b...@decadent.org.uk>
---
 arch/x86/include/asm/apm.h | 6 ------
 arch/x86/kernel/apm_32.c   | 5 +++++
 2 files changed, 5 insertions(+), 6 deletions(-)

--- a/arch/x86/include/asm/apm.h
+++ b/arch/x86/include/asm/apm.h
@@ -6,8 +6,6 @@
 #ifndef _ASM_X86_MACH_DEFAULT_APM_H
 #define _ASM_X86_MACH_DEFAULT_APM_H
 
-#include <asm/nospec-branch.h>
-
 #ifdef APM_ZERO_SEGS
 #      define APM_DO_ZERO_SEGS \
                "pushl %%ds\n\t" \
@@ -33,7 +31,6 @@ static inline void apm_bios_call_asm(u32
         * N.B. We do NOT need a cld after the BIOS call
         * because we always save and restore the flags.
         */
-       firmware_restrict_branch_speculation_start();
        __asm__ __volatile__(APM_DO_ZERO_SEGS
                "pushl %%edi\n\t"
                "pushl %%ebp\n\t"
@@ -46,7 +43,6 @@ static inline void apm_bios_call_asm(u32
                  "=S" (*esi)
                : "a" (func), "b" (ebx_in), "c" (ecx_in)
                : "memory", "cc");
-       firmware_restrict_branch_speculation_end();
 }
 
 static inline u8 apm_bios_call_simple_asm(u32 func, u32 ebx_in,
@@ -59,7 +55,6 @@ static inline u8 apm_bios_call_simple_as
         * N.B. We do NOT need a cld after the BIOS call
         * because we always save and restore the flags.
         */
-       firmware_restrict_branch_speculation_start();
        __asm__ __volatile__(APM_DO_ZERO_SEGS
                "pushl %%edi\n\t"
                "pushl %%ebp\n\t"
@@ -72,7 +67,6 @@ static inline u8 apm_bios_call_simple_as
                  "=S" (si)
                : "a" (func), "b" (ebx_in), "c" (ecx_in)
                : "memory", "cc");
-       firmware_restrict_branch_speculation_end();
        return error;
 }
 
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -239,6 +239,7 @@
 #include <asm/olpc.h>
 #include <asm/paravirt.h>
 #include <asm/reboot.h>
+#include <asm/nospec-branch.h>
 
 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
 extern int (*console_blank_hook)(int);
@@ -614,11 +615,13 @@ static long __apm_bios_call(void *_call)
        gdt[0x40 / 8] = bad_bios_desc;
 
        apm_irq_save(flags);
+       firmware_restrict_branch_speculation_start();
        APM_DO_SAVE_SEGS;
        apm_bios_call_asm(call->func, call->ebx, call->ecx,
                          &call->eax, &call->ebx, &call->ecx, &call->edx,
                          &call->esi);
        APM_DO_RESTORE_SEGS;
+       firmware_restrict_branch_speculation_end();
        apm_irq_restore(flags);
        gdt[0x40 / 8] = save_desc_40;
        put_cpu();
@@ -690,10 +693,12 @@ static long __apm_bios_call_simple(void
        gdt[0x40 / 8] = bad_bios_desc;
 
        apm_irq_save(flags);
+       firmware_restrict_branch_speculation_start();
        APM_DO_SAVE_SEGS;
        error = apm_bios_call_simple_asm(call->func, call->ebx, call->ecx,
                                         &call->eax);
        APM_DO_RESTORE_SEGS;
+       firmware_restrict_branch_speculation_end();
        apm_irq_restore(flags);
        gdt[0x40 / 8] = save_desc_40;
        put_cpu();

Reply via email to