Skip to content

Commit 9a93848

Browse files
Peter ZijlstraIngo Molnar
authored andcommitted
x86/debug: Implement __WARN() using UD0
By using "UD0" for WARN()s we remove the function call and its possible __FILE__ and __LINE__ immediate arguments from the instruction stream. Total image size will not change much, what we win in the instruction stream we'll lose because of the __bug_table entries. Still, saves on I$ footprint and the total image size does go down a bit. text data filename 10702123 4530992 defconfig-build/vmlinux.orig 10682460 4530992 defconfig-build/vmlinux.patched (UML didn't seem to use GENERIC_BUG at all, so remove it) Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Arjan van de Ven <arjan@linux.intel.com> Cc: Borislav Petkov <bp@alien8.de> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Richard Weinberger <richard.weinberger@gmail.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent 1fa9d67 commit 9a93848

File tree

8 files changed

+101
-76
lines changed

8 files changed

+101
-76
lines changed

arch/um/Kconfig.common

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,6 @@ config GENERIC_CALIBRATE_DELAY
5050
bool
5151
default y
5252

53-
config GENERIC_BUG
54-
bool
55-
default y
56-
depends on BUG
57-
5853
config HZ
5954
int
6055
default 100

arch/x86/include/asm/bug.h

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,78 @@
11
#ifndef _ASM_X86_BUG_H
22
#define _ASM_X86_BUG_H
33

4-
#define HAVE_ARCH_BUG
4+
#include <linux/stringify.h>
55

6-
#ifdef CONFIG_DEBUG_BUGVERBOSE
6+
/*
7+
* Since some emulators terminate on UD2, we cannot use it for WARN.
8+
* Since various instruction decoders disagree on the length of UD1,
9+
* we cannot use it either. So use UD0 for WARN.
10+
*
11+
* (binutils knows about "ud1" but {en,de}codes it as 2 bytes, whereas
12+
* our kernel decoder thinks it takes a ModRM byte, which seems consistent
13+
* with various things like the Intel SDM instruction encoding rules)
14+
*/
15+
16+
#define ASM_UD0 ".byte 0x0f, 0xff"
17+
#define ASM_UD1 ".byte 0x0f, 0xb9" /* + ModRM */
18+
#define ASM_UD2 ".byte 0x0f, 0x0b"
19+
20+
#define INSN_UD0 0xff0f
21+
#define INSN_UD2 0x0b0f
22+
23+
#define LEN_UD0 2
24+
25+
#ifdef CONFIG_GENERIC_BUG
26+
#define HAVE_ARCH_BUG
727

828
#ifdef CONFIG_X86_32
9-
# define __BUG_C0 "2:\t.long 1b, %c0\n"
29+
# define __BUG_REL(val) ".long " __stringify(val)
1030
#else
11-
# define __BUG_C0 "2:\t.long 1b - 2b, %c0 - 2b\n"
31+
# define __BUG_REL(val) ".long " __stringify(val) " - 2b"
1232
#endif
1333

