aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-11-14 02:25:10 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-14 02:25:10 -0500
commit7971e23a66c94f1b9bd2d64a3e86dfbfa8c60121 (patch)
tree20ff577e437ac6c361335151ce6b4c59bc72de02 /arch
parentf0d55cc1a65852e6647d4f5d707c1c9b5471ce3c (diff)
parenta4f61dec55c1bdebb84ba77212ebf98f7247736c (diff)
Merge branch 'x86-trace-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86/trace changes from Ingo Molnar: "This adds page fault tracepoints which have zero runtime cost in the disabled case via IDT trickery (no NOPs in the page fault hotpath)" * 'x86-trace-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86, trace: Change user|kernel_page_fault to page_fault_user|kernel x86, trace: Add page fault tracepoints x86, trace: Delete __trace_alloc_intr_gate() x86, trace: Register exception handler to trace IDT x86, trace: Remove __alloc_intr_gate()
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/desc.h57
-rw-r--r--arch/x86/include/asm/hw_irq.h3
-rw-r--r--arch/x86/include/asm/segment.h3
-rw-r--r--arch/x86/include/asm/trace/exceptions.h52
-rw-r--r--arch/x86/include/asm/traps.h20
-rw-r--r--arch/x86/kernel/entry_32.S10
-rw-r--r--arch/x86/kernel/entry_64.S13
-rw-r--r--arch/x86/kernel/head64.c2
-rw-r--r--arch/x86/kernel/kvm.c2
-rw-r--r--arch/x86/kernel/traps.c28
-rw-r--r--arch/x86/mm/Makefile2
-rw-r--r--arch/x86/mm/fault.c23
12 files changed, 165 insertions, 50 deletions
diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h
index b90e5dfeee46..50d033a8947d 100644
--- a/arch/x86/include/asm/desc.h
+++ b/arch/x86/include/asm/desc.h
@@ -327,10 +327,25 @@ static inline void write_trace_idt_entry(int entry, const gate_desc *gate)
327{ 327{
328 write_idt_entry(trace_idt_table, entry, gate); 328 write_idt_entry(trace_idt_table, entry, gate);
329} 329}
330
331static inline void _trace_set_gate(int gate, unsigned type, void *addr,
332 unsigned dpl, unsigned ist, unsigned seg)
333{
334 gate_desc s;
335
336 pack_gate(&s, type, (unsigned long)addr, dpl, ist, seg);
337 /*
338 * does not need to be atomic because it is only done once at
339 * setup time
340 */
341 write_trace_idt_entry(gate, &s);
342}
330#else 343#else
331static inline void write_trace_idt_entry(int entry, const gate_desc *gate) 344static inline void write_trace_idt_entry(int entry, const gate_desc *gate)
332{ 345{
333} 346}
347
348#define _trace_set_gate(gate, type, addr, dpl, ist, seg)
334#endif 349#endif
335 350
336static inline void _set_gate(int gate, unsigned type, void *addr, 351static inline void _set_gate(int gate, unsigned type, void *addr,
@@ -353,11 +368,14 @@ static inline void _set_gate(int gate, unsigned type, void *addr,
353 * Pentium F0 0F bugfix can have resulted in the mapped 368 * Pentium F0 0F bugfix can have resulted in the mapped
354 * IDT being write-protected. 369 * IDT being write-protected.
355 */ 370 */
356static inline void set_intr_gate(unsigned int n, void *addr) 371#define set_intr_gate(n, addr) \
357{ 372 do { \
358 BUG_ON((unsigned)n > 0xFF); 373 BUG_ON((unsigned)n > 0xFF); \
359 _set_gate(n, GATE_INTERRUPT, addr, 0, 0, __KERNEL_CS); 374 _set_gate(n, GATE_INTERRUPT, (void *)addr, 0, 0, \
360} 375 __KERNEL_CS); \
376 _trace_set_gate(n, GATE_INTERRUPT, (void *)trace_##addr,\
377 0, 0, __KERNEL_CS); \
378 } while (0)
361 379
362extern int first_system_vector; 380extern int first_system_vector;
363/* used_vectors is BITMAP for irq is not managed by percpu vector_irq */ 381/* used_vectors is BITMAP for irq is not managed by percpu vector_irq */
@@ -374,37 +392,10 @@ static inline void alloc_system_vector(int vector)
374 } 392 }
375} 393}
376 394
377#ifdef CONFIG_TRACING
378static inline void trace_set_intr_gate(unsigned int gate, void *addr)
379{
380 gate_desc s;
381
382 pack_gate(&s, GATE_INTERRUPT, (unsigned long)addr, 0, 0, __KERNEL_CS);
383 write_idt_entry(trace_idt_table, gate, &s);
384}
385
386static inline void __trace_alloc_intr_gate(unsigned int n, void *addr)
387{
388 trace_set_intr_gate(n, addr);
389}
390#else
391static inline void trace_set_intr_gate(unsigned int gate, void *addr)
392{
393}
394
395#define __trace_alloc_intr_gate(n, addr)
396#endif
397
398static inline void __alloc_intr_gate(unsigned int n, void *addr)
399{
400 set_intr_gate(n, addr);
401}
402
403#define alloc_intr_gate(n, addr) \ 395#define alloc_intr_gate(n, addr) \
404 do { \ 396 do { \
405 alloc_system_vector(n); \ 397 alloc_system_vector(n); \
406 __alloc_intr_gate(n, addr); \ 398 set_intr_gate(n, addr); \
407 __trace_alloc_intr_gate(n, trace_##addr); \
408 } while (0) 399 } while (0)
409 400
410/* 401/*
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index 92b3bae08b74..cba45d99ac1a 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -187,6 +187,9 @@ extern __visible void smp_invalidate_interrupt(struct pt_regs *);
187#endif 187#endif
188 188
189extern void (*__initconst interrupt[NR_VECTORS-FIRST_EXTERNAL_VECTOR])(void); 189extern void (*__initconst interrupt[NR_VECTORS-FIRST_EXTERNAL_VECTOR])(void);
190#ifdef CONFIG_TRACING
191#define trace_interrupt interrupt
192#endif
190 193
191typedef int vector_irq_t[NR_VECTORS]; 194typedef int vector_irq_t[NR_VECTORS];
192DECLARE_PER_CPU(vector_irq_t, vector_irq); 195DECLARE_PER_CPU(vector_irq_t, vector_irq);
diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h
index c48a95035a77..6f1c3a8a33ab 100644
--- a/arch/x86/include/asm/segment.h
+++ b/arch/x86/include/asm/segment.h
@@ -214,6 +214,9 @@
214#ifdef __KERNEL__ 214#ifdef __KERNEL__
215#ifndef __ASSEMBLY__ 215#ifndef __ASSEMBLY__
216extern const char early_idt_handlers[NUM_EXCEPTION_VECTORS][2+2+5]; 216extern const char early_idt_handlers[NUM_EXCEPTION_VECTORS][2+2+5];
217#ifdef CONFIG_TRACING
218#define trace_early_idt_handlers early_idt_handlers
219#endif
217 220
218/* 221/*
219 * Load a segment. Fall back on loading the zero 222 * Load a segment. Fall back on loading the zero
diff --git a/arch/x86/include/asm/trace/exceptions.h b/arch/x86/include/asm/trace/exceptions.h
new file mode 100644
index 000000000000..2fbc66c7885b
--- /dev/null
+++ b/arch/x86/include/asm/trace/exceptions.h
@@ -0,0 +1,52 @@
1#undef TRACE_SYSTEM
2#define TRACE_SYSTEM exceptions
3
4#if !defined(_TRACE_PAGE_FAULT_H) || defined(TRACE_HEADER_MULTI_READ)
5#define _TRACE_PAGE_FAULT_H
6
7#include <linux/tracepoint.h>
8
9extern void trace_irq_vector_regfunc(void);
10extern void trace_irq_vector_unregfunc(void);
11
12DECLARE_EVENT_CLASS(x86_exceptions,
13
14 TP_PROTO(unsigned long address, struct pt_regs *regs,
15 unsigned long error_code),
16
17 TP_ARGS(address, regs, error_code),
18
19 TP_STRUCT__entry(
20 __field( unsigned long, address )
21 __field( unsigned long, ip )
22 __field( unsigned long, error_code )
23 ),
24
25 TP_fast_assign(
26 __entry->address = address;
27 __entry->ip = regs->ip;
28 __entry->error_code = error_code;
29 ),
30
31 TP_printk("address=%pf ip=%pf error_code=0x%lx",
32 (void *)__entry->address, (void *)__entry->ip,
33 __entry->error_code) );
34
35#define DEFINE_PAGE_FAULT_EVENT(name) \
36DEFINE_EVENT_FN(x86_exceptions, name, \
37 TP_PROTO(unsigned long address, struct pt_regs *regs, \
38 unsigned long error_code), \
39 TP_ARGS(address, regs, error_code), \
40 trace_irq_vector_regfunc, \
41 trace_irq_vector_unregfunc);
42
43DEFINE_PAGE_FAULT_EVENT(page_fault_user);
44DEFINE_PAGE_FAULT_EVENT(page_fault_kernel);
45
46#undef TRACE_INCLUDE_PATH
47#define TRACE_INCLUDE_PATH .
48#define TRACE_INCLUDE_FILE exceptions
49#endif /* _TRACE_PAGE_FAULT_H */
50
51/* This part must be outside protection */
52#include <trace/define_trace.h>
diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h
index 7036cb60cd87..58d66fe06b61 100644
--- a/arch/x86/include/asm/traps.h
+++ b/arch/x86/include/asm/traps.h
@@ -37,6 +37,23 @@ asmlinkage void machine_check(void);
37#endif /* CONFIG_X86_MCE */ 37#endif /* CONFIG_X86_MCE */
38asmlinkage void simd_coprocessor_error(void); 38asmlinkage void simd_coprocessor_error(void);
39 39
40#ifdef CONFIG_TRACING
41asmlinkage void trace_page_fault(void);
42#define trace_divide_error divide_error
43#define trace_bounds bounds
44#define trace_invalid_op invalid_op
45#define trace_device_not_available device_not_available
46#define trace_coprocessor_segment_overrun coprocessor_segment_overrun
47#define trace_invalid_TSS invalid_TSS
48#define trace_segment_not_present segment_not_present
49#define trace_general_protection general_protection
50#define trace_spurious_interrupt_bug spurious_interrupt_bug
51#define trace_coprocessor_error coprocessor_error
52#define trace_alignment_check alignment_check
53#define trace_simd_coprocessor_error simd_coprocessor_error
54#define trace_async_page_fault async_page_fault
55#endif
56
40dotraplinkage void do_divide_error(struct pt_regs *, long); 57dotraplinkage void do_divide_error(struct pt_regs *, long);
41dotraplinkage void do_debug(struct pt_regs *, long); 58dotraplinkage void do_debug(struct pt_regs *, long);
42dotraplinkage void do_nmi(struct pt_regs *, long); 59dotraplinkage void do_nmi(struct pt_regs *, long);
@@ -55,6 +72,9 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *);
55#endif 72#endif
56dotraplinkage void do_general_protection(struct pt_regs *, long); 73dotraplinkage void do_general_protection(struct pt_regs *, long);
57dotraplinkage void do_page_fault(struct pt_regs *, unsigned long); 74dotraplinkage void do_page_fault(struct pt_regs *, unsigned long);
75#ifdef CONFIG_TRACING
76dotraplinkage void trace_do_page_fault(struct pt_regs *, unsigned long);
77#endif
58dotraplinkage void do_spurious_interrupt_bug(struct pt_regs *, long); 78dotraplinkage void do_spurious_interrupt_bug(struct pt_regs *, long);
59dotraplinkage void do_coprocessor_error(struct pt_regs *, long); 79dotraplinkage void do_coprocessor_error(struct pt_regs *, long);
60dotraplinkage void do_alignment_check(struct pt_regs *, long); 80dotraplinkage void do_alignment_check(struct pt_regs *, long);
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index fd1bc1b15e6d..51e2988c5728 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -1244,6 +1244,16 @@ return_to_handler:
1244 */ 1244 */
1245 .pushsection .kprobes.text, "ax" 1245 .pushsection .kprobes.text, "ax"
1246 1246
1247#ifdef CONFIG_TRACING
1248ENTRY(trace_page_fault)
1249 RING0_EC_FRAME
1250 ASM_CLAC
1251 pushl_cfi $trace_do_page_fault
1252 jmp error_code
1253 CFI_ENDPROC
1254END(trace_page_fault)
1255#endif
1256
1247ENTRY(page_fault) 1257ENTRY(page_fault)
1248 RING0_EC_FRAME 1258 RING0_EC_FRAME
1249 ASM_CLAC 1259 ASM_CLAC
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 603be7c70675..e21b0785a85b 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -1278,6 +1278,17 @@ ENTRY(\sym)
1278END(\sym) 1278END(\sym)
1279.endm 1279.endm
1280 1280
1281#ifdef CONFIG_TRACING
1282.macro trace_errorentry sym do_sym
1283errorentry trace(\sym) trace(\do_sym)
1284errorentry \sym \do_sym
1285.endm
1286#else
1287.macro trace_errorentry sym do_sym
1288errorentry \sym \do_sym
1289.endm
1290#endif
1291
1281 /* error code is on the stack already */ 1292 /* error code is on the stack already */
1282.macro paranoiderrorentry sym do_sym 1293.macro paranoiderrorentry sym do_sym
1283ENTRY(\sym) 1294ENTRY(\sym)
@@ -1480,7 +1491,7 @@ zeroentry xen_int3 do_int3
1480errorentry xen_stack_segment do_stack_segment 1491errorentry xen_stack_segment do_stack_segment
1481#endif 1492#endif
1482errorentry general_protection do_general_protection 1493errorentry general_protection do_general_protection
1483errorentry page_fault do_page_fault 1494trace_errorentry page_fault do_page_fault
1484#ifdef CONFIG_KVM_GUEST 1495#ifdef CONFIG_KVM_GUEST
1485errorentry async_page_fault do_async_page_fault 1496errorentry async_page_fault do_async_page_fault
1486#endif 1497#endif
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 1be8e43b669e..85126ccbdf6b 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -162,7 +162,7 @@ asmlinkage void __init x86_64_start_kernel(char * real_mode_data)
162 clear_bss(); 162 clear_bss();
163 163
164 for (i = 0; i < NUM_EXCEPTION_VECTORS; i++) 164 for (i = 0; i < NUM_EXCEPTION_VECTORS; i++)
165 set_intr_gate(i, &early_idt_handlers[i]); 165 set_intr_gate(i, early_idt_handlers[i]);
166 load_idt((const struct desc_ptr *)&idt_descr); 166 load_idt((const struct desc_ptr *)&idt_descr);
167 167
168 copy_bootdata(__va(real_mode_data)); 168 copy_bootdata(__va(real_mode_data));
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index b2046e4d0b59..6dd802c6d780 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -464,7 +464,7 @@ static struct notifier_block kvm_cpu_notifier = {
464 464
465static void __init kvm_apf_trap_init(void) 465static void __init kvm_apf_trap_init(void)
466{ 466{
467 set_intr_gate(14, &async_page_fault); 467 set_intr_gate(14, async_page_fault);
468} 468}
469 469
470void __init kvm_guest_init(void) 470void __init kvm_guest_init(void)
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 996ce2313ce6..b857ed890b4c 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -713,7 +713,7 @@ void __init early_trap_init(void)
713 /* int3 can be called from all */ 713 /* int3 can be called from all */
714 set_system_intr_gate_ist(X86_TRAP_BP, &int3, DEBUG_STACK); 714 set_system_intr_gate_ist(X86_TRAP_BP, &int3, DEBUG_STACK);
715#ifdef CONFIG_X86_32 715#ifdef CONFIG_X86_32
716 set_intr_gate(X86_TRAP_PF, &page_fault); 716 set_intr_gate(X86_TRAP_PF, page_fault);
717#endif 717#endif
718 load_idt(&idt_descr); 718 load_idt(&idt_descr);
719} 719}
@@ -721,7 +721,7 @@ void __init early_trap_init(void)
721void __init early_trap_pf_init(void) 721void __init early_trap_pf_init(void)
722{ 722{
723#ifdef CONFIG_X86_64 723#ifdef CONFIG_X86_64
724 set_intr_gate(X86_TRAP_PF, &page_fault); 724 set_intr_gate(X86_TRAP_PF, page_fault);
725#endif 725#endif
726} 726}
727 727
@@ -737,30 +737,30 @@ void __init trap_init(void)
737 early_iounmap(p, 4); 737 early_iounmap(p, 4);
738#endif 738#endif
739 739
740 set_intr_gate(X86_TRAP_DE, &divide_error); 740 set_intr_gate(X86_TRAP_DE, divide_error);
741 set_intr_gate_ist(X86_TRAP_NMI, &nmi, NMI_STACK); 741 set_intr_gate_ist(X86_TRAP_NMI, &nmi, NMI_STACK);
742 /* int4 can be called from all */ 742 /* int4 can be called from all */
743 set_system_intr_gate(X86_TRAP_OF, &overflow); 743 set_system_intr_gate(X86_TRAP_OF, &overflow);
744 set_intr_gate(X86_TRAP_BR, &bounds); 744 set_intr_gate(X86_TRAP_BR, bounds);
745 set_intr_gate(X86_TRAP_UD, &invalid_op); 745 set_intr_gate(X86_TRAP_UD, invalid_op);
746 set_intr_gate(X86_TRAP_NM, &device_not_available); 746 set_intr_gate(X86_TRAP_NM, device_not_available);
747#ifdef CONFIG_X86_32 747#ifdef CONFIG_X86_32
748 set_task_gate(X86_TRAP_DF, GDT_ENTRY_DOUBLEFAULT_TSS); 748 set_task_gate(X86_TRAP_DF, GDT_ENTRY_DOUBLEFAULT_TSS);
749#else 749#else
750 set_intr_gate_ist(X86_TRAP_DF, &double_fault, DOUBLEFAULT_STACK); 750 set_intr_gate_ist(X86_TRAP_DF, &double_fault, DOUBLEFAULT_STACK);
751#endif 751#endif
752 set_intr_gate(X86_TRAP_OLD_MF, &coprocessor_segment_overrun); 752 set_intr_gate(X86_TRAP_OLD_MF, coprocessor_segment_overrun);
753 set_intr_gate(X86_TRAP_TS, &invalid_TSS); 753 set_intr_gate(X86_TRAP_TS, invalid_TSS);
754 set_intr_gate(X86_TRAP_NP, &segment_not_present); 754 set_intr_gate(X86_TRAP_NP, segment_not_present);
755 set_intr_gate_ist(X86_TRAP_SS, &stack_segment, STACKFAULT_STACK); 755 set_intr_gate_ist(X86_TRAP_SS, &stack_segment, STACKFAULT_STACK);
756 set_intr_gate(X86_TRAP_GP, &general_protection); 756 set_intr_gate(X86_TRAP_GP, general_protection);
757 set_intr_gate(X86_TRAP_SPURIOUS, &spurious_interrupt_bug); 757 set_intr_gate(X86_TRAP_SPURIOUS, spurious_interrupt_bug);
758 set_intr_gate(X86_TRAP_MF, &coprocessor_error); 758 set_intr_gate(X86_TRAP_MF, coprocessor_error);
759 set_intr_gate(X86_TRAP_AC, &alignment_check); 759 set_intr_gate(X86_TRAP_AC, alignment_check);
760#ifdef CONFIG_X86_MCE 760#ifdef CONFIG_X86_MCE
761 set_intr_gate_ist(X86_TRAP_MC, &machine_check, MCE_STACK); 761 set_intr_gate_ist(X86_TRAP_MC, &machine_check, MCE_STACK);
762#endif 762#endif
763 set_intr_gate(X86_TRAP_XF, &simd_coprocessor_error); 763 set_intr_gate(X86_TRAP_XF, simd_coprocessor_error);
764 764
765 /* Reserve all the builtin and the syscall vector: */ 765 /* Reserve all the builtin and the syscall vector: */
766 for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) 766 for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++)
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile
index 23d8e5fecf76..6a19ad9f370d 100644
--- a/arch/x86/mm/Makefile
+++ b/arch/x86/mm/Makefile
@@ -6,6 +6,8 @@ nostackp := $(call cc-option, -fno-stack-protector)
6CFLAGS_physaddr.o := $(nostackp) 6CFLAGS_physaddr.o := $(nostackp)
7CFLAGS_setup_nx.o := $(nostackp) 7CFLAGS_setup_nx.o := $(nostackp)
8 8
9CFLAGS_fault.o := -I$(src)/../include/asm/trace
10
9obj-$(CONFIG_X86_PAT) += pat_rbtree.o 11obj-$(CONFIG_X86_PAT) += pat_rbtree.o
10obj-$(CONFIG_SMP) += tlb.o 12obj-$(CONFIG_SMP) += tlb.o
11 13
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 7a517bb41060..1560a5de1ce0 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -20,6 +20,9 @@
20#include <asm/kmemcheck.h> /* kmemcheck_*(), ... */ 20#include <asm/kmemcheck.h> /* kmemcheck_*(), ... */
21#include <asm/fixmap.h> /* VSYSCALL_START */ 21#include <asm/fixmap.h> /* VSYSCALL_START */
22 22
23#define CREATE_TRACE_POINTS
24#include <asm/trace/exceptions.h>
25
23/* 26/*
24 * Page fault error code bits: 27 * Page fault error code bits:
25 * 28 *
@@ -1232,3 +1235,23 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)
1232 __do_page_fault(regs, error_code); 1235 __do_page_fault(regs, error_code);
1233 exception_exit(prev_state); 1236 exception_exit(prev_state);
1234} 1237}
1238
1239static void trace_page_fault_entries(struct pt_regs *regs,
1240 unsigned long error_code)
1241{
1242 if (user_mode(regs))
1243 trace_page_fault_user(read_cr2(), regs, error_code);
1244 else
1245 trace_page_fault_kernel(read_cr2(), regs, error_code);
1246}
1247
1248dotraplinkage void __kprobes
1249trace_do_page_fault(struct pt_regs *regs, unsigned long error_code)
1250{
1251 enum ctx_state prev_state;
1252
1253 prev_state = exception_enter();
1254 trace_page_fault_entries(regs, error_code);
1255 __do_page_fault(regs, error_code);
1256 exception_exit(prev_state);
1257}