2008-10-22 22:26:29 -07:00
|
|
|
#ifndef _ASM_X86_ASM_H
|
|
|
|
#define _ASM_X86_ASM_H
|
2008-01-30 13:30:06 +01:00
|
|
|
|
2008-06-16 16:08:17 -07:00
|
|
|
#ifdef __ASSEMBLY__
|
|
|
|
# define __ASM_FORM(x) x
|
2013-08-29 21:13:04 +02:00
|
|
|
# define __ASM_FORM_RAW(x) x
|
2011-07-19 13:00:45 +01:00
|
|
|
# define __ASM_FORM_COMMA(x) x,
|
2008-06-16 16:08:17 -07:00
|
|
|
#else
|
|
|
|
# define __ASM_FORM(x) " " #x " "
|
2013-08-29 21:13:04 +02:00
|
|
|
# define __ASM_FORM_RAW(x) #x
|
2011-07-19 13:00:45 +01:00
|
|
|
# define __ASM_FORM_COMMA(x) " " #x ","
|
2008-06-16 16:08:17 -07:00
|
|
|
#endif
|
2008-01-30 13:31:26 +01:00
|
|
|
|
x86/asm: Fix inline asm call constraints for GCC 4.4
commit 520a13c530aeb5f63e011d668c42db1af19ed349 upstream.
The kernel test bot (run by Xiaolong Ye) reported that the following commit:
f5caf621ee35 ("x86/asm: Fix inline asm call constraints for Clang")
is causing double faults in a kernel compiled with GCC 4.4.
Linus subsequently diagnosed the crash pattern and the buggy commit and found that
the issue is with this code:
register unsigned int __asm_call_sp asm("esp");
#define ASM_CALL_CONSTRAINT "+r" (__asm_call_sp)
Even on a 64-bit kernel, it's using ESP instead of RSP. That causes GCC
to produce the following bogus code:
ffffffff8147461d: 89 e0 mov %esp,%eax
ffffffff8147461f: 4c 89 f7 mov %r14,%rdi
ffffffff81474622: 4c 89 fe mov %r15,%rsi
ffffffff81474625: ba 20 00 00 00 mov $0x20,%edx
ffffffff8147462a: 89 c4 mov %eax,%esp
ffffffff8147462c: e8 bf 52 05 00 callq ffffffff814c98f0 <copy_user_generic_unrolled>
Despite the absurdity of it backing up and restoring the stack pointer
for no reason, the bug is actually the fact that it's only backing up
and restoring the lower 32 bits of the stack pointer. The upper 32 bits
are getting cleared out, corrupting the stack pointer.
So change the '__asm_call_sp' register variable to be associated with
the actual full-size stack pointer.
This also requires changing the __ASM_SEL() macro to be based on the
actual compiled arch size, rather than the CONFIG value, because
CONFIG_X86_64 compiles some files with '-m32' (e.g., realmode and vdso).
Otherwise Clang fails to build the kernel because it complains about the
use of a 64-bit register (RSP) in a 32-bit file.
Reported-and-Bisected-and-Tested-by: kernel test robot <xiaolong.ye@intel.com>
Diagnosed-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Alexander Potapenko <glider@google.com>
Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Dmitriy Vyukov <dvyukov@google.com>
Cc: LKP <lkp@01.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Matthias Kaehlcke <mka@chromium.org>
Cc: Miguel Bernal Marin <miguel.bernal.marin@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Fixes: f5caf621ee35 ("x86/asm: Fix inline asm call constraints for Clang")
Link: http://lkml.kernel.org/r/20170928215826.6sdpmwtkiydiytim@treble
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Matthias Kaehlcke <mka@chromium.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-09-28 16:58:26 -05:00
|
|
|
#ifndef __x86_64__
|
|
|
|
/* 32 bit */
|
2008-06-16 16:08:17 -07:00
|
|
|
# define __ASM_SEL(a,b) __ASM_FORM(a)
|
2013-08-29 21:13:04 +02:00
|
|
|
# define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(a)
|
2008-01-30 13:30:06 +01:00
|
|
|
#else
|
x86/asm: Fix inline asm call constraints for GCC 4.4
commit 520a13c530aeb5f63e011d668c42db1af19ed349 upstream.
The kernel test bot (run by Xiaolong Ye) reported that the following commit:
f5caf621ee35 ("x86/asm: Fix inline asm call constraints for Clang")
is causing double faults in a kernel compiled with GCC 4.4.
Linus subsequently diagnosed the crash pattern and the buggy commit and found that
the issue is with this code:
register unsigned int __asm_call_sp asm("esp");
#define ASM_CALL_CONSTRAINT "+r" (__asm_call_sp)
Even on a 64-bit kernel, it's using ESP instead of RSP. That causes GCC
to produce the following bogus code:
ffffffff8147461d: 89 e0 mov %esp,%eax
ffffffff8147461f: 4c 89 f7 mov %r14,%rdi
ffffffff81474622: 4c 89 fe mov %r15,%rsi
ffffffff81474625: ba 20 00 00 00 mov $0x20,%edx
ffffffff8147462a: 89 c4 mov %eax,%esp
ffffffff8147462c: e8 bf 52 05 00 callq ffffffff814c98f0 <copy_user_generic_unrolled>
Despite the absurdity of it backing up and restoring the stack pointer
for no reason, the bug is actually the fact that it's only backing up
and restoring the lower 32 bits of the stack pointer. The upper 32 bits
are getting cleared out, corrupting the stack pointer.
So change the '__asm_call_sp' register variable to be associated with
the actual full-size stack pointer.
This also requires changing the __ASM_SEL() macro to be based on the
actual compiled arch size, rather than the CONFIG value, because
CONFIG_X86_64 compiles some files with '-m32' (e.g., realmode and vdso).
Otherwise Clang fails to build the kernel because it complains about the
use of a 64-bit register (RSP) in a 32-bit file.
Reported-and-Bisected-and-Tested-by: kernel test robot <xiaolong.ye@intel.com>
Diagnosed-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Alexander Potapenko <glider@google.com>
Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Dmitriy Vyukov <dvyukov@google.com>
Cc: LKP <lkp@01.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Matthias Kaehlcke <mka@chromium.org>
Cc: Miguel Bernal Marin <miguel.bernal.marin@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Fixes: f5caf621ee35 ("x86/asm: Fix inline asm call constraints for Clang")
Link: http://lkml.kernel.org/r/20170928215826.6sdpmwtkiydiytim@treble
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Matthias Kaehlcke <mka@chromium.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-09-28 16:58:26 -05:00
|
|
|
/* 64 bit */
|
2008-06-16 16:08:17 -07:00
|
|
|
# define __ASM_SEL(a,b) __ASM_FORM(b)
|
2013-08-29 21:13:04 +02:00
|
|
|
# define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(b)
|
2008-06-16 16:08:17 -07:00
|
|
|
#endif
|
2008-01-30 13:30:06 +01:00
|
|
|
|
2011-07-19 12:59:51 +01:00
|
|
|
#define __ASM_SIZE(inst, ...) __ASM_SEL(inst##l##__VA_ARGS__, \
|
|
|
|
inst##q##__VA_ARGS__)
|
2013-08-29 21:13:04 +02:00
|
|
|
#define __ASM_REG(reg) __ASM_SEL_RAW(e##reg, r##reg)
|
2008-01-30 13:30:06 +01:00
|
|
|
|
2008-06-16 16:08:17 -07:00
|
|
|
#define _ASM_PTR __ASM_SEL(.long, .quad)
|
|
|
|
#define _ASM_ALIGN __ASM_SEL(.balign 4, .balign 8)
|
2008-01-30 13:31:26 +01:00
|
|
|
|
2008-08-18 18:13:33 -07:00
|
|
|
#define _ASM_MOV __ASM_SIZE(mov)
|
2008-06-16 16:08:17 -07:00
|
|
|
#define _ASM_INC __ASM_SIZE(inc)
|
|
|
|
#define _ASM_DEC __ASM_SIZE(dec)
|
|
|
|
#define _ASM_ADD __ASM_SIZE(add)
|
|
|
|
#define _ASM_SUB __ASM_SIZE(sub)
|
|
|
|
#define _ASM_XADD __ASM_SIZE(xadd)
|
2008-08-18 18:13:33 -07:00
|
|
|
|
2008-06-24 11:37:57 -03:00
|
|
|
#define _ASM_AX __ASM_REG(ax)
|
2008-06-24 17:36:31 -03:00
|
|
|
#define _ASM_BX __ASM_REG(bx)
|
|
|
|
#define _ASM_CX __ASM_REG(cx)
|
2008-06-24 11:37:57 -03:00
|
|
|
#define _ASM_DX __ASM_REG(dx)
|
2008-08-18 18:13:33 -07:00
|
|
|
#define _ASM_SP __ASM_REG(sp)
|
|
|
|
#define _ASM_BP __ASM_REG(bp)
|
|
|
|
#define _ASM_SI __ASM_REG(si)
|
|
|
|
#define _ASM_DI __ASM_REG(di)
|
2008-01-30 13:30:06 +01:00
|
|
|
|
2016-06-08 12:38:40 -07:00
|
|
|
/*
|
|
|
|
* Macros to generate condition code outputs from inline assembly,
|
|
|
|
* The output operand must be type "bool".
|
|
|
|
*/
|
|
|
|
#ifdef __GCC_ASM_FLAG_OUTPUTS__
|
|
|
|
# define CC_SET(c) "\n\t/* output condition code " #c "*/\n"
|
|
|
|
# define CC_OUT(c) "=@cc" #c
|
|
|
|
#else
|
|
|
|
# define CC_SET(c) "\n\tset" #c " %[_cc_" #c "]\n"
|
|
|
|
# define CC_OUT(c) [_cc_ ## c] "=qm"
|
|
|
|
#endif
|
|
|
|
|
2008-02-04 16:47:56 +01:00
|
|
|
/* Exception table entry */
|
2009-08-31 11:57:20 -07:00
|
|
|
#ifdef __ASSEMBLY__
|
2016-02-17 10:20:12 -08:00
|
|
|
# define _ASM_EXTABLE_HANDLE(from, to, handler) \
|
2012-04-20 16:57:35 -07:00
|
|
|
.pushsection "__ex_table","a" ; \
|
2016-02-17 10:20:12 -08:00
|
|
|
.balign 4 ; \
|
2012-04-20 17:12:48 -07:00
|
|
|
.long (from) - . ; \
|
|
|
|
.long (to) - . ; \
|
2016-02-17 10:20:12 -08:00
|
|
|
.long (handler) - . ; \
|
2012-04-20 16:57:35 -07:00
|
|
|
.popsection
|
|
|
|
|
2016-02-17 10:20:12 -08:00
|
|
|
# define _ASM_EXTABLE(from, to) \
|
|
|
|
_ASM_EXTABLE_HANDLE(from, to, ex_handler_default)
|
|
|
|
|
|
|
|
# define _ASM_EXTABLE_FAULT(from, to) \
|
|
|
|
_ASM_EXTABLE_HANDLE(from, to, ex_handler_fault)
|
|
|
|
|
|
|
|
# define _ASM_EXTABLE_EX(from, to) \
|
|
|
|
_ASM_EXTABLE_HANDLE(from, to, ex_handler_ext)
|
2014-04-17 17:17:05 +09:00
|
|
|
|
|
|
|
# define _ASM_NOKPROBE(entry) \
|
|
|
|
.pushsection "_kprobe_blacklist","aw" ; \
|
|
|
|
_ASM_ALIGN ; \
|
|
|
|
_ASM_PTR (entry); \
|
|
|
|
.popsection
|
2015-05-13 19:42:23 +02:00
|
|
|
|
|
|
|
.macro ALIGN_DESTINATION
|
|
|
|
/* check for bad alignment of destination */
|
|
|
|
movl %edi,%ecx
|
|
|
|
andl $7,%ecx
|
|
|
|
jz 102f /* already aligned */
|
|
|
|
subl $8,%ecx
|
|
|
|
negl %ecx
|
|
|
|
subl %ecx,%edx
|
|
|
|
100: movb (%rsi),%al
|
|
|
|
101: movb %al,(%rdi)
|
|
|
|
incq %rsi
|
|
|
|
incq %rdi
|
|
|
|
decl %ecx
|
|
|
|
jnz 100b
|
|
|
|
102:
|
|
|
|
.section .fixup,"ax"
|
|
|
|
103: addl %ecx,%edx /* ecx is zerorest also */
|
|
|
|
jmp copy_user_handle_tail
|
|
|
|
.previous
|
|
|
|
|
|
|
|
_ASM_EXTABLE(100b,103b)
|
|
|
|
_ASM_EXTABLE(101b,103b)
|
|
|
|
.endm
|
|
|
|
|
2009-08-31 11:57:20 -07:00
|
|
|
#else
|
2016-02-17 10:20:12 -08:00
|
|
|
# define _EXPAND_EXTABLE_HANDLE(x) #x
|
|
|
|
# define _ASM_EXTABLE_HANDLE(from, to, handler) \
|
2012-04-20 16:57:35 -07:00
|
|
|
" .pushsection \"__ex_table\",\"a\"\n" \
|
2016-02-17 10:20:12 -08:00
|
|
|
" .balign 4\n" \
|
2012-04-20 17:12:48 -07:00
|
|
|
" .long (" #from ") - .\n" \
|
|
|
|
" .long (" #to ") - .\n" \
|
2016-02-17 10:20:12 -08:00
|
|
|
" .long (" _EXPAND_EXTABLE_HANDLE(handler) ") - .\n" \
|
2012-04-20 16:57:35 -07:00
|
|
|
" .popsection\n"
|
|
|
|
|
2016-02-17 10:20:12 -08:00
|
|
|
# define _ASM_EXTABLE(from, to) \
|
|
|
|
_ASM_EXTABLE_HANDLE(from, to, ex_handler_default)
|
|
|
|
|
|
|
|
# define _ASM_EXTABLE_FAULT(from, to) \
|
|
|
|
_ASM_EXTABLE_HANDLE(from, to, ex_handler_fault)
|
|
|
|
|
|
|
|
# define _ASM_EXTABLE_EX(from, to) \
|
|
|
|
_ASM_EXTABLE_HANDLE(from, to, ex_handler_ext)
|
|
|
|
|
2014-04-17 17:17:05 +09:00
|
|
|
/* For C file, we already have NOKPROBE_SYMBOL macro */
|
2009-08-31 11:57:20 -07:00
|
|
|
#endif
|
2008-02-04 16:47:56 +01:00
|
|
|
|
2017-09-29 17:15:36 +03:00
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
/*
|
|
|
|
* This output constraint should be used for any inline asm which has a "call"
|
|
|
|
* instruction. Otherwise the asm may be inserted before the frame pointer
|
|
|
|
* gets set up by the containing function. If you forget to do this, objtool
|
|
|
|
* may print a "call without frame pointer save/setup" warning.
|
|
|
|
*/
|
|
|
|
register unsigned long current_stack_pointer asm(_ASM_SP);
|
|
|
|
#define ASM_CALL_CONSTRAINT "+r" (current_stack_pointer)
|
|
|
|
#endif
|
|
|
|
|
2008-10-22 22:26:29 -07:00
|
|
|
#endif /* _ASM_X86_ASM_H */
|