14-
#define BUG() \
15-
do { \
16-
asm volatile("1:\tud2\n" \
17-
".pushsection __bug_table,\"a\"\n" \
18-
__BUG_C0 \
19-
"\t.word %c1, 0\n" \
20-
"\t.org 2b+%c2\n" \
21-
".popsection" \
22-
: : "i" (__FILE__), "i" (__LINE__), \
23-
"i" (sizeof(struct bug_entry))); \
24-
unreachable(); \
34+
#ifdef CONFIG_DEBUG_BUGVERBOSE
35+
36+
#define _BUG_FLAGS(ins, flags) \
37+
do { \
38+
asm volatile("1:\t" ins "\n" \
39+
".pushsection __bug_table,\"a\"\n" \
40+
"2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n" \
41+
"\t" __BUG_REL(%c0) "\t# bug_entry::file\n" \
42+
"\t.word %c1" "\t# bug_entry::line\n" \
43+
"\t.word %c2" "\t# bug_entry::flags\n" \
44+
"\t.org 2b+%c3\n" \
45+
".popsection" \
46+
: : "i" (__FILE__), "i" (__LINE__), \
47+
"i" (flags), \
48+
"i" (sizeof(struct bug_entry))); \
2549
} while (0)
2650

27-
#else
51+
#else /* !CONFIG_DEBUG_BUGVERBOSE */
52+
53+
#define _BUG_FLAGS(ins, flags) \
54+
do { \
55+
asm volatile("1:\t" ins "\n" \
56+
".pushsection __bug_table,\"a\"\n" \
57+
"2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n" \
58+
"\t.word %c0" "\t# bug_entry::flags\n" \
59+
"\t.org 2b+%c1\n" \
60+
".popsection" \
61+
: : "i" (flags), \
62+
"i" (sizeof(struct bug_entry))); \
63+
} while (0)
64+
65+
#endif /* CONFIG_DEBUG_BUGVERBOSE */
66+
2867
#define BUG() \
2968
do { \
30-
asm volatile("ud2"); \
69+
_BUG_FLAGS(ASM_UD2, 0); \
3170
unreachable(); \
3271
} while (0)
33-
#endif
72+
73+
#define __WARN_TAINT(taint) _BUG_FLAGS(ASM_UD0, BUGFLAG_TAINT(taint))
74+
75+
#endif /* CONFIG_GENERIC_BUG */
3476

3577
#include <asm-generic/bug.h>
3678

arch/x86/kernel/dumpstack.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,9 +289,6 @@ void die(const char *str, struct pt_regs *regs, long err)
289289
unsigned long flags = oops_begin();
290290
int sig = SIGSEGV;
291291

292-
if (!user_mode(regs))
293-
report_bug(regs->ip, regs);
294-
295292
if (__die(str, regs, err))
296293
sig = 0;
297294
oops_end(flags, regs, sig);

arch/x86/kernel/dumpstack_32.c

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -162,15 +162,3 @@ void show_regs(struct pt_regs *regs)
162162
}
163163
pr_cont("\n");
164164
}
165-
166-
int is_valid_bugaddr(unsigned long ip)
167-
{
168-
unsigned short ud2;
169-
170-
if (ip < PAGE_OFFSET)
171-
return 0;
172-
if (probe_kernel_address((unsigned short *)ip, ud2))
173-
return 0;
174-
175-
return ud2 == 0x0b0f;
176-
}

arch/x86/kernel/dumpstack_64.c

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -178,13 +178,3 @@ void show_regs(struct pt_regs *regs)
178178
}
179179
pr_cont("\n");
180180
}
181-
182-
int is_valid_bugaddr(unsigned long ip)
183-
{
184-
unsigned short ud2;
185-
186-
if (__copy_from_user(&ud2, (const void __user *) ip, sizeof(ud2)))
187-
return 0;
188-
189-
return ud2 == 0x0b0f;
190-
}

arch/x86/kernel/traps.c

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,37 @@ void ist_end_non_atomic(void)
169169
preempt_disable();
170170
}
171171

172+
int is_valid_bugaddr(unsigned long addr)
173+
{
174+
unsigned short ud;
175+
176+
if (addr < TASK_SIZE_MAX)
177+
return 0;
178+
179+
if (probe_kernel_address((unsigned short *)addr, ud))
180+
return 0;
181+
182+
return ud == INSN_UD0 || ud == INSN_UD2;
183+
}
184+
185+
static int fixup_bug(struct pt_regs *regs, int trapnr)
186+
{
187+
if (trapnr != X86_TRAP_UD)
188+
return 0;
189+
190+
switch (report_bug(regs->ip, regs)) {
191+
case BUG_TRAP_TYPE_NONE:
192+
case BUG_TRAP_TYPE_BUG:
193+
break;
194+
195+
case BUG_TRAP_TYPE_WARN:
196+
regs->ip += LEN_UD0;
197+
return 1;
198+
}
199+
200+
return 0;
201+
}
202+
172203
static nokprobe_inline int
173204
do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
174205
struct pt_regs *regs, long error_code)
@@ -187,12 +218,15 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
187218
}
188219

189220
if (!user_mode(regs)) {
190-
if (!fixup_exception(regs, trapnr)) {
191-
tsk->thread.error_code = error_code;
192-
tsk->thread.trap_nr = trapnr;
193-
die(str, regs, error_code);
194-
}
195-
return 0;
221+
if (fixup_exception(regs, trapnr))
222+
return 0;
223+
224+
if (fixup_bug(regs, trapnr))
225+
return 0;
226+
227+
tsk->thread.error_code = error_code;
228+
tsk->thread.trap_nr = trapnr;
229+
die(str, regs, error_code);
196230
}
197231

198232
return -1;

arch/x86/um/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ else
88
BITS := 64
99
endif
1010

11-
obj-y = bug.o bugs_$(BITS).o delay.o fault.o ldt.o \
11+
obj-y = bugs_$(BITS).o delay.o fault.o ldt.o \
1212
ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \
1313
stub_$(BITS).o stub_segv.o \
1414
sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \

arch/x86/um/bug.c

Lines changed: 0 additions & 21 deletions
This file was deleted.

0 commit comments

Comments
 (0)