mirror of
https://github.com/torvalds/linux.git
synced 2024-12-26 04:42:12 +00:00
6f6060a5c9
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: dd84441a79
("x86/speculation: Use IBRS if available before calling into firmware")
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: stable@vger.kernel.org
Cc: David Woodhouse <dwmw@amazon.co.uk>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: x86@kernel.org
Cc: David Woodhouse <dwmw@amazon.co.uk>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Link: https://lkml.kernel.org/r/20180709133534.5963-1-ville.syrjala@linux.intel.com
75 lines
1.7 KiB
C
75 lines
1.7 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Machine specific APM BIOS functions for generic.
|
|
* Split out from apm.c by Osamu Tomita <tomita@cinet.co.jp>
|
|
*/
|
|
|
|
#ifndef _ASM_X86_MACH_DEFAULT_APM_H
|
|
#define _ASM_X86_MACH_DEFAULT_APM_H
|
|
|
|
#ifdef APM_ZERO_SEGS
|
|
# define APM_DO_ZERO_SEGS \
|
|
"pushl %%ds\n\t" \
|
|
"pushl %%es\n\t" \
|
|
"xorl %%edx, %%edx\n\t" \
|
|
"mov %%dx, %%ds\n\t" \
|
|
"mov %%dx, %%es\n\t" \
|
|
"mov %%dx, %%fs\n\t" \
|
|
"mov %%dx, %%gs\n\t"
|
|
# define APM_DO_POP_SEGS \
|
|
"popl %%es\n\t" \
|
|
"popl %%ds\n\t"
|
|
#else
|
|
# define APM_DO_ZERO_SEGS
|
|
# define APM_DO_POP_SEGS
|
|
#endif
|
|
|
|
static inline void apm_bios_call_asm(u32 func, u32 ebx_in, u32 ecx_in,
|
|
u32 *eax, u32 *ebx, u32 *ecx,
|
|
u32 *edx, u32 *esi)
|
|
{
|
|
/*
|
|
* N.B. We do NOT need a cld after the BIOS call
|
|
* because we always save and restore the flags.
|
|
*/
|
|
__asm__ __volatile__(APM_DO_ZERO_SEGS
|
|
"pushl %%edi\n\t"
|
|
"pushl %%ebp\n\t"
|
|
"lcall *%%cs:apm_bios_entry\n\t"
|
|
"setc %%al\n\t"
|
|
"popl %%ebp\n\t"
|
|
"popl %%edi\n\t"
|
|
APM_DO_POP_SEGS
|
|
: "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx),
|
|
"=S" (*esi)
|
|
: "a" (func), "b" (ebx_in), "c" (ecx_in)
|
|
: "memory", "cc");
|
|
}
|
|
|
|
static inline bool apm_bios_call_simple_asm(u32 func, u32 ebx_in,
|
|
u32 ecx_in, u32 *eax)
|
|
{
|
|
int cx, dx, si;
|
|
bool error;
|
|
|
|
/*
|
|
* N.B. We do NOT need a cld after the BIOS call
|
|
* because we always save and restore the flags.
|
|
*/
|
|
__asm__ __volatile__(APM_DO_ZERO_SEGS
|
|
"pushl %%edi\n\t"
|
|
"pushl %%ebp\n\t"
|
|
"lcall *%%cs:apm_bios_entry\n\t"
|
|
"setc %%bl\n\t"
|
|
"popl %%ebp\n\t"
|
|
"popl %%edi\n\t"
|
|
APM_DO_POP_SEGS
|
|
: "=a" (*eax), "=b" (error), "=c" (cx), "=d" (dx),
|
|
"=S" (si)
|
|
: "a" (func), "b" (ebx_in), "c" (ecx_in)
|
|
: "memory", "cc");
|
|
return error;
|
|
}
|
|
|
|
#endif /* _ASM_X86_MACH_DEFAULT_APM_H */
|