diff options
author | Jeremy Fitzhardinge <jeremy@goop.org> | 2006-12-08 05:36:22 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-08 11:28:39 -0500 |
commit | c31a0bf3e1bc581676618db7492f18798fd0a73f (patch) | |
tree | 68eb38dbc58d647c3b20cd73fb812cafe93eb663 | |
parent | 91768d6c2bad0d2766a166f13f2f57e197de3458 (diff) |
[PATCH] Generic BUG for x86-64
This makes x86-64 use the generic BUG machinery.
The main advantage in using the generic BUG machinery for x86-64 is that
the inlined overhead of BUG is just the ud2a instruction; the file+line
information are no longer inlined into the instruction stream. This
reduces cache pollution.
Signed-off-by: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Andi Kleen <ak@muc.de>
Cc: Hugh Dickens <hugh@veritas.com>
Cc: Michael Ellerman <michael@ellerman.id.au>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | arch/x86_64/Kconfig | 5 | ||||
-rw-r--r-- | arch/x86_64/kernel/module.c | 5 | ||||
-rw-r--r-- | arch/x86_64/kernel/traps.c | 36 | ||||
-rw-r--r-- | arch/x86_64/kernel/vmlinux.lds.S | 2 | ||||
-rw-r--r-- | include/asm-x86_64/bug.h | 44 |
5 files changed, 45 insertions, 47 deletions
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index bfbb9bcae123..3254a616c69e 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig | |||
@@ -96,6 +96,11 @@ config AUDIT_ARCH | |||
96 | bool | 96 | bool |
97 | default y | 97 | default y |
98 | 98 | ||
99 | config GENERIC_BUG | ||
100 | bool | ||
101 | default y | ||
102 | depends on BUG | ||
103 | |||
99 | source "init/Kconfig" | 104 | source "init/Kconfig" |
100 | 105 | ||
101 | 106 | ||
diff --git a/arch/x86_64/kernel/module.c b/arch/x86_64/kernel/module.c index 9d0958ff547f..a888e67f5874 100644 --- a/arch/x86_64/kernel/module.c +++ b/arch/x86_64/kernel/module.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/string.h> | 23 | #include <linux/string.h> |
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/bug.h> | ||
26 | 27 | ||
27 | #include <asm/system.h> | 28 | #include <asm/system.h> |
28 | #include <asm/page.h> | 29 | #include <asm/page.h> |
@@ -173,10 +174,12 @@ int module_finalize(const Elf_Ehdr *hdr, | |||
173 | lseg, lseg + locks->sh_size, | 174 | lseg, lseg + locks->sh_size, |
174 | tseg, tseg + text->sh_size); | 175 | tseg, tseg + text->sh_size); |
175 | } | 176 | } |
176 | return 0; | 177 | |
178 | return module_bug_finalize(hdr, sechdrs, me); | ||
177 | } | 179 | } |
178 | 180 | ||
179 | void module_arch_cleanup(struct module *mod) | 181 | void module_arch_cleanup(struct module *mod) |
180 | { | 182 | { |
181 | alternatives_smp_module_del(mod); | 183 | alternatives_smp_module_del(mod); |
184 | module_bug_cleanup(mod); | ||
182 | } | 185 | } |
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index a1641ffdffcf..b54ccc07f379 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/kexec.h> | 31 | #include <linux/kexec.h> |
32 | #include <linux/unwind.h> | 32 | #include <linux/unwind.h> |
33 | #include <linux/uaccess.h> | 33 | #include <linux/uaccess.h> |
34 | #include <linux/bug.h> | ||
34 | 35 | ||
35 | #include <asm/system.h> | 36 | #include <asm/system.h> |
36 | #include <asm/io.h> | 37 | #include <asm/io.h> |
@@ -524,30 +525,15 @@ bad: | |||
524 | printk("\n"); | 525 | printk("\n"); |
525 | } | 526 | } |
526 | 527 | ||
527 | void handle_BUG(struct pt_regs *regs) | 528 | int is_valid_bugaddr(unsigned long rip) |
528 | { | 529 | { |
529 | struct bug_frame f; | 530 | unsigned short ud2; |
530 | long len; | ||
531 | const char *prefix = ""; | ||
532 | 531 | ||
533 | if (user_mode(regs)) | 532 | if (__copy_from_user(&ud2, (const void __user *) rip, sizeof(ud2))) |
534 | return; | 533 | return 0; |
535 | if (__copy_from_user(&f, (const void __user *) regs->rip, | 534 | |
536 | sizeof(struct bug_frame))) | 535 | return ud2 == 0x0b0f; |
537 | return; | 536 | } |
538 | if (f.filename >= 0 || | ||
539 | f.ud2[0] != 0x0f || f.ud2[1] != 0x0b) | ||
540 | return; | ||
541 | len = __strnlen_user((char *)(long)f.filename, PATH_MAX) - 1; | ||
542 | if (len < 0 || len >= PATH_MAX) | ||
543 | f.filename = (int)(long)"unmapped filename"; | ||
544 | else if (len > 50) { | ||
545 | f.filename += len - 50; | ||
546 | prefix = "..."; | ||
547 | } | ||
548 | printk("----------- [cut here ] --------- [please bite here ] ---------\n"); | ||
549 | printk(KERN_ALERT "Kernel BUG at %s%.50s:%d\n", prefix, (char *)(long)f.filename, f.line); | ||
550 | } | ||
551 | 537 | ||
552 | #ifdef CONFIG_BUG | 538 | #ifdef CONFIG_BUG |
553 | void out_of_line_bug(void) | 539 | void out_of_line_bug(void) |
@@ -627,7 +613,9 @@ void die(const char * str, struct pt_regs * regs, long err) | |||
627 | { | 613 | { |
628 | unsigned long flags = oops_begin(); | 614 | unsigned long flags = oops_begin(); |
629 | 615 | ||
630 | handle_BUG(regs); | 616 | if (!user_mode(regs)) |
617 | report_bug(regs->rip); | ||
618 | |||
631 | __die(str, regs, err); | 619 | __die(str, regs, err); |
632 | oops_end(flags); | 620 | oops_end(flags); |
633 | do_exit(SIGSEGV); | 621 | do_exit(SIGSEGV); |
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S index 6a1f8f491e5d..6c417788c54b 100644 --- a/arch/x86_64/kernel/vmlinux.lds.S +++ b/arch/x86_64/kernel/vmlinux.lds.S | |||
@@ -51,6 +51,8 @@ SECTIONS | |||
51 | 51 | ||
52 | RODATA | 52 | RODATA |
53 | 53 | ||
54 | BUG_TABLE | ||
55 | |||
54 | . = ALIGN(PAGE_SIZE); /* Align data segment to page size boundary */ | 56 | . = ALIGN(PAGE_SIZE); /* Align data segment to page size boundary */ |
55 | /* Data */ | 57 | /* Data */ |
56 | .data : AT(ADDR(.data) - LOAD_OFFSET) { | 58 | .data : AT(ADDR(.data) - LOAD_OFFSET) { |
diff --git a/include/asm-x86_64/bug.h b/include/asm-x86_64/bug.h index 80ac1fe966ac..682606414913 100644 --- a/include/asm-x86_64/bug.h +++ b/include/asm-x86_64/bug.h | |||
@@ -1,30 +1,30 @@ | |||
1 | #ifndef __ASM_X8664_BUG_H | 1 | #ifndef __ASM_X8664_BUG_H |
2 | #define __ASM_X8664_BUG_H 1 | 2 | #define __ASM_X8664_BUG_H 1 |
3 | 3 | ||
4 | #include <linux/stringify.h> | ||
5 | |||
6 | /* | ||
7 | * Tell the user there is some problem. The exception handler decodes | ||
8 | * this frame. | ||
9 | */ | ||
10 | struct bug_frame { | ||
11 | unsigned char ud2[2]; | ||
12 | unsigned char push; | ||
13 | signed int filename; | ||
14 | unsigned char ret; | ||
15 | unsigned short line; | ||
16 | } __attribute__((packed)); | ||
17 | |||
18 | #ifdef CONFIG_BUG | 4 | #ifdef CONFIG_BUG |
19 | #define HAVE_ARCH_BUG | 5 | #define HAVE_ARCH_BUG |
20 | /* We turn the bug frame into valid instructions to not confuse | 6 | |
21 | the disassembler. Thanks to Jan Beulich & Suresh Siddha | 7 | #ifdef CONFIG_DEBUG_BUGVERBOSE |
22 | for nice instruction selection. | 8 | #define BUG() \ |
23 | The magic numbers generate mov $64bitimm,%eax ; ret $offset. */ | 9 | do { \ |
24 | #define BUG() \ | 10 | asm volatile("1:\tud2\n" \ |
25 | asm volatile( \ | 11 | ".pushsection __bug_table,\"a\"\n" \ |
26 | "ud2 ; pushq $%c1 ; ret $%c0" :: \ | 12 | "2:\t.quad 1b, %c0\n" \ |
27 | "i"(__LINE__), "i" (__FILE__)) | 13 | "\t.word %c1, 0\n" \ |
14 | "\t.org 2b+%c2\n" \ | ||
15 | ".popsection" \ | ||
16 | : : "i" (__FILE__), "i" (__LINE__), \ | ||
17 | "i" (sizeof(struct bug_entry))); \ | ||
18 | for(;;) ; \ | ||
19 | } while(0) | ||
20 | #else | ||
21 | #define BUG() \ | ||
22 | do { \ | ||
23 | asm volatile("ud2"); \ | ||
24 | for(;;) ; \ | ||
25 | } while(0) | ||
26 | #endif | ||
27 | |||
28 | void out_of_line_bug(void); | 28 | void out_of_line_bug(void); |
29 | #else | 29 | #else |
30 | static inline void out_of_line_bug(void) { } | 30 | static inline void out_of_line_bug(void) { } |