diff options
Diffstat (limited to 'arch')
46 files changed, 2012 insertions, 1208 deletions
diff --git a/arch/ia64/include/asm/topology.h b/arch/ia64/include/asm/topology.h index 35bcb641c9e5..a3cc9f65f954 100644 --- a/arch/ia64/include/asm/topology.h +++ b/arch/ia64/include/asm/topology.h | |||
@@ -55,7 +55,6 @@ | |||
55 | void build_cpu_to_node_map(void); | 55 | void build_cpu_to_node_map(void); |
56 | 56 | ||
57 | #define SD_CPU_INIT (struct sched_domain) { \ | 57 | #define SD_CPU_INIT (struct sched_domain) { \ |
58 | .span = CPU_MASK_NONE, \ | ||
59 | .parent = NULL, \ | 58 | .parent = NULL, \ |
60 | .child = NULL, \ | 59 | .child = NULL, \ |
61 | .groups = NULL, \ | 60 | .groups = NULL, \ |
@@ -80,7 +79,6 @@ void build_cpu_to_node_map(void); | |||
80 | 79 | ||
81 | /* sched_domains SD_NODE_INIT for IA64 NUMA machines */ | 80 | /* sched_domains SD_NODE_INIT for IA64 NUMA machines */ |
82 | #define SD_NODE_INIT (struct sched_domain) { \ | 81 | #define SD_NODE_INIT (struct sched_domain) { \ |
83 | .span = CPU_MASK_NONE, \ | ||
84 | .parent = NULL, \ | 82 | .parent = NULL, \ |
85 | .child = NULL, \ | 83 | .child = NULL, \ |
86 | .groups = NULL, \ | 84 | .groups = NULL, \ |
diff --git a/arch/mips/include/asm/mach-ip27/topology.h b/arch/mips/include/asm/mach-ip27/topology.h index 7785bec732f2..1fb959f98982 100644 --- a/arch/mips/include/asm/mach-ip27/topology.h +++ b/arch/mips/include/asm/mach-ip27/topology.h | |||
@@ -37,7 +37,6 @@ extern unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES]; | |||
37 | 37 | ||
38 | /* sched_domains SD_NODE_INIT for SGI IP27 machines */ | 38 | /* sched_domains SD_NODE_INIT for SGI IP27 machines */ |
39 | #define SD_NODE_INIT (struct sched_domain) { \ | 39 | #define SD_NODE_INIT (struct sched_domain) { \ |
40 | .span = CPU_MASK_NONE, \ | ||
41 | .parent = NULL, \ | 40 | .parent = NULL, \ |
42 | .child = NULL, \ | 41 | .child = NULL, \ |
43 | .groups = NULL, \ | 42 | .groups = NULL, \ |
diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h index b298f7a631e6..e5f2ae8362f7 100644 --- a/arch/powerpc/include/asm/ftrace.h +++ b/arch/powerpc/include/asm/ftrace.h | |||
@@ -7,7 +7,19 @@ | |||
7 | 7 | ||
8 | #ifndef __ASSEMBLY__ | 8 | #ifndef __ASSEMBLY__ |
9 | extern void _mcount(void); | 9 | extern void _mcount(void); |
10 | #endif | 10 | |
11 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
12 | static inline unsigned long ftrace_call_adjust(unsigned long addr) | ||
13 | { | ||
14 | /* reloction of mcount call site is the same as the address */ | ||
15 | return addr; | ||
16 | } | ||
17 | |||
18 | struct dyn_arch_ftrace { | ||
19 | struct module *mod; | ||
20 | }; | ||
21 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
22 | #endif /* __ASSEMBLY__ */ | ||
11 | 23 | ||
12 | #endif | 24 | #endif |
13 | 25 | ||
diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h index e5f14b13ccf0..08454880a2c0 100644 --- a/arch/powerpc/include/asm/module.h +++ b/arch/powerpc/include/asm/module.h | |||
@@ -34,11 +34,19 @@ struct mod_arch_specific { | |||
34 | #ifdef __powerpc64__ | 34 | #ifdef __powerpc64__ |
35 | unsigned int stubs_section; /* Index of stubs section in module */ | 35 | unsigned int stubs_section; /* Index of stubs section in module */ |
36 | unsigned int toc_section; /* What section is the TOC? */ | 36 | unsigned int toc_section; /* What section is the TOC? */ |
37 | #else | 37 | #ifdef CONFIG_DYNAMIC_FTRACE |
38 | unsigned long toc; | ||
39 | unsigned long tramp; | ||
40 | #endif | ||
41 | |||
42 | #else /* powerpc64 */ | ||
38 | /* Indices of PLT sections within module. */ | 43 | /* Indices of PLT sections within module. */ |
39 | unsigned int core_plt_section; | 44 | unsigned int core_plt_section; |
40 | unsigned int init_plt_section; | 45 | unsigned int init_plt_section; |
46 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
47 | unsigned long tramp; | ||
41 | #endif | 48 | #endif |
49 | #endif /* powerpc64 */ | ||
42 | 50 | ||
43 | /* List of BUG addresses, source line numbers and filenames */ | 51 | /* List of BUG addresses, source line numbers and filenames */ |
44 | struct list_head bug_list; | 52 | struct list_head bug_list; |
@@ -68,6 +76,12 @@ struct mod_arch_specific { | |||
68 | # endif /* MODULE */ | 76 | # endif /* MODULE */ |
69 | #endif | 77 | #endif |
70 | 78 | ||
79 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
80 | # ifdef MODULE | ||
81 | asm(".section .ftrace.tramp,\"ax\",@nobits; .align 3; .previous"); | ||
82 | # endif /* MODULE */ | ||
83 | #endif | ||
84 | |||
71 | 85 | ||
72 | struct exception_table_entry; | 86 | struct exception_table_entry; |
73 | void sort_ex_table(struct exception_table_entry *start, | 87 | void sort_ex_table(struct exception_table_entry *start, |
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index c32da6f97999..373fca394a54 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h | |||
@@ -48,7 +48,6 @@ static inline int pcibus_to_node(struct pci_bus *bus) | |||
48 | 48 | ||
49 | /* sched_domains SD_NODE_INIT for PPC64 machines */ | 49 | /* sched_domains SD_NODE_INIT for PPC64 machines */ |
50 | #define SD_NODE_INIT (struct sched_domain) { \ | 50 | #define SD_NODE_INIT (struct sched_domain) { \ |
51 | .span = CPU_MASK_NONE, \ | ||
52 | .parent = NULL, \ | 51 | .parent = NULL, \ |
53 | .child = NULL, \ | 52 | .child = NULL, \ |
54 | .groups = NULL, \ | 53 | .groups = NULL, \ |
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 92673b43858d..d17edb4a2f9d 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile | |||
@@ -17,6 +17,7 @@ ifdef CONFIG_FUNCTION_TRACER | |||
17 | CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog | 17 | CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog |
18 | CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog | 18 | CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog |
19 | CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog | 19 | CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog |
20 | CFLAGS_REMOVE_prom.o = -pg -mno-sched-epilog | ||
20 | 21 | ||
21 | ifdef CONFIG_DYNAMIC_FTRACE | 22 | ifdef CONFIG_DYNAMIC_FTRACE |
22 | # dynamic ftrace setup. | 23 | # dynamic ftrace setup. |
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 7ecc0d1855c3..6f7eb7e00c79 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S | |||
@@ -1162,39 +1162,17 @@ machine_check_in_rtas: | |||
1162 | #ifdef CONFIG_DYNAMIC_FTRACE | 1162 | #ifdef CONFIG_DYNAMIC_FTRACE |
1163 | _GLOBAL(mcount) | 1163 | _GLOBAL(mcount) |
1164 | _GLOBAL(_mcount) | 1164 | _GLOBAL(_mcount) |
1165 | stwu r1,-48(r1) | 1165 | /* |
1166 | stw r3, 12(r1) | 1166 | * It is required that _mcount on PPC32 must preserve the |
1167 | stw r4, 16(r1) | 1167 | * link register. But we have r0 to play with. We use r0 |
1168 | stw r5, 20(r1) | 1168 | * to push the return address back to the caller of mcount |
1169 | stw r6, 24(r1) | 1169 | * into the ctr register, restore the link register and |
1170 | mflr r3 | 1170 | * then jump back using the ctr register. |
1171 | stw r7, 28(r1) | 1171 | */ |
1172 | mfcr r5 | 1172 | mflr r0 |
1173 | stw r8, 32(r1) | ||
1174 | stw r9, 36(r1) | ||
1175 | stw r10,40(r1) | ||
1176 | stw r3, 44(r1) | ||
1177 | stw r5, 8(r1) | ||
1178 | subi r3, r3, MCOUNT_INSN_SIZE | ||
1179 | .globl mcount_call | ||
1180 | mcount_call: | ||
1181 | bl ftrace_stub | ||
1182 | nop | ||
1183 | lwz r6, 8(r1) | ||
1184 | lwz r0, 44(r1) | ||
1185 | lwz r3, 12(r1) | ||
1186 | mtctr r0 | 1173 | mtctr r0 |
1187 | lwz r4, 16(r1) | 1174 | lwz r0, 4(r1) |
1188 | mtcr r6 | ||
1189 | lwz r5, 20(r1) | ||
1190 | lwz r6, 24(r1) | ||
1191 | lwz r0, 52(r1) | ||
1192 | lwz r7, 28(r1) | ||
1193 | lwz r8, 32(r1) | ||
1194 | mtlr r0 | 1175 | mtlr r0 |
1195 | lwz r9, 36(r1) | ||
1196 | lwz r10,40(r1) | ||
1197 | addi r1, r1, 48 | ||
1198 | bctr | 1176 | bctr |
1199 | 1177 | ||
1200 | _GLOBAL(ftrace_caller) | 1178 | _GLOBAL(ftrace_caller) |
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index e0bcf9354286..383ed6eb0085 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -894,18 +894,6 @@ _GLOBAL(enter_prom) | |||
894 | #ifdef CONFIG_DYNAMIC_FTRACE | 894 | #ifdef CONFIG_DYNAMIC_FTRACE |
895 | _GLOBAL(mcount) | 895 | _GLOBAL(mcount) |
896 | _GLOBAL(_mcount) | 896 | _GLOBAL(_mcount) |
897 | /* Taken from output of objdump from lib64/glibc */ | ||
898 | mflr r3 | ||
899 | stdu r1, -112(r1) | ||
900 | std r3, 128(r1) | ||
901 | subi r3, r3, MCOUNT_INSN_SIZE | ||
902 | .globl mcount_call | ||
903 | mcount_call: | ||
904 | bl ftrace_stub | ||
905 | nop | ||
906 | ld r0, 128(r1) | ||
907 | mtlr r0 | ||
908 | addi r1, r1, 112 | ||
909 | blr | 897 | blr |
910 | 898 | ||
911 | _GLOBAL(ftrace_caller) | 899 | _GLOBAL(ftrace_caller) |
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c index f4b006ed0ab1..5355244c99ff 100644 --- a/arch/powerpc/kernel/ftrace.c +++ b/arch/powerpc/kernel/ftrace.c | |||
@@ -9,22 +9,30 @@ | |||
9 | 9 | ||
10 | #include <linux/spinlock.h> | 10 | #include <linux/spinlock.h> |
11 | #include <linux/hardirq.h> | 11 | #include <linux/hardirq.h> |
12 | #include <linux/uaccess.h> | ||
13 | #include <linux/module.h> | ||
12 | #include <linux/ftrace.h> | 14 | #include <linux/ftrace.h> |
13 | #include <linux/percpu.h> | 15 | #include <linux/percpu.h> |
14 | #include <linux/init.h> | 16 | #include <linux/init.h> |
15 | #include <linux/list.h> | 17 | #include <linux/list.h> |
16 | 18 | ||
17 | #include <asm/cacheflush.h> | 19 | #include <asm/cacheflush.h> |
20 | #include <asm/code-patching.h> | ||
18 | #include <asm/ftrace.h> | 21 | #include <asm/ftrace.h> |
19 | 22 | ||
23 | #if 0 | ||
24 | #define DEBUGP printk | ||
25 | #else | ||
26 | #define DEBUGP(fmt , ...) do { } while (0) | ||
27 | #endif | ||
20 | 28 | ||
21 | static unsigned int ftrace_nop = 0x60000000; | 29 | static unsigned int ftrace_nop = PPC_NOP_INSTR; |
22 | 30 | ||
23 | #ifdef CONFIG_PPC32 | 31 | #ifdef CONFIG_PPC32 |
24 | # define GET_ADDR(addr) addr | 32 | # define GET_ADDR(addr) addr |
25 | #else | 33 | #else |
26 | /* PowerPC64's functions are data that points to the functions */ | 34 | /* PowerPC64's functions are data that points to the functions */ |
27 | # define GET_ADDR(addr) *(unsigned long *)addr | 35 | # define GET_ADDR(addr) (*(unsigned long *)addr) |
28 | #endif | 36 | #endif |
29 | 37 | ||
30 | 38 | ||
@@ -33,12 +41,12 @@ static unsigned int ftrace_calc_offset(long ip, long addr) | |||
33 | return (int)(addr - ip); | 41 | return (int)(addr - ip); |
34 | } | 42 | } |
35 | 43 | ||
36 | unsigned char *ftrace_nop_replace(void) | 44 | static unsigned char *ftrace_nop_replace(void) |
37 | { | 45 | { |
38 | return (char *)&ftrace_nop; | 46 | return (char *)&ftrace_nop; |
39 | } | 47 | } |
40 | 48 | ||
41 | unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) | 49 | static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) |
42 | { | 50 | { |
43 | static unsigned int op; | 51 | static unsigned int op; |
44 | 52 | ||
@@ -68,49 +76,422 @@ unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) | |||
68 | # define _ASM_PTR " .long " | 76 | # define _ASM_PTR " .long " |
69 | #endif | 77 | #endif |
70 | 78 | ||
71 | int | 79 | static int |
72 | ftrace_modify_code(unsigned long ip, unsigned char *old_code, | 80 | ftrace_modify_code(unsigned long ip, unsigned char *old_code, |
73 | unsigned char *new_code) | 81 | unsigned char *new_code) |
74 | { | 82 | { |
75 | unsigned replaced; | 83 | unsigned char replaced[MCOUNT_INSN_SIZE]; |
76 | unsigned old = *(unsigned *)old_code; | ||
77 | unsigned new = *(unsigned *)new_code; | ||
78 | int faulted = 0; | ||
79 | 84 | ||
80 | /* | 85 | /* |
81 | * Note: Due to modules and __init, code can | 86 | * Note: Due to modules and __init, code can |
82 | * disappear and change, we need to protect against faulting | 87 | * disappear and change, we need to protect against faulting |
83 | * as well as code changing. | 88 | * as well as code changing. We do this by using the |
89 | * probe_kernel_* functions. | ||
84 | * | 90 | * |
85 | * No real locking needed, this code is run through | 91 | * No real locking needed, this code is run through |
86 | * kstop_machine. | 92 | * kstop_machine, or before SMP starts. |
87 | */ | 93 | */ |
88 | asm volatile ( | 94 | |
89 | "1: lwz %1, 0(%2)\n" | 95 | /* read the text we want to modify */ |
90 | " cmpw %1, %5\n" | 96 | if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE)) |
91 | " bne 2f\n" | 97 | return -EFAULT; |
92 | " stwu %3, 0(%2)\n" | 98 | |
93 | "2:\n" | 99 | /* Make sure it is what we expect it to be */ |
94 | ".section .fixup, \"ax\"\n" | 100 | if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0) |
95 | "3: li %0, 1\n" | 101 | return -EINVAL; |
96 | " b 2b\n" | 102 | |
97 | ".previous\n" | 103 | /* replace the text with the new text */ |
98 | ".section __ex_table,\"a\"\n" | 104 | if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE)) |
99 | _ASM_ALIGN "\n" | 105 | return -EPERM; |
100 | _ASM_PTR "1b, 3b\n" | 106 | |
101 | ".previous" | 107 | flush_icache_range(ip, ip + 8); |
102 | : "=r"(faulted), "=r"(replaced) | 108 | |
103 | : "r"(ip), "r"(new), | 109 | return 0; |
104 | "0"(faulted), "r"(old) | 110 | } |
105 | : "memory"); | 111 | |
106 | 112 | /* | |
107 | if (replaced != old && replaced != new) | 113 | * Helper functions that are the same for both PPC64 and PPC32. |
108 | faulted = 2; | 114 | */ |
109 | 115 | static int test_24bit_addr(unsigned long ip, unsigned long addr) | |
110 | if (!faulted) | 116 | { |
111 | flush_icache_range(ip, ip + 8); | 117 | |
112 | 118 | /* use the create_branch to verify that this offset can be branched */ | |
113 | return faulted; | 119 | return create_branch((unsigned int *)ip, addr, 0); |
120 | } | ||
121 | |||
122 | static int is_bl_op(unsigned int op) | ||
123 | { | ||
124 | return (op & 0xfc000003) == 0x48000001; | ||
125 | } | ||
126 | |||
127 | static unsigned long find_bl_target(unsigned long ip, unsigned int op) | ||
128 | { | ||
129 | static int offset; | ||
130 | |||
131 | offset = (op & 0x03fffffc); | ||
132 | /* make it signed */ | ||
133 | if (offset & 0x02000000) | ||
134 | offset |= 0xfe000000; | ||
135 | |||
136 | return ip + (long)offset; | ||
137 | } | ||
138 | |||
139 | #ifdef CONFIG_PPC64 | ||
140 | static int | ||
141 | __ftrace_make_nop(struct module *mod, | ||
142 | struct dyn_ftrace *rec, unsigned long addr) | ||
143 | { | ||
144 | unsigned int op; | ||
145 | unsigned int jmp[5]; | ||
146 | unsigned long ptr; | ||
147 | unsigned long ip = rec->ip; | ||
148 | unsigned long tramp; | ||
149 | int offset; | ||
150 | |||
151 | /* read where this goes */ | ||
152 | if (probe_kernel_read(&op, (void *)ip, sizeof(int))) | ||
153 | return -EFAULT; | ||
154 | |||
155 | /* Make sure that that this is still a 24bit jump */ | ||
156 | if (!is_bl_op(op)) { | ||
157 | printk(KERN_ERR "Not expected bl: opcode is %x\n", op); | ||
158 | return -EINVAL; | ||
159 | } | ||
160 | |||
161 | /* lets find where the pointer goes */ | ||
162 | tramp = find_bl_target(ip, op); | ||
163 | |||
164 | /* | ||
165 | * On PPC64 the trampoline looks like: | ||
166 | * 0x3d, 0x82, 0x00, 0x00, addis r12,r2, <high> | ||
167 | * 0x39, 0x8c, 0x00, 0x00, addi r12,r12, <low> | ||
168 | * Where the bytes 2,3,6 and 7 make up the 32bit offset | ||
169 | * to the TOC that holds the pointer. | ||
170 | * to jump to. | ||
171 | * 0xf8, 0x41, 0x00, 0x28, std r2,40(r1) | ||
172 | * 0xe9, 0x6c, 0x00, 0x20, ld r11,32(r12) | ||
173 | * The actually address is 32 bytes from the offset | ||
174 | * into the TOC. | ||
175 | * 0xe8, 0x4c, 0x00, 0x28, ld r2,40(r12) | ||
176 | */ | ||
177 | |||
178 | DEBUGP("ip:%lx jumps to %lx r2: %lx", ip, tramp, mod->arch.toc); | ||
179 | |||
180 | /* Find where the trampoline jumps to */ | ||
181 | if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) { | ||
182 | printk(KERN_ERR "Failed to read %lx\n", tramp); | ||
183 | return -EFAULT; | ||
184 | } | ||
185 | |||
186 | DEBUGP(" %08x %08x", jmp[0], jmp[1]); | ||
187 | |||
188 | /* verify that this is what we expect it to be */ | ||
189 | if (((jmp[0] & 0xffff0000) != 0x3d820000) || | ||
190 | ((jmp[1] & 0xffff0000) != 0x398c0000) || | ||
191 | (jmp[2] != 0xf8410028) || | ||
192 | (jmp[3] != 0xe96c0020) || | ||
193 | (jmp[4] != 0xe84c0028)) { | ||
194 | printk(KERN_ERR "Not a trampoline\n"); | ||
195 | return -EINVAL; | ||
196 | } | ||
197 | |||
198 | offset = (unsigned)((unsigned short)jmp[0]) << 16 | | ||
199 | (unsigned)((unsigned short)jmp[1]); | ||
200 | |||
201 | DEBUGP(" %x ", offset); | ||
202 | |||
203 | /* get the address this jumps too */ | ||
204 | tramp = mod->arch.toc + offset + 32; | ||
205 | DEBUGP("toc: %lx", tramp); | ||
206 | |||
207 | if (probe_kernel_read(jmp, (void *)tramp, 8)) { | ||
208 | printk(KERN_ERR "Failed to read %lx\n", tramp); | ||
209 | return -EFAULT; | ||
210 | } | ||
211 | |||
212 | DEBUGP(" %08x %08x\n", jmp[0], jmp[1]); | ||
213 | |||
214 | ptr = ((unsigned long)jmp[0] << 32) + jmp[1]; | ||
215 | |||
216 | /* This should match what was called */ | ||
217 | if (ptr != GET_ADDR(addr)) { | ||
218 | printk(KERN_ERR "addr does not match %lx\n", ptr); | ||
219 | return -EINVAL; | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * We want to nop the line, but the next line is | ||
224 | * 0xe8, 0x41, 0x00, 0x28 ld r2,40(r1) | ||
225 | * This needs to be turned to a nop too. | ||
226 | */ | ||
227 | if (probe_kernel_read(&op, (void *)(ip+4), MCOUNT_INSN_SIZE)) | ||
228 | return -EFAULT; | ||
229 | |||
230 | if (op != 0xe8410028) { | ||
231 | printk(KERN_ERR "Next line is not ld! (%08x)\n", op); | ||
232 | return -EINVAL; | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * Milton Miller pointed out that we can not blindly do nops. | ||
237 | * If a task was preempted when calling a trace function, | ||
238 | * the nops will remove the way to restore the TOC in r2 | ||
239 | * and the r2 TOC will get corrupted. | ||
240 | */ | ||
241 | |||
242 | /* | ||
243 | * Replace: | ||
244 | * bl <tramp> <==== will be replaced with "b 1f" | ||
245 | * ld r2,40(r1) | ||
246 | * 1: | ||
247 | */ | ||
248 | op = 0x48000008; /* b +8 */ | ||
249 | |||
250 | if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE)) | ||
251 | return -EPERM; | ||
252 | |||
253 | |||
254 | flush_icache_range(ip, ip + 8); | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | #else /* !PPC64 */ | ||
260 | static int | ||
261 | __ftrace_make_nop(struct module *mod, | ||
262 | struct dyn_ftrace *rec, unsigned long addr) | ||
263 | { | ||
264 | unsigned int op; | ||
265 | unsigned int jmp[4]; | ||
266 | unsigned long ip = rec->ip; | ||
267 | unsigned long tramp; | ||
268 | |||
269 | if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE)) | ||
270 | return -EFAULT; | ||
271 | |||
272 | /* Make sure that that this is still a 24bit jump */ | ||
273 | if (!is_bl_op(op)) { | ||
274 | printk(KERN_ERR "Not expected bl: opcode is %x\n", op); | ||
275 | return -EINVAL; | ||
276 | } | ||
277 | |||
278 | /* lets find where the pointer goes */ | ||
279 | tramp = find_bl_target(ip, op); | ||
280 | |||
281 | /* | ||
282 | * On PPC32 the trampoline looks like: | ||
283 | * 0x3d, 0x60, 0x00, 0x00 lis r11,sym@ha | ||
284 | * 0x39, 0x6b, 0x00, 0x00 addi r11,r11,sym@l | ||
285 | * 0x7d, 0x69, 0x03, 0xa6 mtctr r11 | ||
286 | * 0x4e, 0x80, 0x04, 0x20 bctr | ||
287 | */ | ||
288 | |||
289 | DEBUGP("ip:%lx jumps to %lx", ip, tramp); | ||
290 | |||
291 | /* Find where the trampoline jumps to */ | ||
292 | if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) { | ||
293 | printk(KERN_ERR "Failed to read %lx\n", tramp); | ||
294 | return -EFAULT; | ||
295 | } | ||
296 | |||
297 | DEBUGP(" %08x %08x ", jmp[0], jmp[1]); | ||
298 | |||
299 | /* verify that this is what we expect it to be */ | ||
300 | if (((jmp[0] & 0xffff0000) != 0x3d600000) || | ||
301 | ((jmp[1] & 0xffff0000) != 0x396b0000) || | ||
302 | (jmp[2] != 0x7d6903a6) || | ||
303 | (jmp[3] != 0x4e800420)) { | ||
304 | printk(KERN_ERR "Not a trampoline\n"); | ||
305 | return -EINVAL; | ||
306 | } | ||
307 | |||
308 | tramp = (jmp[1] & 0xffff) | | ||
309 | ((jmp[0] & 0xffff) << 16); | ||
310 | if (tramp & 0x8000) | ||
311 | tramp -= 0x10000; | ||
312 | |||
313 | DEBUGP(" %x ", tramp); | ||
314 | |||
315 | if (tramp != addr) { | ||
316 | printk(KERN_ERR | ||
317 | "Trampoline location %08lx does not match addr\n", | ||
318 | tramp); | ||
319 | return -EINVAL; | ||
320 | } | ||
321 | |||
322 | op = PPC_NOP_INSTR; | ||
323 | |||
324 | if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE)) | ||
325 | return -EPERM; | ||
326 | |||
327 | flush_icache_range(ip, ip + 8); | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | #endif /* PPC64 */ | ||
332 | |||
333 | int ftrace_make_nop(struct module *mod, | ||
334 | struct dyn_ftrace *rec, unsigned long addr) | ||
335 | { | ||
336 | unsigned char *old, *new; | ||
337 | unsigned long ip = rec->ip; | ||
338 | |||
339 | /* | ||
340 | * If the calling address is more that 24 bits away, | ||
341 | * then we had to use a trampoline to make the call. | ||
342 | * Otherwise just update the call site. | ||
343 | */ | ||
344 | if (test_24bit_addr(ip, addr)) { | ||
345 | /* within range */ | ||
346 | old = ftrace_call_replace(ip, addr); | ||
347 | new = ftrace_nop_replace(); | ||
348 | return ftrace_modify_code(ip, old, new); | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * Out of range jumps are called from modules. | ||
353 | * We should either already have a pointer to the module | ||
354 | * or it has been passed in. | ||
355 | */ | ||
356 | if (!rec->arch.mod) { | ||
357 | if (!mod) { | ||
358 | printk(KERN_ERR "No module loaded addr=%lx\n", | ||
359 | addr); | ||
360 | return -EFAULT; | ||
361 | } | ||
362 | rec->arch.mod = mod; | ||
363 | } else if (mod) { | ||
364 | if (mod != rec->arch.mod) { | ||
365 | printk(KERN_ERR | ||
366 | "Record mod %p not equal to passed in mod %p\n", | ||
367 | rec->arch.mod, mod); | ||
368 | return -EINVAL; | ||
369 | } | ||
370 | /* nothing to do if mod == rec->arch.mod */ | ||
371 | } else | ||
372 | mod = rec->arch.mod; | ||
373 | |||
374 | return __ftrace_make_nop(mod, rec, addr); | ||
375 | |||
376 | } | ||
377 | |||
378 | #ifdef CONFIG_PPC64 | ||
379 | static int | ||
380 | __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | ||
381 | { | ||
382 | unsigned int op[2]; | ||
383 | unsigned long ip = rec->ip; | ||
384 | |||
385 | /* read where this goes */ | ||
386 | if (probe_kernel_read(op, (void *)ip, MCOUNT_INSN_SIZE * 2)) | ||
387 | return -EFAULT; | ||
388 | |||
389 | /* | ||
390 | * It should be pointing to two nops or | ||
391 | * b +8; ld r2,40(r1) | ||
392 | */ | ||
393 | if (((op[0] != 0x48000008) || (op[1] != 0xe8410028)) && | ||
394 | ((op[0] != PPC_NOP_INSTR) || (op[1] != PPC_NOP_INSTR))) { | ||
395 | printk(KERN_ERR "Expected NOPs but have %x %x\n", op[0], op[1]); | ||
396 | return -EINVAL; | ||
397 | } | ||
398 | |||
399 | /* If we never set up a trampoline to ftrace_caller, then bail */ | ||
400 | if (!rec->arch.mod->arch.tramp) { | ||
401 | printk(KERN_ERR "No ftrace trampoline\n"); | ||
402 | return -EINVAL; | ||
403 | } | ||
404 | |||
405 | /* create the branch to the trampoline */ | ||
406 | op[0] = create_branch((unsigned int *)ip, | ||
407 | rec->arch.mod->arch.tramp, BRANCH_SET_LINK); | ||
408 | if (!op[0]) { | ||
409 | printk(KERN_ERR "REL24 out of range!\n"); | ||
410 | return -EINVAL; | ||
411 | } | ||
412 | |||
413 | /* ld r2,40(r1) */ | ||
414 | op[1] = 0xe8410028; | ||
415 | |||
416 | DEBUGP("write to %lx\n", rec->ip); | ||
417 | |||
418 | if (probe_kernel_write((void *)ip, op, MCOUNT_INSN_SIZE * 2)) | ||
419 | return -EPERM; | ||
420 | |||
421 | flush_icache_range(ip, ip + 8); | ||
422 | |||
423 | return 0; | ||
424 | } | ||
425 | #else | ||
426 | static int | ||
427 | __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | ||
428 | { | ||
429 | unsigned int op; | ||
430 | unsigned long ip = rec->ip; | ||
431 | |||
432 | /* read where this goes */ | ||
433 | if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE)) | ||
434 | return -EFAULT; | ||
435 | |||
436 | /* It should be pointing to a nop */ | ||
437 | if (op != PPC_NOP_INSTR) { | ||
438 | printk(KERN_ERR "Expected NOP but have %x\n", op); | ||
439 | return -EINVAL; | ||
440 | } | ||
441 | |||
442 | /* If we never set up a trampoline to ftrace_caller, then bail */ | ||
443 | if (!rec->arch.mod->arch.tramp) { | ||
444 | printk(KERN_ERR "No ftrace trampoline\n"); | ||
445 | return -EINVAL; | ||
446 | } | ||
447 | |||
448 | /* create the branch to the trampoline */ | ||
449 | op = create_branch((unsigned int *)ip, | ||
450 | rec->arch.mod->arch.tramp, BRANCH_SET_LINK); | ||
451 | if (!op) { | ||
452 | printk(KERN_ERR "REL24 out of range!\n"); | ||
453 | return -EINVAL; | ||
454 | } | ||
455 | |||
456 | DEBUGP("write to %lx\n", rec->ip); | ||
457 | |||
458 | if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE)) | ||
459 | return -EPERM; | ||
460 | |||
461 | flush_icache_range(ip, ip + 8); | ||
462 | |||
463 | return 0; | ||
464 | } | ||
465 | #endif /* CONFIG_PPC64 */ | ||
466 | |||
467 | int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | ||
468 | { | ||
469 | unsigned char *old, *new; | ||
470 | unsigned long ip = rec->ip; | ||
471 | |||
472 | /* | ||
473 | * If the calling address is more that 24 bits away, | ||
474 | * then we had to use a trampoline to make the call. | ||
475 | * Otherwise just update the call site. | ||
476 | */ | ||
477 | if (test_24bit_addr(ip, addr)) { | ||
478 | /* within range */ | ||
479 | old = ftrace_nop_replace(); | ||
480 | new = ftrace_call_replace(ip, addr); | ||
481 | return ftrace_modify_code(ip, old, new); | ||
482 | } | ||
483 | |||
484 | /* | ||
485 | * Out of range jumps are called from modules. | ||
486 | * Being that we are converting from nop, it had better | ||
487 | * already have a module defined. | ||
488 | */ | ||
489 | if (!rec->arch.mod) { | ||
490 | printk(KERN_ERR "No module loaded\n"); | ||
491 | return -EINVAL; | ||
492 | } | ||
493 | |||
494 | return __ftrace_make_call(rec, addr); | ||
114 | } | 495 | } |
115 | 496 | ||
116 | int ftrace_update_ftrace_func(ftrace_func_t func) | 497 | int ftrace_update_ftrace_func(ftrace_func_t func) |
@@ -128,10 +509,10 @@ int ftrace_update_ftrace_func(ftrace_func_t func) | |||
128 | 509 | ||
129 | int __init ftrace_dyn_arch_init(void *data) | 510 | int __init ftrace_dyn_arch_init(void *data) |
130 | { | 511 | { |
131 | /* This is running in kstop_machine */ | 512 | /* caller expects data to be zero */ |
513 | unsigned long *p = data; | ||
132 | 514 | ||
133 | ftrace_mcount_set(data); | 515 | *p = 0; |
134 | 516 | ||
135 | return 0; | 517 | return 0; |
136 | } | 518 | } |
137 | |||
diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index 31982d05d81a..88d9c1d5e5fb 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c | |||
@@ -69,10 +69,15 @@ void cpu_idle(void) | |||
69 | smp_mb(); | 69 | smp_mb(); |
70 | local_irq_disable(); | 70 | local_irq_disable(); |
71 | 71 | ||
72 | /* Don't trace irqs off for idle */ | ||
73 | stop_critical_timings(); | ||
74 | |||
72 | /* check again after disabling irqs */ | 75 | /* check again after disabling irqs */ |
73 | if (!need_resched() && !cpu_should_die()) | 76 | if (!need_resched() && !cpu_should_die()) |
74 | ppc_md.power_save(); | 77 | ppc_md.power_save(); |
75 | 78 | ||
79 | start_critical_timings(); | ||
80 | |||
76 | local_irq_enable(); | 81 | local_irq_enable(); |
77 | set_thread_flag(TIF_POLLING_NRFLAG); | 82 | set_thread_flag(TIF_POLLING_NRFLAG); |
78 | 83 | ||
diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c index 2df91a03462a..f832773fc28e 100644 --- a/arch/powerpc/kernel/module_32.c +++ b/arch/powerpc/kernel/module_32.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/fs.h> | 22 | #include <linux/fs.h> |
23 | #include <linux/string.h> | 23 | #include <linux/string.h> |
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/ftrace.h> | ||
25 | #include <linux/cache.h> | 26 | #include <linux/cache.h> |
26 | #include <linux/bug.h> | 27 | #include <linux/bug.h> |
27 | #include <linux/sort.h> | 28 | #include <linux/sort.h> |
@@ -53,6 +54,9 @@ static unsigned int count_relocs(const Elf32_Rela *rela, unsigned int num) | |||
53 | r_addend = rela[i].r_addend; | 54 | r_addend = rela[i].r_addend; |
54 | } | 55 | } |
55 | 56 | ||
57 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
58 | _count_relocs++; /* add one for ftrace_caller */ | ||
59 | #endif | ||
56 | return _count_relocs; | 60 | return _count_relocs; |
57 | } | 61 | } |
58 | 62 | ||
@@ -306,5 +310,11 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, | |||
306 | return -ENOEXEC; | 310 | return -ENOEXEC; |
307 | } | 311 | } |
308 | } | 312 | } |
313 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
314 | module->arch.tramp = | ||
315 | do_plt_call(module->module_core, | ||
316 | (unsigned long)ftrace_caller, | ||
317 | sechdrs, module); | ||
318 | #endif | ||
309 | return 0; | 319 | return 0; |
310 | } | 320 | } |
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index 1af2377e4992..8992b031a7b6 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/moduleloader.h> | 20 | #include <linux/moduleloader.h> |
21 | #include <linux/err.h> | 21 | #include <linux/err.h> |
22 | #include <linux/vmalloc.h> | 22 | #include <linux/vmalloc.h> |
23 | #include <linux/ftrace.h> | ||
23 | #include <linux/bug.h> | 24 | #include <linux/bug.h> |
24 | #include <asm/module.h> | 25 | #include <asm/module.h> |
25 | #include <asm/firmware.h> | 26 | #include <asm/firmware.h> |
@@ -163,6 +164,11 @@ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr, | |||
163 | } | 164 | } |
164 | } | 165 | } |
165 | 166 | ||
167 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
168 | /* make the trampoline to the ftrace_caller */ | ||
169 | relocs++; | ||
170 | #endif | ||
171 | |||
166 | DEBUGP("Looks like a total of %lu stubs, max\n", relocs); | 172 | DEBUGP("Looks like a total of %lu stubs, max\n", relocs); |
167 | return relocs * sizeof(struct ppc64_stub_entry); | 173 | return relocs * sizeof(struct ppc64_stub_entry); |
168 | } | 174 | } |
@@ -441,5 +447,12 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, | |||
441 | } | 447 | } |
442 | } | 448 | } |
443 | 449 | ||
450 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
451 | me->arch.toc = my_r2(sechdrs, me); | ||
452 | me->arch.tramp = stub_for_addr(sechdrs, | ||
453 | (unsigned long)ftrace_caller, | ||
454 | me); | ||
455 | #endif | ||
456 | |||
444 | return 0; | 457 | return 0; |
445 | } | 458 | } |
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index d69912c07ce7..8db35278a4b4 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile | |||
@@ -6,6 +6,9 @@ ifeq ($(CONFIG_PPC64),y) | |||
6 | EXTRA_CFLAGS += -mno-minimal-toc | 6 | EXTRA_CFLAGS += -mno-minimal-toc |
7 | endif | 7 | endif |
8 | 8 | ||
9 | CFLAGS_REMOVE_code-patching.o = -pg | ||
10 | CFLAGS_REMOVE_feature-fixups.o = -pg | ||
11 | |||
9 | obj-y := string.o alloc.o \ | 12 | obj-y := string.o alloc.o \ |
10 | checksum_$(CONFIG_WORD_SIZE).o | 13 | checksum_$(CONFIG_WORD_SIZE).o |
11 | obj-$(CONFIG_PPC32) += div64.o copy_32.o crtsavres.o | 14 | obj-$(CONFIG_PPC32) += div64.o copy_32.o crtsavres.o |
diff --git a/arch/sh/include/asm/topology.h b/arch/sh/include/asm/topology.h index 95f0085e098a..279d9cc4a007 100644 --- a/arch/sh/include/asm/topology.h +++ b/arch/sh/include/asm/topology.h | |||
@@ -5,7 +5,6 @@ | |||
5 | 5 | ||
6 | /* sched_domains SD_NODE_INIT for sh machines */ | 6 | /* sched_domains SD_NODE_INIT for sh machines */ |
7 | #define SD_NODE_INIT (struct sched_domain) { \ | 7 | #define SD_NODE_INIT (struct sched_domain) { \ |
8 | .span = CPU_MASK_NONE, \ | ||
9 | .parent = NULL, \ | 8 | .parent = NULL, \ |
10 | .child = NULL, \ | 9 | .child = NULL, \ |
11 | .groups = NULL, \ | 10 | .groups = NULL, \ |
diff --git a/arch/um/include/asm/system.h b/arch/um/include/asm/system.h index 753346e2cdfd..ae5f94d6317d 100644 --- a/arch/um/include/asm/system.h +++ b/arch/um/include/asm/system.h | |||
@@ -11,21 +11,21 @@ extern int get_signals(void); | |||
11 | extern void block_signals(void); | 11 | extern void block_signals(void); |
12 | extern void unblock_signals(void); | 12 | extern void unblock_signals(void); |
13 | 13 | ||
14 | #define local_save_flags(flags) do { typecheck(unsigned long, flags); \ | 14 | #define raw_local_save_flags(flags) do { typecheck(unsigned long, flags); \ |
15 | (flags) = get_signals(); } while(0) | 15 | (flags) = get_signals(); } while(0) |
16 | #define local_irq_restore(flags) do { typecheck(unsigned long, flags); \ | 16 | #define raw_local_irq_restore(flags) do { typecheck(unsigned long, flags); \ |
17 | set_signals(flags); } while(0) | 17 | set_signals(flags); } while(0) |
18 | 18 | ||
19 | #define local_irq_save(flags) do { local_save_flags(flags); \ | 19 | #define raw_local_irq_save(flags) do { raw_local_save_flags(flags); \ |
20 | local_irq_disable(); } while(0) | 20 | raw_local_irq_disable(); } while(0) |
21 | 21 | ||
22 | #define local_irq_enable() unblock_signals() | 22 | #define raw_local_irq_enable() unblock_signals() |
23 | #define local_irq_disable() block_signals() | 23 | #define raw_local_irq_disable() block_signals() |
24 | 24 | ||
25 | #define irqs_disabled() \ | 25 | #define irqs_disabled() \ |
26 | ({ \ | 26 | ({ \ |
27 | unsigned long flags; \ | 27 | unsigned long flags; \ |
28 | local_save_flags(flags); \ | 28 | raw_local_save_flags(flags); \ |
29 | (flags == 0); \ | 29 | (flags == 0); \ |
30 | }) | 30 | }) |
31 | 31 | ||
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 7b7d2764a215..c7235e643aff 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -29,11 +29,14 @@ config X86 | |||
29 | select HAVE_FTRACE_MCOUNT_RECORD | 29 | select HAVE_FTRACE_MCOUNT_RECORD |
30 | select HAVE_DYNAMIC_FTRACE | 30 | select HAVE_DYNAMIC_FTRACE |
31 | select HAVE_FUNCTION_TRACER | 31 | select HAVE_FUNCTION_TRACER |
32 | select HAVE_FUNCTION_GRAPH_TRACER | ||
33 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST | ||
32 | select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64) | 34 | select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64) |
33 | select HAVE_ARCH_KGDB if !X86_VOYAGER | 35 | select HAVE_ARCH_KGDB if !X86_VOYAGER |
34 | select HAVE_ARCH_TRACEHOOK | 36 | select HAVE_ARCH_TRACEHOOK |
35 | select HAVE_GENERIC_DMA_COHERENT if X86_32 | 37 | select HAVE_GENERIC_DMA_COHERENT if X86_32 |
36 | select HAVE_EFFICIENT_UNALIGNED_ACCESS | 38 | select HAVE_EFFICIENT_UNALIGNED_ACCESS |
39 | select USER_STACKTRACE_SUPPORT | ||
37 | 40 | ||
38 | config ARCH_DEFCONFIG | 41 | config ARCH_DEFCONFIG |
39 | string | 42 | string |
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index b815664fe370..85a78575956c 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu | |||
@@ -515,6 +515,7 @@ config CPU_SUP_UMC_32 | |||
515 | config X86_DS | 515 | config X86_DS |
516 | def_bool X86_PTRACE_BTS | 516 | def_bool X86_PTRACE_BTS |
517 | depends on X86_DEBUGCTLMSR | 517 | depends on X86_DEBUGCTLMSR |
518 | select HAVE_HW_BRANCH_TRACER | ||
518 | 519 | ||
519 | config X86_PTRACE_BTS | 520 | config X86_PTRACE_BTS |
520 | bool "Branch Trace Store" | 521 | bool "Branch Trace Store" |
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 2a3dfbd5e677..fa013f529b74 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug | |||
@@ -186,14 +186,10 @@ config IOMMU_LEAK | |||
186 | Add a simple leak tracer to the IOMMU code. This is useful when you | 186 | Add a simple leak tracer to the IOMMU code. This is useful when you |
187 | are debugging a buggy device driver that leaks IOMMU mappings. | 187 | are debugging a buggy device driver that leaks IOMMU mappings. |
188 | 188 | ||
189 | config MMIOTRACE_HOOKS | ||
190 | bool | ||
191 | |||
192 | config MMIOTRACE | 189 | config MMIOTRACE |
193 | bool "Memory mapped IO tracing" | 190 | bool "Memory mapped IO tracing" |
194 | depends on DEBUG_KERNEL && PCI | 191 | depends on DEBUG_KERNEL && PCI |
195 | select TRACING | 192 | select TRACING |
196 | select MMIOTRACE_HOOKS | ||
197 | help | 193 | help |
198 | Mmiotrace traces Memory Mapped I/O access and is meant for | 194 | Mmiotrace traces Memory Mapped I/O access and is meant for |
199 | debugging and reverse engineering. It is called from the ioremap | 195 | debugging and reverse engineering. It is called from the ioremap |
diff --git a/arch/x86/include/asm/ds.h b/arch/x86/include/asm/ds.h index a95008457ea4..99b6c39774a4 100644 --- a/arch/x86/include/asm/ds.h +++ b/arch/x86/include/asm/ds.h | |||
@@ -7,13 +7,12 @@ | |||
7 | * | 7 | * |
8 | * It manages: | 8 | * It manages: |
9 | * - per-thread and per-cpu allocation of BTS and PEBS | 9 | * - per-thread and per-cpu allocation of BTS and PEBS |
10 | * - buffer memory allocation (optional) | 10 | * - buffer overflow handling (to be done) |
11 | * - buffer overflow handling | ||
12 | * - buffer access | 11 | * - buffer access |
13 | * | 12 | * |
14 | * It assumes: | 13 | * It assumes: |
15 | * - get_task_struct on all parameter tasks | 14 | * - get_task_struct on all traced tasks |
16 | * - current is allowed to trace parameter tasks | 15 | * - current is allowed to trace tasks |
17 | * | 16 | * |
18 | * | 17 | * |
19 | * Copyright (C) 2007-2008 Intel Corporation. | 18 | * Copyright (C) 2007-2008 Intel Corporation. |
@@ -26,11 +25,18 @@ | |||
26 | 25 | ||
27 | #include <linux/types.h> | 26 | #include <linux/types.h> |
28 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/err.h> | ||
29 | 29 | ||
30 | 30 | ||
31 | #ifdef CONFIG_X86_DS | 31 | #ifdef CONFIG_X86_DS |
32 | 32 | ||
33 | struct task_struct; | 33 | struct task_struct; |
34 | struct ds_tracer; | ||
35 | struct bts_tracer; | ||
36 | struct pebs_tracer; | ||
37 | |||
38 | typedef void (*bts_ovfl_callback_t)(struct bts_tracer *); | ||
39 | typedef void (*pebs_ovfl_callback_t)(struct pebs_tracer *); | ||
34 | 40 | ||
35 | /* | 41 | /* |
36 | * Request BTS or PEBS | 42 | * Request BTS or PEBS |
@@ -38,60 +44,62 @@ struct task_struct; | |||
38 | * Due to alignement constraints, the actual buffer may be slightly | 44 | * Due to alignement constraints, the actual buffer may be slightly |
39 | * smaller than the requested or provided buffer. | 45 | * smaller than the requested or provided buffer. |
40 | * | 46 | * |
41 | * Returns 0 on success; -Eerrno otherwise | 47 | * Returns a pointer to a tracer structure on success, or |
48 | * ERR_PTR(errcode) on failure. | ||
49 | * | ||
50 | * The interrupt threshold is independent from the overflow callback | ||
51 | * to allow users to use their own overflow interrupt handling mechanism. | ||
42 | * | 52 | * |
43 | * task: the task to request recording for; | 53 | * task: the task to request recording for; |
44 | * NULL for per-cpu recording on the current cpu | 54 | * NULL for per-cpu recording on the current cpu |
45 | * base: the base pointer for the (non-pageable) buffer; | 55 | * base: the base pointer for the (non-pageable) buffer; |
46 | * NULL if buffer allocation requested | 56 | * size: the size of the provided buffer in bytes |
47 | * size: the size of the requested or provided buffer | ||
48 | * ovfl: pointer to a function to be called on buffer overflow; | 57 | * ovfl: pointer to a function to be called on buffer overflow; |
49 | * NULL if cyclic buffer requested | 58 | * NULL if cyclic buffer requested |
59 | * th: the interrupt threshold in records from the end of the buffer; | ||
60 | * -1 if no interrupt threshold is requested. | ||
50 | */ | 61 | */ |
51 | typedef void (*ds_ovfl_callback_t)(struct task_struct *); | 62 | extern struct bts_tracer *ds_request_bts(struct task_struct *task, |
52 | extern int ds_request_bts(struct task_struct *task, void *base, size_t size, | 63 | void *base, size_t size, |
53 | ds_ovfl_callback_t ovfl); | 64 | bts_ovfl_callback_t ovfl, size_t th); |
54 | extern int ds_request_pebs(struct task_struct *task, void *base, size_t size, | 65 | extern struct pebs_tracer *ds_request_pebs(struct task_struct *task, |
55 | ds_ovfl_callback_t ovfl); | 66 | void *base, size_t size, |
67 | pebs_ovfl_callback_t ovfl, | ||
68 | size_t th); | ||
56 | 69 | ||
57 | /* | 70 | /* |
58 | * Release BTS or PEBS resources | 71 | * Release BTS or PEBS resources |
59 | * | 72 | * |
60 | * Frees buffers allocated on ds_request. | ||
61 | * | ||
62 | * Returns 0 on success; -Eerrno otherwise | 73 | * Returns 0 on success; -Eerrno otherwise |
63 | * | 74 | * |
64 | * task: the task to release resources for; | 75 | * tracer: the tracer handle returned from ds_request_~() |
65 | * NULL to release resources for the current cpu | ||
66 | */ | 76 | */ |
67 | extern int ds_release_bts(struct task_struct *task); | 77 | extern int ds_release_bts(struct bts_tracer *tracer); |
68 | extern int ds_release_pebs(struct task_struct *task); | 78 | extern int ds_release_pebs(struct pebs_tracer *tracer); |
69 | 79 | ||
70 | /* | 80 | /* |
71 | * Return the (array) index of the write pointer. | 81 | * Get the (array) index of the write pointer. |
72 | * (assuming an array of BTS/PEBS records) | 82 | * (assuming an array of BTS/PEBS records) |
73 | * | 83 | * |
74 | * Returns -Eerrno on error | 84 | * Returns 0 on success; -Eerrno on error |
75 | * | 85 | * |
76 | * task: the task to access; | 86 | * tracer: the tracer handle returned from ds_request_~() |
77 | * NULL to access the current cpu | 87 | * pos (out): will hold the result |
78 | * pos (out): if not NULL, will hold the result | ||
79 | */ | 88 | */ |
80 | extern int ds_get_bts_index(struct task_struct *task, size_t *pos); | 89 | extern int ds_get_bts_index(struct bts_tracer *tracer, size_t *pos); |
81 | extern int ds_get_pebs_index(struct task_struct *task, size_t *pos); | 90 | extern int ds_get_pebs_index(struct pebs_tracer *tracer, size_t *pos); |
82 | 91 | ||
83 | /* | 92 | /* |
84 | * Return the (array) index one record beyond the end of the array. | 93 | * Get the (array) index one record beyond the end of the array. |
85 | * (assuming an array of BTS/PEBS records) | 94 | * (assuming an array of BTS/PEBS records) |
86 | * | 95 | * |
87 | * Returns -Eerrno on error | 96 | * Returns 0 on success; -Eerrno on error |
88 | * | 97 | * |
89 | * task: the task to access; | 98 | * tracer: the tracer handle returned from ds_request_~() |
90 | * NULL to access the current cpu | 99 | * pos (out): will hold the result |
91 | * pos (out): if not NULL, will hold the result | ||
92 | */ | 100 | */ |
93 | extern int ds_get_bts_end(struct task_struct *task, size_t *pos); | 101 | extern int ds_get_bts_end(struct bts_tracer *tracer, size_t *pos); |
94 | extern int ds_get_pebs_end(struct task_struct *task, size_t *pos); | 102 | extern int ds_get_pebs_end(struct pebs_tracer *tracer, size_t *pos); |
95 | 103 | ||
96 | /* | 104 | /* |
97 | * Provide a pointer to the BTS/PEBS record at parameter index. | 105 | * Provide a pointer to the BTS/PEBS record at parameter index. |
@@ -102,14 +110,13 @@ extern int ds_get_pebs_end(struct task_struct *task, size_t *pos); | |||
102 | * | 110 | * |
103 | * Returns the size of a single record on success; -Eerrno on error | 111 | * Returns the size of a single record on success; -Eerrno on error |
104 | * | 112 | * |
105 | * task: the task to access; | 113 | * tracer: the tracer handle returned from ds_request_~() |
106 | * NULL to access the current cpu | ||
107 | * index: the index of the requested record | 114 | * index: the index of the requested record |
108 | * record (out): pointer to the requested record | 115 | * record (out): pointer to the requested record |
109 | */ | 116 | */ |
110 | extern int ds_access_bts(struct task_struct *task, | 117 | extern int ds_access_bts(struct bts_tracer *tracer, |
111 | size_t index, const void **record); | 118 | size_t index, const void **record); |
112 | extern int ds_access_pebs(struct task_struct *task, | 119 | extern int ds_access_pebs(struct pebs_tracer *tracer, |
113 | size_t index, const void **record); | 120 | size_t index, const void **record); |
114 | 121 | ||
115 | /* | 122 | /* |
@@ -129,38 +136,24 @@ extern int ds_access_pebs(struct task_struct *task, | |||
129 | * | 136 | * |
130 | * Returns the number of bytes written or -Eerrno. | 137 | * Returns the number of bytes written or -Eerrno. |
131 | * | 138 | * |
132 | * task: the task to access; | 139 | * tracer: the tracer handle returned from ds_request_~() |
133 | * NULL to access the current cpu | ||
134 | * buffer: the buffer to write | 140 | * buffer: the buffer to write |
135 | * size: the size of the buffer | 141 | * size: the size of the buffer |
136 | */ | 142 | */ |
137 | extern int ds_write_bts(struct task_struct *task, | 143 | extern int ds_write_bts(struct bts_tracer *tracer, |
138 | const void *buffer, size_t size); | 144 | const void *buffer, size_t size); |
139 | extern int ds_write_pebs(struct task_struct *task, | 145 | extern int ds_write_pebs(struct pebs_tracer *tracer, |
140 | const void *buffer, size_t size); | 146 | const void *buffer, size_t size); |
141 | 147 | ||
142 | /* | 148 | /* |
143 | * Same as ds_write_bts/pebs, but omit ownership checks. | ||
144 | * | ||
145 | * This is needed to have some other task than the owner of the | ||
146 | * BTS/PEBS buffer or the parameter task itself write into the | ||
147 | * respective buffer. | ||
148 | */ | ||
149 | extern int ds_unchecked_write_bts(struct task_struct *task, | ||
150 | const void *buffer, size_t size); | ||
151 | extern int ds_unchecked_write_pebs(struct task_struct *task, | ||
152 | const void *buffer, size_t size); | ||
153 | |||
154 | /* | ||
155 | * Reset the write pointer of the BTS/PEBS buffer. | 149 | * Reset the write pointer of the BTS/PEBS buffer. |
156 | * | 150 | * |
157 | * Returns 0 on success; -Eerrno on error | 151 | * Returns 0 on success; -Eerrno on error |
158 | * | 152 | * |
159 | * task: the task to access; | 153 | * tracer: the tracer handle returned from ds_request_~() |
160 | * NULL to access the current cpu | ||
161 | */ | 154 | */ |
162 | extern int ds_reset_bts(struct task_struct *task); | 155 | extern int ds_reset_bts(struct bts_tracer *tracer); |
163 | extern int ds_reset_pebs(struct task_struct *task); | 156 | extern int ds_reset_pebs(struct pebs_tracer *tracer); |
164 | 157 | ||
165 | /* | 158 | /* |
166 | * Clear the BTS/PEBS buffer and reset the write pointer. | 159 | * Clear the BTS/PEBS buffer and reset the write pointer. |
@@ -168,33 +161,30 @@ extern int ds_reset_pebs(struct task_struct *task); | |||
168 | * | 161 | * |
169 | * Returns 0 on success; -Eerrno on error | 162 | * Returns 0 on success; -Eerrno on error |
170 | * | 163 | * |
171 | * task: the task to access; | 164 | * tracer: the tracer handle returned from ds_request_~() |
172 | * NULL to access the current cpu | ||
173 | */ | 165 | */ |
174 | extern int ds_clear_bts(struct task_struct *task); | 166 | extern int ds_clear_bts(struct bts_tracer *tracer); |
175 | extern int ds_clear_pebs(struct task_struct *task); | 167 | extern int ds_clear_pebs(struct pebs_tracer *tracer); |
176 | 168 | ||
177 | /* | 169 | /* |
178 | * Provide the PEBS counter reset value. | 170 | * Provide the PEBS counter reset value. |
179 | * | 171 | * |
180 | * Returns 0 on success; -Eerrno on error | 172 | * Returns 0 on success; -Eerrno on error |
181 | * | 173 | * |
182 | * task: the task to access; | 174 | * tracer: the tracer handle returned from ds_request_pebs() |
183 | * NULL to access the current cpu | ||
184 | * value (out): the counter reset value | 175 | * value (out): the counter reset value |
185 | */ | 176 | */ |
186 | extern int ds_get_pebs_reset(struct task_struct *task, u64 *value); | 177 | extern int ds_get_pebs_reset(struct pebs_tracer *tracer, u64 *value); |
187 | 178 | ||
188 | /* | 179 | /* |
189 | * Set the PEBS counter reset value. | 180 | * Set the PEBS counter reset value. |
190 | * | 181 | * |
191 | * Returns 0 on success; -Eerrno on error | 182 | * Returns 0 on success; -Eerrno on error |
192 | * | 183 | * |
193 | * task: the task to access; | 184 | * tracer: the tracer handle returned from ds_request_pebs() |
194 | * NULL to access the current cpu | ||
195 | * value: the new counter reset value | 185 | * value: the new counter reset value |
196 | */ | 186 | */ |
197 | extern int ds_set_pebs_reset(struct task_struct *task, u64 value); | 187 | extern int ds_set_pebs_reset(struct pebs_tracer *tracer, u64 value); |
198 | 188 | ||
199 | /* | 189 | /* |
200 | * Initialization | 190 | * Initialization |
@@ -207,17 +197,13 @@ extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *); | |||
207 | /* | 197 | /* |
208 | * The DS context - part of struct thread_struct. | 198 | * The DS context - part of struct thread_struct. |
209 | */ | 199 | */ |
200 | #define MAX_SIZEOF_DS (12 * 8) | ||
201 | |||
210 | struct ds_context { | 202 | struct ds_context { |
211 | /* pointer to the DS configuration; goes into MSR_IA32_DS_AREA */ | 203 | /* pointer to the DS configuration; goes into MSR_IA32_DS_AREA */ |
212 | unsigned char *ds; | 204 | unsigned char ds[MAX_SIZEOF_DS]; |
213 | /* the owner of the BTS and PEBS configuration, respectively */ | 205 | /* the owner of the BTS and PEBS configuration, respectively */ |
214 | struct task_struct *owner[2]; | 206 | struct ds_tracer *owner[2]; |
215 | /* buffer overflow notification function for BTS and PEBS */ | ||
216 | ds_ovfl_callback_t callback[2]; | ||
217 | /* the original buffer address */ | ||
218 | void *buffer[2]; | ||
219 | /* the number of allocated pages for on-request allocated buffers */ | ||
220 | unsigned int pages[2]; | ||
221 | /* use count */ | 207 | /* use count */ |
222 | unsigned long count; | 208 | unsigned long count; |
223 | /* a pointer to the context location inside the thread_struct | 209 | /* a pointer to the context location inside the thread_struct |
diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h index 9e8bc29b8b17..7e61b4ceb9a4 100644 --- a/arch/x86/include/asm/ftrace.h +++ b/arch/x86/include/asm/ftrace.h | |||
@@ -17,8 +17,40 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr) | |||
17 | */ | 17 | */ |
18 | return addr - 1; | 18 | return addr - 1; |
19 | } | 19 | } |
20 | #endif | ||
21 | 20 | ||
21 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
22 | |||
23 | struct dyn_arch_ftrace { | ||
24 | /* No extra data needed for x86 */ | ||
25 | }; | ||
26 | |||
27 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
28 | #endif /* __ASSEMBLY__ */ | ||
22 | #endif /* CONFIG_FUNCTION_TRACER */ | 29 | #endif /* CONFIG_FUNCTION_TRACER */ |
23 | 30 | ||
31 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
32 | |||
33 | #ifndef __ASSEMBLY__ | ||
34 | |||
35 | /* | ||
36 | * Stack of return addresses for functions | ||
37 | * of a thread. | ||
38 | * Used in struct thread_info | ||
39 | */ | ||
40 | struct ftrace_ret_stack { | ||
41 | unsigned long ret; | ||
42 | unsigned long func; | ||
43 | unsigned long long calltime; | ||
44 | }; | ||
45 | |||
46 | /* | ||
47 | * Primary handler of a function return. | ||
48 | * It relays on ftrace_return_to_handler. | ||
49 | * Defined in entry32.S | ||
50 | */ | ||
51 | extern void return_to_handler(void); | ||
52 | |||
53 | #endif /* __ASSEMBLY__ */ | ||
54 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
55 | |||
24 | #endif /* _ASM_X86_FTRACE_H */ | 56 | #endif /* _ASM_X86_FTRACE_H */ |
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index e44d379faad2..0921b4018c11 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h | |||
@@ -20,6 +20,8 @@ | |||
20 | struct task_struct; | 20 | struct task_struct; |
21 | struct exec_domain; | 21 | struct exec_domain; |
22 | #include <asm/processor.h> | 22 | #include <asm/processor.h> |
23 | #include <asm/ftrace.h> | ||
24 | #include <asm/atomic.h> | ||
23 | 25 | ||
24 | struct thread_info { | 26 | struct thread_info { |
25 | struct task_struct *task; /* main task structure */ | 27 | struct task_struct *task; /* main task structure */ |
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 35c54921b2e4..99192bb55a53 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h | |||
@@ -157,6 +157,7 @@ extern int __get_user_bad(void); | |||
157 | int __ret_gu; \ | 157 | int __ret_gu; \ |
158 | unsigned long __val_gu; \ | 158 | unsigned long __val_gu; \ |
159 | __chk_user_ptr(ptr); \ | 159 | __chk_user_ptr(ptr); \ |
160 | might_fault(); \ | ||
160 | switch (sizeof(*(ptr))) { \ | 161 | switch (sizeof(*(ptr))) { \ |
161 | case 1: \ | 162 | case 1: \ |
162 | __get_user_x(1, __ret_gu, __val_gu, ptr); \ | 163 | __get_user_x(1, __ret_gu, __val_gu, ptr); \ |
@@ -241,6 +242,7 @@ extern void __put_user_8(void); | |||
241 | int __ret_pu; \ | 242 | int __ret_pu; \ |
242 | __typeof__(*(ptr)) __pu_val; \ | 243 | __typeof__(*(ptr)) __pu_val; \ |
243 | __chk_user_ptr(ptr); \ | 244 | __chk_user_ptr(ptr); \ |
245 | might_fault(); \ | ||
244 | __pu_val = x; \ | 246 | __pu_val = x; \ |
245 | switch (sizeof(*(ptr))) { \ | 247 | switch (sizeof(*(ptr))) { \ |
246 | case 1: \ | 248 | case 1: \ |
diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h index d095a3aeea1b..5e06259e90e5 100644 --- a/arch/x86/include/asm/uaccess_32.h +++ b/arch/x86/include/asm/uaccess_32.h | |||
@@ -82,8 +82,8 @@ __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n) | |||
82 | static __always_inline unsigned long __must_check | 82 | static __always_inline unsigned long __must_check |
83 | __copy_to_user(void __user *to, const void *from, unsigned long n) | 83 | __copy_to_user(void __user *to, const void *from, unsigned long n) |
84 | { | 84 | { |
85 | might_sleep(); | 85 | might_fault(); |
86 | return __copy_to_user_inatomic(to, from, n); | 86 | return __copy_to_user_inatomic(to, from, n); |
87 | } | 87 | } |
88 | 88 | ||
89 | static __always_inline unsigned long | 89 | static __always_inline unsigned long |
@@ -137,7 +137,7 @@ __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n) | |||
137 | static __always_inline unsigned long | 137 | static __always_inline unsigned long |
138 | __copy_from_user(void *to, const void __user *from, unsigned long n) | 138 | __copy_from_user(void *to, const void __user *from, unsigned long n) |
139 | { | 139 | { |
140 | might_sleep(); | 140 | might_fault(); |
141 | if (__builtin_constant_p(n)) { | 141 | if (__builtin_constant_p(n)) { |
142 | unsigned long ret; | 142 | unsigned long ret; |
143 | 143 | ||
@@ -159,7 +159,7 @@ __copy_from_user(void *to, const void __user *from, unsigned long n) | |||
159 | static __always_inline unsigned long __copy_from_user_nocache(void *to, | 159 | static __always_inline unsigned long __copy_from_user_nocache(void *to, |
160 | const void __user *from, unsigned long n) | 160 | const void __user *from, unsigned long n) |
161 | { | 161 | { |
162 | might_sleep(); | 162 | might_fault(); |
163 | if (__builtin_constant_p(n)) { | 163 | if (__builtin_constant_p(n)) { |
164 | unsigned long ret; | 164 | unsigned long ret; |
165 | 165 | ||
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h index f8cfd00db450..84210c479fca 100644 --- a/arch/x86/include/asm/uaccess_64.h +++ b/arch/x86/include/asm/uaccess_64.h | |||
@@ -29,6 +29,8 @@ static __always_inline __must_check | |||
29 | int __copy_from_user(void *dst, const void __user *src, unsigned size) | 29 | int __copy_from_user(void *dst, const void __user *src, unsigned size) |
30 | { | 30 | { |
31 | int ret = 0; | 31 | int ret = 0; |
32 | |||
33 | might_fault(); | ||
32 | if (!__builtin_constant_p(size)) | 34 | if (!__builtin_constant_p(size)) |
33 | return copy_user_generic(dst, (__force void *)src, size); | 35 | return copy_user_generic(dst, (__force void *)src, size); |
34 | switch (size) { | 36 | switch (size) { |
@@ -71,6 +73,8 @@ static __always_inline __must_check | |||
71 | int __copy_to_user(void __user *dst, const void *src, unsigned size) | 73 | int __copy_to_user(void __user *dst, const void *src, unsigned size) |
72 | { | 74 | { |
73 | int ret = 0; | 75 | int ret = 0; |
76 | |||
77 | might_fault(); | ||
74 | if (!__builtin_constant_p(size)) | 78 | if (!__builtin_constant_p(size)) |
75 | return copy_user_generic((__force void *)dst, src, size); | 79 | return copy_user_generic((__force void *)dst, src, size); |
76 | switch (size) { | 80 | switch (size) { |
@@ -113,6 +117,8 @@ static __always_inline __must_check | |||
113 | int __copy_in_user(void __user *dst, const void __user *src, unsigned size) | 117 | int __copy_in_user(void __user *dst, const void __user *src, unsigned size) |
114 | { | 118 | { |
115 | int ret = 0; | 119 | int ret = 0; |
120 | |||
121 | might_fault(); | ||
116 | if (!__builtin_constant_p(size)) | 122 | if (!__builtin_constant_p(size)) |
117 | return copy_user_generic((__force void *)dst, | 123 | return copy_user_generic((__force void *)dst, |
118 | (__force void *)src, size); | 124 | (__force void *)src, size); |
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index b62a7667828e..1cad9318d217 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -25,7 +25,7 @@ CFLAGS_tsc.o := $(nostackp) | |||
25 | 25 | ||
26 | obj-y := process_$(BITS).o signal_$(BITS).o entry_$(BITS).o | 26 | obj-y := process_$(BITS).o signal_$(BITS).o entry_$(BITS).o |
27 | obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o | 27 | obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o |
28 | obj-y += time_$(BITS).o ioport.o ldt.o | 28 | obj-y += time_$(BITS).o ioport.o ldt.o dumpstack.o |
29 | obj-y += setup.o i8259.o irqinit_$(BITS).o setup_percpu.o | 29 | obj-y += setup.o i8259.o irqinit_$(BITS).o setup_percpu.o |
30 | obj-$(CONFIG_X86_VISWS) += visws_quirks.o | 30 | obj-$(CONFIG_X86_VISWS) += visws_quirks.o |
31 | obj-$(CONFIG_X86_32) += probe_roms_32.o | 31 | obj-$(CONFIG_X86_32) += probe_roms_32.o |
@@ -65,6 +65,7 @@ obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o | |||
65 | obj-$(CONFIG_X86_IO_APIC) += io_apic.o | 65 | obj-$(CONFIG_X86_IO_APIC) += io_apic.o |
66 | obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o | 66 | obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o |
67 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o | 67 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o |
68 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | ||
68 | obj-$(CONFIG_KEXEC) += machine_kexec_$(BITS).o | 69 | obj-$(CONFIG_KEXEC) += machine_kexec_$(BITS).o |
69 | obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o | 70 | obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o |
70 | obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o | 71 | obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o |
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c index 8e48c5d4467d..88ea02dcb622 100644 --- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/cpufreq.h> | 33 | #include <linux/cpufreq.h> |
34 | #include <linux/compiler.h> | 34 | #include <linux/compiler.h> |
35 | #include <linux/dmi.h> | 35 | #include <linux/dmi.h> |
36 | #include <linux/ftrace.h> | ||
36 | 37 | ||
37 | #include <linux/acpi.h> | 38 | #include <linux/acpi.h> |
38 | #include <acpi/processor.h> | 39 | #include <acpi/processor.h> |
@@ -391,6 +392,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, | |||
391 | unsigned int next_perf_state = 0; /* Index into perf table */ | 392 | unsigned int next_perf_state = 0; /* Index into perf table */ |
392 | unsigned int i; | 393 | unsigned int i; |
393 | int result = 0; | 394 | int result = 0; |
395 | struct power_trace it; | ||
394 | 396 | ||
395 | dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu); | 397 | dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu); |
396 | 398 | ||
@@ -427,6 +429,8 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, | |||
427 | } | 429 | } |
428 | } | 430 | } |
429 | 431 | ||
432 | trace_power_mark(&it, POWER_PSTATE, next_perf_state); | ||
433 | |||
430 | switch (data->cpu_feature) { | 434 | switch (data->cpu_feature) { |
431 | case SYSTEM_INTEL_MSR_CAPABLE: | 435 | case SYSTEM_INTEL_MSR_CAPABLE: |
432 | cmd.type = SYSTEM_INTEL_MSR_CAPABLE; | 436 | cmd.type = SYSTEM_INTEL_MSR_CAPABLE; |
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index cce0b6118d55..816f27f289b1 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c | |||
@@ -307,12 +307,11 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c) | |||
307 | set_cpu_cap(c, X86_FEATURE_P4); | 307 | set_cpu_cap(c, X86_FEATURE_P4); |
308 | if (c->x86 == 6) | 308 | if (c->x86 == 6) |
309 | set_cpu_cap(c, X86_FEATURE_P3); | 309 | set_cpu_cap(c, X86_FEATURE_P3); |
310 | #endif | ||
310 | 311 | ||
311 | if (cpu_has_bts) | 312 | if (cpu_has_bts) |
312 | ptrace_bts_init_intel(c); | 313 | ptrace_bts_init_intel(c); |
313 | 314 | ||
314 | #endif | ||
315 | |||
316 | detect_extended_topology(c); | 315 | detect_extended_topology(c); |
317 | if (!cpu_has(c, X86_FEATURE_XTOPOLOGY)) { | 316 | if (!cpu_has(c, X86_FEATURE_XTOPOLOGY)) { |
318 | /* | 317 | /* |
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c index a2d1176c38ee..19a8c2c0389f 100644 --- a/arch/x86/kernel/ds.c +++ b/arch/x86/kernel/ds.c | |||
@@ -7,13 +7,12 @@ | |||
7 | * | 7 | * |
8 | * It manages: | 8 | * It manages: |
9 | * - per-thread and per-cpu allocation of BTS and PEBS | 9 | * - per-thread and per-cpu allocation of BTS and PEBS |
10 | * - buffer memory allocation (optional) | 10 | * - buffer overflow handling (to be done) |
11 | * - buffer overflow handling | ||
12 | * - buffer access | 11 | * - buffer access |
13 | * | 12 | * |
14 | * It assumes: | 13 | * It assumes: |
15 | * - get_task_struct on all parameter tasks | 14 | * - get_task_struct on all traced tasks |
16 | * - current is allowed to trace parameter tasks | 15 | * - current is allowed to trace tasks |
17 | * | 16 | * |
18 | * | 17 | * |
19 | * Copyright (C) 2007-2008 Intel Corporation. | 18 | * Copyright (C) 2007-2008 Intel Corporation. |
@@ -28,6 +27,7 @@ | |||
28 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
29 | #include <linux/sched.h> | 28 | #include <linux/sched.h> |
30 | #include <linux/mm.h> | 29 | #include <linux/mm.h> |
30 | #include <linux/kernel.h> | ||
31 | 31 | ||
32 | 32 | ||
33 | /* | 33 | /* |
@@ -44,6 +44,33 @@ struct ds_configuration { | |||
44 | }; | 44 | }; |
45 | static struct ds_configuration ds_cfg; | 45 | static struct ds_configuration ds_cfg; |
46 | 46 | ||
47 | /* | ||
48 | * A BTS or PEBS tracer. | ||
49 | * | ||
50 | * This holds the configuration of the tracer and serves as a handle | ||
51 | * to identify tracers. | ||
52 | */ | ||
53 | struct ds_tracer { | ||
54 | /* the DS context (partially) owned by this tracer */ | ||
55 | struct ds_context *context; | ||
56 | /* the buffer provided on ds_request() and its size in bytes */ | ||
57 | void *buffer; | ||
58 | size_t size; | ||
59 | }; | ||
60 | |||
61 | struct bts_tracer { | ||
62 | /* the common DS part */ | ||
63 | struct ds_tracer ds; | ||
64 | /* buffer overflow notification function */ | ||
65 | bts_ovfl_callback_t ovfl; | ||
66 | }; | ||
67 | |||
68 | struct pebs_tracer { | ||
69 | /* the common DS part */ | ||
70 | struct ds_tracer ds; | ||
71 | /* buffer overflow notification function */ | ||
72 | pebs_ovfl_callback_t ovfl; | ||
73 | }; | ||
47 | 74 | ||
48 | /* | 75 | /* |
49 | * Debug Store (DS) save area configuration (see Intel64 and IA32 | 76 | * Debug Store (DS) save area configuration (see Intel64 and IA32 |
@@ -107,34 +134,13 @@ static inline void ds_set(unsigned char *base, enum ds_qualifier qual, | |||
107 | (*(unsigned long *)base) = value; | 134 | (*(unsigned long *)base) = value; |
108 | } | 135 | } |
109 | 136 | ||
137 | #define DS_ALIGNMENT (1 << 3) /* BTS and PEBS buffer alignment */ | ||
110 | 138 | ||
111 | /* | ||
112 | * Locking is done only for allocating BTS or PEBS resources and for | ||
113 | * guarding context and buffer memory allocation. | ||
114 | * | ||
115 | * Most functions require the current task to own the ds context part | ||
116 | * they are going to access. All the locking is done when validating | ||
117 | * access to the context. | ||
118 | */ | ||
119 | static spinlock_t ds_lock = __SPIN_LOCK_UNLOCKED(ds_lock); | ||
120 | 139 | ||
121 | /* | 140 | /* |
122 | * Validate that the current task is allowed to access the BTS/PEBS | 141 | * Locking is done only for allocating BTS or PEBS resources. |
123 | * buffer of the parameter task. | ||
124 | * | ||
125 | * Returns 0, if access is granted; -Eerrno, otherwise. | ||
126 | */ | 142 | */ |
127 | static inline int ds_validate_access(struct ds_context *context, | 143 | static spinlock_t ds_lock = __SPIN_LOCK_UNLOCKED(ds_lock); |
128 | enum ds_qualifier qual) | ||
129 | { | ||
130 | if (!context) | ||
131 | return -EPERM; | ||
132 | |||
133 | if (context->owner[qual] == current) | ||
134 | return 0; | ||
135 | |||
136 | return -EPERM; | ||
137 | } | ||
138 | 144 | ||
139 | 145 | ||
140 | /* | 146 | /* |
@@ -183,51 +189,13 @@ static inline int check_tracer(struct task_struct *task) | |||
183 | * | 189 | * |
184 | * Contexts are use-counted. They are allocated on first access and | 190 | * Contexts are use-counted. They are allocated on first access and |
185 | * deallocated when the last user puts the context. | 191 | * deallocated when the last user puts the context. |
186 | * | ||
187 | * We distinguish between an allocating and a non-allocating get of a | ||
188 | * context: | ||
189 | * - the allocating get is used for requesting BTS/PEBS resources. It | ||
190 | * requires the caller to hold the global ds_lock. | ||
191 | * - the non-allocating get is used for all other cases. A | ||
192 | * non-existing context indicates an error. It acquires and releases | ||
193 | * the ds_lock itself for obtaining the context. | ||
194 | * | ||
195 | * A context and its DS configuration are allocated and deallocated | ||
196 | * together. A context always has a DS configuration of the | ||
197 | * appropriate size. | ||
198 | */ | 192 | */ |
199 | static DEFINE_PER_CPU(struct ds_context *, system_context); | 193 | static DEFINE_PER_CPU(struct ds_context *, system_context); |
200 | 194 | ||
201 | #define this_system_context per_cpu(system_context, smp_processor_id()) | 195 | #define this_system_context per_cpu(system_context, smp_processor_id()) |
202 | 196 | ||
203 | /* | ||
204 | * Returns the pointer to the parameter task's context or to the | ||
205 | * system-wide context, if task is NULL. | ||
206 | * | ||
207 | * Increases the use count of the returned context, if not NULL. | ||
208 | */ | ||
209 | static inline struct ds_context *ds_get_context(struct task_struct *task) | 197 | static inline struct ds_context *ds_get_context(struct task_struct *task) |
210 | { | 198 | { |
211 | struct ds_context *context; | ||
212 | unsigned long irq; | ||
213 | |||
214 | spin_lock_irqsave(&ds_lock, irq); | ||
215 | |||
216 | context = (task ? task->thread.ds_ctx : this_system_context); | ||
217 | if (context) | ||
218 | context->count++; | ||
219 | |||
220 | spin_unlock_irqrestore(&ds_lock, irq); | ||
221 | |||
222 | return context; | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * Same as ds_get_context, but allocates the context and it's DS | ||
227 | * structure, if necessary; returns NULL; if out of memory. | ||
228 | */ | ||
229 | static inline struct ds_context *ds_alloc_context(struct task_struct *task) | ||
230 | { | ||
231 | struct ds_context **p_context = | 199 | struct ds_context **p_context = |
232 | (task ? &task->thread.ds_ctx : &this_system_context); | 200 | (task ? &task->thread.ds_ctx : &this_system_context); |
233 | struct ds_context *context = *p_context; | 201 | struct ds_context *context = *p_context; |
@@ -238,16 +206,9 @@ static inline struct ds_context *ds_alloc_context(struct task_struct *task) | |||
238 | if (!context) | 206 | if (!context) |
239 | return NULL; | 207 | return NULL; |
240 | 208 | ||
241 | context->ds = kzalloc(ds_cfg.sizeof_ds, GFP_KERNEL); | ||
242 | if (!context->ds) { | ||
243 | kfree(context); | ||
244 | return NULL; | ||
245 | } | ||
246 | |||
247 | spin_lock_irqsave(&ds_lock, irq); | 209 | spin_lock_irqsave(&ds_lock, irq); |
248 | 210 | ||
249 | if (*p_context) { | 211 | if (*p_context) { |
250 | kfree(context->ds); | ||
251 | kfree(context); | 212 | kfree(context); |
252 | 213 | ||
253 | context = *p_context; | 214 | context = *p_context; |
@@ -272,10 +233,6 @@ static inline struct ds_context *ds_alloc_context(struct task_struct *task) | |||
272 | return context; | 233 | return context; |
273 | } | 234 | } |
274 | 235 | ||
275 | /* | ||
276 | * Decreases the use count of the parameter context, if not NULL. | ||
277 | * Deallocates the context, if the use count reaches zero. | ||
278 | */ | ||
279 | static inline void ds_put_context(struct ds_context *context) | 236 | static inline void ds_put_context(struct ds_context *context) |
280 | { | 237 | { |
281 | unsigned long irq; | 238 | unsigned long irq; |
@@ -296,13 +253,6 @@ static inline void ds_put_context(struct ds_context *context) | |||
296 | if (!context->task || (context->task == current)) | 253 | if (!context->task || (context->task == current)) |
297 | wrmsrl(MSR_IA32_DS_AREA, 0); | 254 | wrmsrl(MSR_IA32_DS_AREA, 0); |
298 | 255 | ||
299 | put_tracer(context->task); | ||
300 | |||
301 | /* free any leftover buffers from tracers that did not | ||
302 | * deallocate them properly. */ | ||
303 | kfree(context->buffer[ds_bts]); | ||
304 | kfree(context->buffer[ds_pebs]); | ||
305 | kfree(context->ds); | ||
306 | kfree(context); | 256 | kfree(context); |
307 | out: | 257 | out: |
308 | spin_unlock_irqrestore(&ds_lock, irq); | 258 | spin_unlock_irqrestore(&ds_lock, irq); |
@@ -312,345 +262,342 @@ static inline void ds_put_context(struct ds_context *context) | |||
312 | /* | 262 | /* |
313 | * Handle a buffer overflow | 263 | * Handle a buffer overflow |
314 | * | 264 | * |
315 | * task: the task whose buffers are overflowing; | ||
316 | * NULL for a buffer overflow on the current cpu | ||
317 | * context: the ds context | 265 | * context: the ds context |
318 | * qual: the buffer type | 266 | * qual: the buffer type |
319 | */ | 267 | */ |
320 | static void ds_overflow(struct task_struct *task, struct ds_context *context, | 268 | static void ds_overflow(struct ds_context *context, enum ds_qualifier qual) |
321 | enum ds_qualifier qual) | 269 | { |
322 | { | 270 | switch (qual) { |
323 | if (!context) | 271 | case ds_bts: { |
324 | return; | 272 | struct bts_tracer *tracer = |
325 | 273 | container_of(context->owner[qual], | |
326 | if (context->callback[qual]) | 274 | struct bts_tracer, ds); |
327 | (*context->callback[qual])(task); | 275 | if (tracer->ovfl) |
328 | 276 | tracer->ovfl(tracer); | |
329 | /* todo: do some more overflow handling */ | 277 | } |
278 | break; | ||
279 | case ds_pebs: { | ||
280 | struct pebs_tracer *tracer = | ||
281 | container_of(context->owner[qual], | ||
282 | struct pebs_tracer, ds); | ||
283 | if (tracer->ovfl) | ||
284 | tracer->ovfl(tracer); | ||
285 | } | ||
286 | break; | ||
287 | } | ||
330 | } | 288 | } |
331 | 289 | ||
332 | 290 | ||
333 | /* | 291 | static void ds_install_ds_config(struct ds_context *context, |
334 | * Allocate a non-pageable buffer of the parameter size. | 292 | enum ds_qualifier qual, |
335 | * Checks the memory and the locked memory rlimit. | 293 | void *base, size_t size, size_t ith) |
336 | * | ||
337 | * Returns the buffer, if successful; | ||
338 | * NULL, if out of memory or rlimit exceeded. | ||
339 | * | ||
340 | * size: the requested buffer size in bytes | ||
341 | * pages (out): if not NULL, contains the number of pages reserved | ||
342 | */ | ||
343 | static inline void *ds_allocate_buffer(size_t size, unsigned int *pages) | ||
344 | { | 294 | { |
345 | unsigned long rlim, vm, pgsz; | 295 | unsigned long buffer, adj; |
346 | void *buffer; | ||
347 | |||
348 | pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT; | ||
349 | |||
350 | rlim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT; | ||
351 | vm = current->mm->total_vm + pgsz; | ||
352 | if (rlim < vm) | ||
353 | return NULL; | ||
354 | 296 | ||
355 | rlim = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT; | 297 | /* adjust the buffer address and size to meet alignment |
356 | vm = current->mm->locked_vm + pgsz; | 298 | * constraints: |
357 | if (rlim < vm) | 299 | * - buffer is double-word aligned |
358 | return NULL; | 300 | * - size is multiple of record size |
301 | * | ||
302 | * We checked the size at the very beginning; we have enough | ||
303 | * space to do the adjustment. | ||
304 | */ | ||
305 | buffer = (unsigned long)base; | ||
359 | 306 | ||
360 | buffer = kzalloc(size, GFP_KERNEL); | 307 | adj = ALIGN(buffer, DS_ALIGNMENT) - buffer; |
361 | if (!buffer) | 308 | buffer += adj; |
362 | return NULL; | 309 | size -= adj; |
363 | 310 | ||
364 | current->mm->total_vm += pgsz; | 311 | size /= ds_cfg.sizeof_rec[qual]; |
365 | current->mm->locked_vm += pgsz; | 312 | size *= ds_cfg.sizeof_rec[qual]; |
366 | 313 | ||
367 | if (pages) | 314 | ds_set(context->ds, qual, ds_buffer_base, buffer); |
368 | *pages = pgsz; | 315 | ds_set(context->ds, qual, ds_index, buffer); |
316 | ds_set(context->ds, qual, ds_absolute_maximum, buffer + size); | ||
369 | 317 | ||
370 | return buffer; | 318 | /* The value for 'no threshold' is -1, which will set the |
319 | * threshold outside of the buffer, just like we want it. | ||
320 | */ | ||
321 | ds_set(context->ds, qual, | ||
322 | ds_interrupt_threshold, buffer + size - ith); | ||
371 | } | 323 | } |
372 | 324 | ||
373 | static int ds_request(struct task_struct *task, void *base, size_t size, | 325 | static int ds_request(struct ds_tracer *tracer, enum ds_qualifier qual, |
374 | ds_ovfl_callback_t ovfl, enum ds_qualifier qual) | 326 | struct task_struct *task, |
327 | void *base, size_t size, size_t th) | ||
375 | { | 328 | { |
376 | struct ds_context *context; | 329 | struct ds_context *context; |
377 | unsigned long buffer, adj; | ||
378 | const unsigned long alignment = (1 << 3); | ||
379 | unsigned long irq; | 330 | unsigned long irq; |
380 | int error = 0; | 331 | int error; |
381 | 332 | ||
333 | error = -EOPNOTSUPP; | ||
382 | if (!ds_cfg.sizeof_ds) | 334 | if (!ds_cfg.sizeof_ds) |
383 | return -EOPNOTSUPP; | 335 | goto out; |
336 | |||
337 | error = -EINVAL; | ||
338 | if (!base) | ||
339 | goto out; | ||
384 | 340 | ||
385 | /* we require some space to do alignment adjustments below */ | 341 | /* we require some space to do alignment adjustments below */ |
386 | if (size < (alignment + ds_cfg.sizeof_rec[qual])) | 342 | error = -EINVAL; |
387 | return -EINVAL; | 343 | if (size < (DS_ALIGNMENT + ds_cfg.sizeof_rec[qual])) |
344 | goto out; | ||
388 | 345 | ||
389 | /* buffer overflow notification is not yet implemented */ | 346 | if (th != (size_t)-1) { |
390 | if (ovfl) | 347 | th *= ds_cfg.sizeof_rec[qual]; |
391 | return -EOPNOTSUPP; | 348 | |
349 | error = -EINVAL; | ||
350 | if (size <= th) | ||
351 | goto out; | ||
352 | } | ||
392 | 353 | ||
354 | tracer->buffer = base; | ||
355 | tracer->size = size; | ||
393 | 356 | ||
394 | context = ds_alloc_context(task); | 357 | error = -ENOMEM; |
358 | context = ds_get_context(task); | ||
395 | if (!context) | 359 | if (!context) |
396 | return -ENOMEM; | 360 | goto out; |
361 | tracer->context = context; | ||
362 | |||
397 | 363 | ||
398 | spin_lock_irqsave(&ds_lock, irq); | 364 | spin_lock_irqsave(&ds_lock, irq); |
399 | 365 | ||
400 | error = -EPERM; | 366 | error = -EPERM; |
401 | if (!check_tracer(task)) | 367 | if (!check_tracer(task)) |
402 | goto out_unlock; | 368 | goto out_unlock; |
403 | |||
404 | get_tracer(task); | 369 | get_tracer(task); |
405 | 370 | ||
406 | error = -EALREADY; | ||
407 | if (context->owner[qual] == current) | ||
408 | goto out_put_tracer; | ||
409 | error = -EPERM; | 371 | error = -EPERM; |
410 | if (context->owner[qual] != NULL) | 372 | if (context->owner[qual]) |
411 | goto out_put_tracer; | 373 | goto out_put_tracer; |
412 | context->owner[qual] = current; | 374 | context->owner[qual] = tracer; |
413 | 375 | ||
414 | spin_unlock_irqrestore(&ds_lock, irq); | 376 | spin_unlock_irqrestore(&ds_lock, irq); |
415 | 377 | ||
416 | 378 | ||
417 | error = -ENOMEM; | 379 | ds_install_ds_config(context, qual, base, size, th); |
418 | if (!base) { | ||
419 | base = ds_allocate_buffer(size, &context->pages[qual]); | ||
420 | if (!base) | ||
421 | goto out_release; | ||
422 | |||
423 | context->buffer[qual] = base; | ||
424 | } | ||
425 | error = 0; | ||
426 | 380 | ||
427 | context->callback[qual] = ovfl; | 381 | return 0; |
428 | |||
429 | /* adjust the buffer address and size to meet alignment | ||
430 | * constraints: | ||
431 | * - buffer is double-word aligned | ||
432 | * - size is multiple of record size | ||
433 | * | ||
434 | * We checked the size at the very beginning; we have enough | ||
435 | * space to do the adjustment. | ||
436 | */ | ||
437 | buffer = (unsigned long)base; | ||
438 | |||
439 | adj = ALIGN(buffer, alignment) - buffer; | ||
440 | buffer += adj; | ||
441 | size -= adj; | ||
442 | |||
443 | size /= ds_cfg.sizeof_rec[qual]; | ||
444 | size *= ds_cfg.sizeof_rec[qual]; | ||
445 | |||
446 | ds_set(context->ds, qual, ds_buffer_base, buffer); | ||
447 | ds_set(context->ds, qual, ds_index, buffer); | ||
448 | ds_set(context->ds, qual, ds_absolute_maximum, buffer + size); | ||
449 | |||
450 | if (ovfl) { | ||
451 | /* todo: select a suitable interrupt threshold */ | ||
452 | } else | ||
453 | ds_set(context->ds, qual, | ||
454 | ds_interrupt_threshold, buffer + size + 1); | ||
455 | |||
456 | /* we keep the context until ds_release */ | ||
457 | return error; | ||
458 | |||
459 | out_release: | ||
460 | context->owner[qual] = NULL; | ||
461 | ds_put_context(context); | ||
462 | put_tracer(task); | ||
463 | return error; | ||
464 | 382 | ||
465 | out_put_tracer: | 383 | out_put_tracer: |
466 | spin_unlock_irqrestore(&ds_lock, irq); | ||
467 | ds_put_context(context); | ||
468 | put_tracer(task); | 384 | put_tracer(task); |
469 | return error; | ||
470 | |||
471 | out_unlock: | 385 | out_unlock: |
472 | spin_unlock_irqrestore(&ds_lock, irq); | 386 | spin_unlock_irqrestore(&ds_lock, irq); |
473 | ds_put_context(context); | 387 | ds_put_context(context); |
388 | tracer->context = NULL; | ||
389 | out: | ||
474 | return error; | 390 | return error; |
475 | } | 391 | } |
476 | 392 | ||
477 | int ds_request_bts(struct task_struct *task, void *base, size_t size, | 393 | struct bts_tracer *ds_request_bts(struct task_struct *task, |
478 | ds_ovfl_callback_t ovfl) | 394 | void *base, size_t size, |
395 | bts_ovfl_callback_t ovfl, size_t th) | ||
479 | { | 396 | { |
480 | return ds_request(task, base, size, ovfl, ds_bts); | 397 | struct bts_tracer *tracer; |
481 | } | 398 | int error; |
482 | 399 | ||
483 | int ds_request_pebs(struct task_struct *task, void *base, size_t size, | 400 | /* buffer overflow notification is not yet implemented */ |
484 | ds_ovfl_callback_t ovfl) | 401 | error = -EOPNOTSUPP; |
485 | { | 402 | if (ovfl) |
486 | return ds_request(task, base, size, ovfl, ds_pebs); | 403 | goto out; |
404 | |||
405 | error = -ENOMEM; | ||
406 | tracer = kzalloc(sizeof(*tracer), GFP_KERNEL); | ||
407 | if (!tracer) | ||
408 | goto out; | ||
409 | tracer->ovfl = ovfl; | ||
410 | |||
411 | error = ds_request(&tracer->ds, ds_bts, task, base, size, th); | ||
412 | if (error < 0) | ||
413 | goto out_tracer; | ||
414 | |||
415 | return tracer; | ||
416 | |||
417 | out_tracer: | ||
418 | kfree(tracer); | ||
419 | out: | ||
420 | return ERR_PTR(error); | ||
487 | } | 421 | } |
488 | 422 | ||
489 | static int ds_release(struct task_struct *task, enum ds_qualifier qual) | 423 | struct pebs_tracer *ds_request_pebs(struct task_struct *task, |
424 | void *base, size_t size, | ||
425 | pebs_ovfl_callback_t ovfl, size_t th) | ||
490 | { | 426 | { |
491 | struct ds_context *context; | 427 | struct pebs_tracer *tracer; |
492 | int error; | 428 | int error; |
493 | 429 | ||
494 | context = ds_get_context(task); | 430 | /* buffer overflow notification is not yet implemented */ |
495 | error = ds_validate_access(context, qual); | 431 | error = -EOPNOTSUPP; |
496 | if (error < 0) | 432 | if (ovfl) |
497 | goto out; | 433 | goto out; |
498 | 434 | ||
499 | kfree(context->buffer[qual]); | 435 | error = -ENOMEM; |
500 | context->buffer[qual] = NULL; | 436 | tracer = kzalloc(sizeof(*tracer), GFP_KERNEL); |
437 | if (!tracer) | ||
438 | goto out; | ||
439 | tracer->ovfl = ovfl; | ||
501 | 440 | ||
502 | current->mm->total_vm -= context->pages[qual]; | 441 | error = ds_request(&tracer->ds, ds_pebs, task, base, size, th); |
503 | current->mm->locked_vm -= context->pages[qual]; | 442 | if (error < 0) |
504 | context->pages[qual] = 0; | 443 | goto out_tracer; |
505 | context->owner[qual] = NULL; | ||
506 | 444 | ||
507 | /* | 445 | return tracer; |
508 | * we put the context twice: | 446 | |
509 | * once for the ds_get_context | 447 | out_tracer: |
510 | * once for the corresponding ds_request | 448 | kfree(tracer); |
511 | */ | ||
512 | ds_put_context(context); | ||
513 | out: | 449 | out: |
514 | ds_put_context(context); | 450 | return ERR_PTR(error); |
515 | return error; | ||
516 | } | 451 | } |
517 | 452 | ||
518 | int ds_release_bts(struct task_struct *task) | 453 | static void ds_release(struct ds_tracer *tracer, enum ds_qualifier qual) |
519 | { | 454 | { |
520 | return ds_release(task, ds_bts); | 455 | BUG_ON(tracer->context->owner[qual] != tracer); |
456 | tracer->context->owner[qual] = NULL; | ||
457 | |||
458 | put_tracer(tracer->context->task); | ||
459 | ds_put_context(tracer->context); | ||
521 | } | 460 | } |
522 | 461 | ||
523 | int ds_release_pebs(struct task_struct *task) | 462 | int ds_release_bts(struct bts_tracer *tracer) |
524 | { | 463 | { |
525 | return ds_release(task, ds_pebs); | 464 | if (!tracer) |
465 | return -EINVAL; | ||
466 | |||
467 | ds_release(&tracer->ds, ds_bts); | ||
468 | kfree(tracer); | ||
469 | |||
470 | return 0; | ||
526 | } | 471 | } |
527 | 472 | ||
528 | static int ds_get_index(struct task_struct *task, size_t *pos, | 473 | int ds_release_pebs(struct pebs_tracer *tracer) |
529 | enum ds_qualifier qual) | ||
530 | { | 474 | { |
531 | struct ds_context *context; | 475 | if (!tracer) |
532 | unsigned long base, index; | 476 | return -EINVAL; |
533 | int error; | ||
534 | 477 | ||
535 | context = ds_get_context(task); | 478 | ds_release(&tracer->ds, ds_pebs); |
536 | error = ds_validate_access(context, qual); | 479 | kfree(tracer); |
537 | if (error < 0) | 480 | |
538 | goto out; | 481 | return 0; |
482 | } | ||
483 | |||
484 | static size_t ds_get_index(struct ds_context *context, enum ds_qualifier qual) | ||
485 | { | ||
486 | unsigned long base, index; | ||
539 | 487 | ||
540 | base = ds_get(context->ds, qual, ds_buffer_base); | 488 | base = ds_get(context->ds, qual, ds_buffer_base); |
541 | index = ds_get(context->ds, qual, ds_index); | 489 | index = ds_get(context->ds, qual, ds_index); |
542 | 490 | ||
543 | error = ((index - base) / ds_cfg.sizeof_rec[qual]); | 491 | return (index - base) / ds_cfg.sizeof_rec[qual]; |
544 | if (pos) | ||
545 | *pos = error; | ||
546 | out: | ||
547 | ds_put_context(context); | ||
548 | return error; | ||
549 | } | 492 | } |
550 | 493 | ||
551 | int ds_get_bts_index(struct task_struct *task, size_t *pos) | 494 | int ds_get_bts_index(struct bts_tracer *tracer, size_t *pos) |
552 | { | 495 | { |
553 | return ds_get_index(task, pos, ds_bts); | 496 | if (!tracer) |
497 | return -EINVAL; | ||
498 | |||
499 | if (!pos) | ||
500 | return -EINVAL; | ||
501 | |||
502 | *pos = ds_get_index(tracer->ds.context, ds_bts); | ||
503 | |||
504 | return 0; | ||
554 | } | 505 | } |
555 | 506 | ||
556 | int ds_get_pebs_index(struct task_struct *task, size_t *pos) | 507 | int ds_get_pebs_index(struct pebs_tracer *tracer, size_t *pos) |
557 | { | 508 | { |
558 | return ds_get_index(task, pos, ds_pebs); | 509 | if (!tracer) |
510 | return -EINVAL; | ||
511 | |||
512 | if (!pos) | ||
513 | return -EINVAL; | ||
514 | |||
515 | *pos = ds_get_index(tracer->ds.context, ds_pebs); | ||
516 | |||
517 | return 0; | ||
559 | } | 518 | } |
560 | 519 | ||
561 | static int ds_get_end(struct task_struct *task, size_t *pos, | 520 | static size_t ds_get_end(struct ds_context *context, enum ds_qualifier qual) |
562 | enum ds_qualifier qual) | ||
563 | { | 521 | { |
564 | struct ds_context *context; | 522 | unsigned long base, max; |
565 | unsigned long base, end; | ||
566 | int error; | ||
567 | |||
568 | context = ds_get_context(task); | ||
569 | error = ds_validate_access(context, qual); | ||
570 | if (error < 0) | ||
571 | goto out; | ||
572 | 523 | ||
573 | base = ds_get(context->ds, qual, ds_buffer_base); | 524 | base = ds_get(context->ds, qual, ds_buffer_base); |
574 | end = ds_get(context->ds, qual, ds_absolute_maximum); | 525 | max = ds_get(context->ds, qual, ds_absolute_maximum); |
575 | 526 | ||
576 | error = ((end - base) / ds_cfg.sizeof_rec[qual]); | 527 | return (max - base) / ds_cfg.sizeof_rec[qual]; |
577 | if (pos) | ||
578 | *pos = error; | ||
579 | out: | ||
580 | ds_put_context(context); | ||
581 | return error; | ||
582 | } | 528 | } |
583 | 529 | ||
584 | int ds_get_bts_end(struct task_struct *task, size_t *pos) | 530 | int ds_get_bts_end(struct bts_tracer *tracer, size_t *pos) |
585 | { | 531 | { |
586 | return ds_get_end(task, pos, ds_bts); | 532 | if (!tracer) |
533 | return -EINVAL; | ||
534 | |||
535 | if (!pos) | ||
536 | return -EINVAL; | ||
537 | |||
538 | *pos = ds_get_end(tracer->ds.context, ds_bts); | ||
539 | |||
540 | return 0; | ||
587 | } | 541 | } |
588 | 542 | ||
589 | int ds_get_pebs_end(struct task_struct *task, size_t *pos) | 543 | int ds_get_pebs_end(struct pebs_tracer *tracer, size_t *pos) |
590 | { | 544 | { |
591 | return ds_get_end(task, pos, ds_pebs); | 545 | if (!tracer) |
546 | return -EINVAL; | ||
547 | |||
548 | if (!pos) | ||
549 | return -EINVAL; | ||
550 | |||
551 | *pos = ds_get_end(tracer->ds.context, ds_pebs); | ||
552 | |||
553 | return 0; | ||
592 | } | 554 | } |
593 | 555 | ||
594 | static int ds_access(struct task_struct *task, size_t index, | 556 | static int ds_access(struct ds_context *context, enum ds_qualifier qual, |
595 | const void **record, enum ds_qualifier qual) | 557 | size_t index, const void **record) |
596 | { | 558 | { |
597 | struct ds_context *context; | ||
598 | unsigned long base, idx; | 559 | unsigned long base, idx; |
599 | int error; | ||
600 | 560 | ||
601 | if (!record) | 561 | if (!record) |
602 | return -EINVAL; | 562 | return -EINVAL; |
603 | 563 | ||
604 | context = ds_get_context(task); | ||
605 | error = ds_validate_access(context, qual); | ||
606 | if (error < 0) | ||
607 | goto out; | ||
608 | |||
609 | base = ds_get(context->ds, qual, ds_buffer_base); | 564 | base = ds_get(context->ds, qual, ds_buffer_base); |
610 | idx = base + (index * ds_cfg.sizeof_rec[qual]); | 565 | idx = base + (index * ds_cfg.sizeof_rec[qual]); |
611 | 566 | ||
612 | error = -EINVAL; | ||
613 | if (idx > ds_get(context->ds, qual, ds_absolute_maximum)) | 567 | if (idx > ds_get(context->ds, qual, ds_absolute_maximum)) |
614 | goto out; | 568 | return -EINVAL; |
615 | 569 | ||
616 | *record = (const void *)idx; | 570 | *record = (const void *)idx; |
617 | error = ds_cfg.sizeof_rec[qual]; | 571 | |
618 | out: | 572 | return ds_cfg.sizeof_rec[qual]; |
619 | ds_put_context(context); | ||
620 | return error; | ||
621 | } | 573 | } |
622 | 574 | ||
623 | int ds_access_bts(struct task_struct *task, size_t index, const void **record) | 575 | int ds_access_bts(struct bts_tracer *tracer, size_t index, |
576 | const void **record) | ||
624 | { | 577 | { |
625 | return ds_access(task, index, record, ds_bts); | 578 | if (!tracer) |
579 | return -EINVAL; | ||
580 | |||
581 | return ds_access(tracer->ds.context, ds_bts, index, record); | ||
626 | } | 582 | } |
627 | 583 | ||
628 | int ds_access_pebs(struct task_struct *task, size_t index, const void **record) | 584 | int ds_access_pebs(struct pebs_tracer *tracer, size_t index, |
585 | const void **record) | ||
629 | { | 586 | { |
630 | return ds_access(task, index, record, ds_pebs); | 587 | if (!tracer) |
588 | return -EINVAL; | ||
589 | |||
590 | return ds_access(tracer->ds.context, ds_pebs, index, record); | ||
631 | } | 591 | } |
632 | 592 | ||
633 | static int ds_write(struct task_struct *task, const void *record, size_t size, | 593 | static int ds_write(struct ds_context *context, enum ds_qualifier qual, |
634 | enum ds_qualifier qual, int force) | 594 | const void *record, size_t size) |
635 | { | 595 | { |
636 | struct ds_context *context; | 596 | int bytes_written = 0; |
637 | int error; | ||
638 | 597 | ||
639 | if (!record) | 598 | if (!record) |
640 | return -EINVAL; | 599 | return -EINVAL; |
641 | 600 | ||
642 | error = -EPERM; | ||
643 | context = ds_get_context(task); | ||
644 | if (!context) | ||
645 | goto out; | ||
646 | |||
647 | if (!force) { | ||
648 | error = ds_validate_access(context, qual); | ||
649 | if (error < 0) | ||
650 | goto out; | ||
651 | } | ||
652 | |||
653 | error = 0; | ||
654 | while (size) { | 601 | while (size) { |
655 | unsigned long base, index, end, write_end, int_th; | 602 | unsigned long base, index, end, write_end, int_th; |
656 | unsigned long write_size, adj_write_size; | 603 | unsigned long write_size, adj_write_size; |
@@ -678,14 +625,14 @@ static int ds_write(struct task_struct *task, const void *record, size_t size, | |||
678 | write_end = end; | 625 | write_end = end; |
679 | 626 | ||
680 | if (write_end <= index) | 627 | if (write_end <= index) |
681 | goto out; | 628 | break; |
682 | 629 | ||
683 | write_size = min((unsigned long) size, write_end - index); | 630 | write_size = min((unsigned long) size, write_end - index); |
684 | memcpy((void *)index, record, write_size); | 631 | memcpy((void *)index, record, write_size); |
685 | 632 | ||
686 | record = (const char *)record + write_size; | 633 | record = (const char *)record + write_size; |
687 | size -= write_size; | 634 | size -= write_size; |
688 | error += write_size; | 635 | bytes_written += write_size; |
689 | 636 | ||
690 | adj_write_size = write_size / ds_cfg.sizeof_rec[qual]; | 637 | adj_write_size = write_size / ds_cfg.sizeof_rec[qual]; |
691 | adj_write_size *= ds_cfg.sizeof_rec[qual]; | 638 | adj_write_size *= ds_cfg.sizeof_rec[qual]; |
@@ -700,47 +647,32 @@ static int ds_write(struct task_struct *task, const void *record, size_t size, | |||
700 | ds_set(context->ds, qual, ds_index, index); | 647 | ds_set(context->ds, qual, ds_index, index); |
701 | 648 | ||
702 | if (index >= int_th) | 649 | if (index >= int_th) |
703 | ds_overflow(task, context, qual); | 650 | ds_overflow(context, qual); |
704 | } | 651 | } |
705 | 652 | ||
706 | out: | 653 | return bytes_written; |
707 | ds_put_context(context); | ||
708 | return error; | ||
709 | } | 654 | } |
710 | 655 | ||
711 | int ds_write_bts(struct task_struct *task, const void *record, size_t size) | 656 | int ds_write_bts(struct bts_tracer *tracer, const void *record, size_t size) |
712 | { | 657 | { |
713 | return ds_write(task, record, size, ds_bts, /* force = */ 0); | 658 | if (!tracer) |
714 | } | 659 | return -EINVAL; |
715 | 660 | ||
716 | int ds_write_pebs(struct task_struct *task, const void *record, size_t size) | 661 | return ds_write(tracer->ds.context, ds_bts, record, size); |
717 | { | ||
718 | return ds_write(task, record, size, ds_pebs, /* force = */ 0); | ||
719 | } | 662 | } |
720 | 663 | ||
721 | int ds_unchecked_write_bts(struct task_struct *task, | 664 | int ds_write_pebs(struct pebs_tracer *tracer, const void *record, size_t size) |
722 | const void *record, size_t size) | ||
723 | { | 665 | { |
724 | return ds_write(task, record, size, ds_bts, /* force = */ 1); | 666 | if (!tracer) |
725 | } | 667 | return -EINVAL; |
726 | 668 | ||
727 | int ds_unchecked_write_pebs(struct task_struct *task, | 669 | return ds_write(tracer->ds.context, ds_pebs, record, size); |
728 | const void *record, size_t size) | ||
729 | { | ||
730 | return ds_write(task, record, size, ds_pebs, /* force = */ 1); | ||
731 | } | 670 | } |
732 | 671 | ||
733 | static int ds_reset_or_clear(struct task_struct *task, | 672 | static void ds_reset_or_clear(struct ds_context *context, |
734 | enum ds_qualifier qual, int clear) | 673 | enum ds_qualifier qual, int clear) |
735 | { | 674 | { |
736 | struct ds_context *context; | ||
737 | unsigned long base, end; | 675 | unsigned long base, end; |
738 | int error; | ||
739 | |||
740 | context = ds_get_context(task); | ||
741 | error = ds_validate_access(context, qual); | ||
742 | if (error < 0) | ||
743 | goto out; | ||
744 | 676 | ||
745 | base = ds_get(context->ds, qual, ds_buffer_base); | 677 | base = ds_get(context->ds, qual, ds_buffer_base); |
746 | end = ds_get(context->ds, qual, ds_absolute_maximum); | 678 | end = ds_get(context->ds, qual, ds_absolute_maximum); |
@@ -749,70 +681,69 @@ static int ds_reset_or_clear(struct task_struct *task, | |||
749 | memset((void *)base, 0, end - base); | 681 | memset((void *)base, 0, end - base); |
750 | 682 | ||
751 | ds_set(context->ds, qual, ds_index, base); | 683 | ds_set(context->ds, qual, ds_index, base); |
752 | |||
753 | error = 0; | ||
754 | out: | ||
755 | ds_put_context(context); | ||
756 | return error; | ||
757 | } | 684 | } |
758 | 685 | ||
759 | int ds_reset_bts(struct task_struct *task) | 686 | int ds_reset_bts(struct bts_tracer *tracer) |
760 | { | 687 | { |
761 | return ds_reset_or_clear(task, ds_bts, /* clear = */ 0); | 688 | if (!tracer) |
689 | return -EINVAL; | ||
690 | |||
691 | ds_reset_or_clear(tracer->ds.context, ds_bts, /* clear = */ 0); | ||
692 | |||
693 | return 0; | ||
762 | } | 694 | } |
763 | 695 | ||
764 | int ds_reset_pebs(struct task_struct *task) | 696 | int ds_reset_pebs(struct pebs_tracer *tracer) |
765 | { | 697 | { |
766 | return ds_reset_or_clear(task, ds_pebs, /* clear = */ 0); | 698 | if (!tracer) |
699 | return -EINVAL; | ||
700 | |||
701 | ds_reset_or_clear(tracer->ds.context, ds_pebs, /* clear = */ 0); | ||
702 | |||
703 | return 0; | ||
767 | } | 704 | } |
768 | 705 | ||
769 | int ds_clear_bts(struct task_struct *task) | 706 | int ds_clear_bts(struct bts_tracer *tracer) |
770 | { | 707 | { |
771 | return ds_reset_or_clear(task, ds_bts, /* clear = */ 1); | 708 | if (!tracer) |
709 | return -EINVAL; | ||
710 | |||
711 | ds_reset_or_clear(tracer->ds.context, ds_bts, /* clear = */ 1); | ||
712 | |||
713 | return 0; | ||
772 | } | 714 | } |
773 | 715 | ||
774 | int ds_clear_pebs(struct task_struct *task) | 716 | int ds_clear_pebs(struct pebs_tracer *tracer) |
775 | { | 717 | { |
776 | return ds_reset_or_clear(task, ds_pebs, /* clear = */ 1); | 718 | if (!tracer) |
719 | return -EINVAL; | ||
720 | |||
721 | ds_reset_or_clear(tracer->ds.context, ds_pebs, /* clear = */ 1); | ||
722 | |||
723 | return 0; | ||
777 | } | 724 | } |
778 | 725 | ||
779 | int ds_get_pebs_reset(struct task_struct *task, u64 *value) | 726 | int ds_get_pebs_reset(struct pebs_tracer *tracer, u64 *value) |
780 | { | 727 | { |
781 | struct ds_context *context; | 728 | if (!tracer) |
782 | int error; | 729 | return -EINVAL; |
783 | 730 | ||
784 | if (!value) | 731 | if (!value) |
785 | return -EINVAL; | 732 | return -EINVAL; |
786 | 733 | ||
787 | context = ds_get_context(task); | 734 | *value = *(u64 *)(tracer->ds.context->ds + (ds_cfg.sizeof_field * 8)); |
788 | error = ds_validate_access(context, ds_pebs); | ||
789 | if (error < 0) | ||
790 | goto out; | ||
791 | 735 | ||
792 | *value = *(u64 *)(context->ds + (ds_cfg.sizeof_field * 8)); | 736 | return 0; |
793 | |||
794 | error = 0; | ||
795 | out: | ||
796 | ds_put_context(context); | ||
797 | return error; | ||
798 | } | 737 | } |
799 | 738 | ||
800 | int ds_set_pebs_reset(struct task_struct *task, u64 value) | 739 | int ds_set_pebs_reset(struct pebs_tracer *tracer, u64 value) |
801 | { | 740 | { |
802 | struct ds_context *context; | 741 | if (!tracer) |
803 | int error; | 742 | return -EINVAL; |
804 | |||
805 | context = ds_get_context(task); | ||
806 | error = ds_validate_access(context, ds_pebs); | ||
807 | if (error < 0) | ||
808 | goto out; | ||
809 | 743 | ||
810 | *(u64 *)(context->ds + (ds_cfg.sizeof_field * 8)) = value; | 744 | *(u64 *)(tracer->ds.context->ds + (ds_cfg.sizeof_field * 8)) = value; |
811 | 745 | ||
812 | error = 0; | 746 | return 0; |
813 | out: | ||
814 | ds_put_context(context); | ||
815 | return error; | ||
816 | } | 747 | } |
817 | 748 | ||
818 | static const struct ds_configuration ds_cfg_var = { | 749 | static const struct ds_configuration ds_cfg_var = { |
@@ -840,6 +771,10 @@ static inline void | |||
840 | ds_configure(const struct ds_configuration *cfg) | 771 | ds_configure(const struct ds_configuration *cfg) |
841 | { | 772 | { |
842 | ds_cfg = *cfg; | 773 | ds_cfg = *cfg; |
774 | |||
775 | printk(KERN_INFO "DS available\n"); | ||
776 | |||
777 | BUG_ON(MAX_SIZEOF_DS < ds_cfg.sizeof_ds); | ||
843 | } | 778 | } |
844 | 779 | ||
845 | void __cpuinit ds_init_intel(struct cpuinfo_x86 *c) | 780 | void __cpuinit ds_init_intel(struct cpuinfo_x86 *c) |
@@ -847,17 +782,16 @@ void __cpuinit ds_init_intel(struct cpuinfo_x86 *c) | |||
847 | switch (c->x86) { | 782 | switch (c->x86) { |
848 | case 0x6: | 783 | case 0x6: |
849 | switch (c->x86_model) { | 784 | switch (c->x86_model) { |
785 | case 0 ... 0xC: | ||
786 | /* sorry, don't know about them */ | ||
787 | break; | ||
850 | case 0xD: | 788 | case 0xD: |
851 | case 0xE: /* Pentium M */ | 789 | case 0xE: /* Pentium M */ |
852 | ds_configure(&ds_cfg_var); | 790 | ds_configure(&ds_cfg_var); |
853 | break; | 791 | break; |
854 | case 0xF: /* Core2 */ | 792 | default: /* Core2, Atom, ... */ |
855 | case 0x1C: /* Atom */ | ||
856 | ds_configure(&ds_cfg_64); | 793 | ds_configure(&ds_cfg_64); |
857 | break; | 794 | break; |
858 | default: | ||
859 | /* sorry, don't know about them */ | ||
860 | break; | ||
861 | } | 795 | } |
862 | break; | 796 | break; |
863 | case 0xF: | 797 | case 0xF: |
@@ -884,6 +818,8 @@ void ds_free(struct ds_context *context) | |||
884 | * is dying. There should not be any user of that context left | 818 | * is dying. There should not be any user of that context left |
885 | * to disturb us, anymore. */ | 819 | * to disturb us, anymore. */ |
886 | unsigned long leftovers = context->count; | 820 | unsigned long leftovers = context->count; |
887 | while (leftovers--) | 821 | while (leftovers--) { |
822 | put_tracer(context->task); | ||
888 | ds_put_context(context); | 823 | ds_put_context(context); |
824 | } | ||
889 | } | 825 | } |
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c new file mode 100644 index 000000000000..6b1f6f6f8661 --- /dev/null +++ b/arch/x86/kernel/dumpstack.c | |||
@@ -0,0 +1,351 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
3 | * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs | ||
4 | */ | ||
5 | #include <linux/kallsyms.h> | ||
6 | #include <linux/kprobes.h> | ||
7 | #include <linux/uaccess.h> | ||
8 | #include <linux/utsname.h> | ||
9 | #include <linux/hardirq.h> | ||
10 | #include <linux/kdebug.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/ptrace.h> | ||
13 | #include <linux/kexec.h> | ||
14 | #include <linux/bug.h> | ||
15 | #include <linux/nmi.h> | ||
16 | #include <linux/sysfs.h> | ||
17 | |||
18 | #include <asm/stacktrace.h> | ||
19 | |||
20 | #include "dumpstack.h" | ||
21 | |||
22 | int panic_on_unrecovered_nmi; | ||
23 | unsigned int code_bytes = 64; | ||
24 | int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE; | ||
25 | static int die_counter; | ||
26 | |||
27 | void printk_address(unsigned long address, int reliable) | ||
28 | { | ||
29 | printk(" [<%p>] %s%pS\n", (void *) address, | ||
30 | reliable ? "" : "? ", (void *) address); | ||
31 | } | ||
32 | |||
33 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
34 | static void | ||
35 | print_ftrace_graph_addr(unsigned long addr, void *data, | ||
36 | const struct stacktrace_ops *ops, | ||
37 | struct thread_info *tinfo, int *graph) | ||
38 | { | ||
39 | struct task_struct *task = tinfo->task; | ||
40 | unsigned long ret_addr; | ||
41 | int index = task->curr_ret_stack; | ||
42 | |||
43 | if (addr != (unsigned long)return_to_handler) | ||
44 | return; | ||
45 | |||
46 | if (!task->ret_stack || index < *graph) | ||
47 | return; | ||
48 | |||
49 | index -= *graph; | ||
50 | ret_addr = task->ret_stack[index].ret; | ||
51 | |||
52 | ops->address(data, ret_addr, 1); | ||
53 | |||
54 | (*graph)++; | ||
55 | } | ||
56 | #else | ||
57 | static inline void | ||
58 | print_ftrace_graph_addr(unsigned long addr, void *data, | ||
59 | const struct stacktrace_ops *ops, | ||
60 | struct thread_info *tinfo, int *graph) | ||
61 | { } | ||
62 | #endif | ||
63 | |||
64 | /* | ||
65 | * x86-64 can have up to three kernel stacks: | ||
66 | * process stack | ||
67 | * interrupt stack | ||
68 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack | ||
69 | */ | ||
70 | |||
71 | static inline int valid_stack_ptr(struct thread_info *tinfo, | ||
72 | void *p, unsigned int size, void *end) | ||
73 | { | ||
74 | void *t = tinfo; | ||
75 | if (end) { | ||
76 | if (p < end && p >= (end-THREAD_SIZE)) | ||
77 | return 1; | ||
78 | else | ||
79 | return 0; | ||
80 | } | ||
81 | return p > t && p < t + THREAD_SIZE - size; | ||
82 | } | ||
83 | |||
84 | unsigned long | ||
85 | print_context_stack(struct thread_info *tinfo, | ||
86 | unsigned long *stack, unsigned long bp, | ||
87 | const struct stacktrace_ops *ops, void *data, | ||
88 | unsigned long *end, int *graph) | ||
89 | { | ||
90 | struct stack_frame *frame = (struct stack_frame *)bp; | ||
91 | |||
92 | while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) { | ||
93 | unsigned long addr; | ||
94 | |||
95 | addr = *stack; | ||
96 | if (__kernel_text_address(addr)) { | ||
97 | if ((unsigned long) stack == bp + sizeof(long)) { | ||
98 | ops->address(data, addr, 1); | ||
99 | frame = frame->next_frame; | ||
100 | bp = (unsigned long) frame; | ||
101 | } else { | ||
102 | ops->address(data, addr, bp == 0); | ||
103 | } | ||
104 | print_ftrace_graph_addr(addr, data, ops, tinfo, graph); | ||
105 | } | ||
106 | stack++; | ||
107 | } | ||
108 | return bp; | ||
109 | } | ||
110 | |||
111 | |||
112 | static void | ||
113 | print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) | ||
114 | { | ||
115 | printk(data); | ||
116 | print_symbol(msg, symbol); | ||
117 | printk("\n"); | ||
118 | } | ||
119 | |||
120 | static void print_trace_warning(void *data, char *msg) | ||
121 | { | ||
122 | printk("%s%s\n", (char *)data, msg); | ||
123 | } | ||
124 | |||
125 | static int print_trace_stack(void *data, char *name) | ||
126 | { | ||
127 | printk("%s <%s> ", (char *)data, name); | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * Print one address/symbol entries per line. | ||
133 | */ | ||
134 | static void print_trace_address(void *data, unsigned long addr, int reliable) | ||
135 | { | ||
136 | touch_nmi_watchdog(); | ||
137 | printk(data); | ||
138 | printk_address(addr, reliable); | ||
139 | } | ||
140 | |||
141 | static const struct stacktrace_ops print_trace_ops = { | ||
142 | .warning = print_trace_warning, | ||
143 | .warning_symbol = print_trace_warning_symbol, | ||
144 | .stack = print_trace_stack, | ||
145 | .address = print_trace_address, | ||
146 | }; | ||
147 | |||
148 | void | ||
149 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | ||
150 | unsigned long *stack, unsigned long bp, char *log_lvl) | ||
151 | { | ||
152 | printk("%sCall Trace:\n", log_lvl); | ||
153 | dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); | ||
154 | } | ||
155 | |||
156 | void show_trace(struct task_struct *task, struct pt_regs *regs, | ||
157 | unsigned long *stack, unsigned long bp) | ||
158 | { | ||
159 | show_trace_log_lvl(task, regs, stack, bp, ""); | ||
160 | } | ||
161 | |||
162 | void show_stack(struct task_struct *task, unsigned long *sp) | ||
163 | { | ||
164 | show_stack_log_lvl(task, NULL, sp, 0, ""); | ||
165 | } | ||
166 | |||
167 | /* | ||
168 | * The architecture-independent dump_stack generator | ||
169 | */ | ||
170 | void dump_stack(void) | ||
171 | { | ||
172 | unsigned long bp = 0; | ||
173 | unsigned long stack; | ||
174 | |||
175 | #ifdef CONFIG_FRAME_POINTER | ||
176 | if (!bp) | ||
177 | get_bp(bp); | ||
178 | #endif | ||
179 | |||
180 | printk("Pid: %d, comm: %.20s %s %s %.*s\n", | ||
181 | current->pid, current->comm, print_tainted(), | ||
182 | init_utsname()->release, | ||
183 | (int)strcspn(init_utsname()->version, " "), | ||
184 | init_utsname()->version); | ||
185 | show_trace(NULL, NULL, &stack, bp); | ||
186 | } | ||
187 | EXPORT_SYMBOL(dump_stack); | ||
188 | |||
189 | static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED; | ||
190 | static int die_owner = -1; | ||
191 | static unsigned int die_nest_count; | ||
192 | |||
193 | unsigned __kprobes long oops_begin(void) | ||
194 | { | ||
195 | int cpu; | ||
196 | unsigned long flags; | ||
197 | |||
198 | oops_enter(); | ||
199 | |||
200 | /* racy, but better than risking deadlock. */ | ||
201 | raw_local_irq_save(flags); | ||
202 | cpu = smp_processor_id(); | ||
203 | if (!__raw_spin_trylock(&die_lock)) { | ||
204 | if (cpu == die_owner) | ||
205 | /* nested oops. should stop eventually */; | ||
206 | else | ||
207 | __raw_spin_lock(&die_lock); | ||
208 | } | ||
209 | die_nest_count++; | ||
210 | die_owner = cpu; | ||
211 | console_verbose(); | ||
212 | bust_spinlocks(1); | ||
213 | return flags; | ||
214 | } | ||
215 | |||
216 | void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) | ||
217 | { | ||
218 | if (regs && kexec_should_crash(current)) | ||
219 | crash_kexec(regs); | ||
220 | |||
221 | bust_spinlocks(0); | ||
222 | die_owner = -1; | ||
223 | add_taint(TAINT_DIE); | ||
224 | die_nest_count--; | ||
225 | if (!die_nest_count) | ||
226 | /* Nest count reaches zero, release the lock. */ | ||
227 | __raw_spin_unlock(&die_lock); | ||
228 | raw_local_irq_restore(flags); | ||
229 | oops_exit(); | ||
230 | |||
231 | if (!signr) | ||
232 | return; | ||
233 | if (in_interrupt()) | ||
234 | panic("Fatal exception in interrupt"); | ||
235 | if (panic_on_oops) | ||
236 | panic("Fatal exception"); | ||
237 | do_exit(signr); | ||
238 | } | ||
239 | |||
240 | int __kprobes __die(const char *str, struct pt_regs *regs, long err) | ||
241 | { | ||
242 | #ifdef CONFIG_X86_32 | ||
243 | unsigned short ss; | ||
244 | unsigned long sp; | ||
245 | #endif | ||
246 | printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter); | ||
247 | #ifdef CONFIG_PREEMPT | ||
248 | printk("PREEMPT "); | ||
249 | #endif | ||
250 | #ifdef CONFIG_SMP | ||
251 | printk("SMP "); | ||
252 | #endif | ||
253 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
254 | printk("DEBUG_PAGEALLOC"); | ||
255 | #endif | ||
256 | printk("\n"); | ||
257 | sysfs_printk_last_file(); | ||
258 | if (notify_die(DIE_OOPS, str, regs, err, | ||
259 | current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) | ||
260 | return 1; | ||
261 | |||
262 | show_registers(regs); | ||
263 | #ifdef CONFIG_X86_32 | ||
264 | sp = (unsigned long) (®s->sp); | ||
265 | savesegment(ss, ss); | ||
266 | if (user_mode(regs)) { | ||
267 | sp = regs->sp; | ||
268 | ss = regs->ss & 0xffff; | ||
269 | } | ||
270 | printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip); | ||
271 | print_symbol("%s", regs->ip); | ||
272 | printk(" SS:ESP %04x:%08lx\n", ss, sp); | ||
273 | #else | ||
274 | /* Executive summary in case the oops scrolled away */ | ||
275 | printk(KERN_ALERT "RIP "); | ||
276 | printk_address(regs->ip, 1); | ||
277 | printk(" RSP <%016lx>\n", regs->sp); | ||
278 | #endif | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | * This is gone through when something in the kernel has done something bad | ||
284 | * and is about to be terminated: | ||
285 | */ | ||
286 | void die(const char *str, struct pt_regs *regs, long err) | ||
287 | { | ||
288 | unsigned long flags = oops_begin(); | ||
289 | int sig = SIGSEGV; | ||
290 | |||
291 | if (!user_mode_vm(regs)) | ||
292 | report_bug(regs->ip, regs); | ||
293 | |||
294 | if (__die(str, regs, err)) | ||
295 | sig = 0; | ||
296 | oops_end(flags, regs, sig); | ||
297 | } | ||
298 | |||
299 | void notrace __kprobes | ||
300 | die_nmi(char *str, struct pt_regs *regs, int do_panic) | ||
301 | { | ||
302 | unsigned long flags; | ||
303 | |||
304 | if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP) | ||
305 | return; | ||
306 | |||
307 | /* | ||
308 | * We are in trouble anyway, lets at least try | ||
309 | * to get a message out. | ||
310 | */ | ||
311 | flags = oops_begin(); | ||
312 | printk(KERN_EMERG "%s", str); | ||
313 | printk(" on CPU%d, ip %08lx, registers:\n", | ||
314 | smp_processor_id(), regs->ip); | ||
315 | show_registers(regs); | ||
316 | oops_end(flags, regs, 0); | ||
317 | if (do_panic || panic_on_oops) | ||
318 | panic("Non maskable interrupt"); | ||
319 | nmi_exit(); | ||
320 | local_irq_enable(); | ||
321 | do_exit(SIGBUS); | ||
322 | } | ||
323 | |||
324 | static int __init oops_setup(char *s) | ||
325 | { | ||
326 | if (!s) | ||
327 | return -EINVAL; | ||
328 | if (!strcmp(s, "panic")) | ||
329 | panic_on_oops = 1; | ||
330 | return 0; | ||
331 | } | ||
332 | early_param("oops", oops_setup); | ||
333 | |||
334 | static int __init kstack_setup(char *s) | ||
335 | { | ||
336 | if (!s) | ||
337 | return -EINVAL; | ||
338 | kstack_depth_to_print = simple_strtoul(s, NULL, 0); | ||
339 | return 0; | ||
340 | } | ||
341 | early_param("kstack", kstack_setup); | ||
342 | |||
343 | static int __init code_bytes_setup(char *s) | ||
344 | { | ||
345 | code_bytes = simple_strtoul(s, NULL, 0); | ||
346 | if (code_bytes > 8192) | ||
347 | code_bytes = 8192; | ||
348 | |||
349 | return 1; | ||
350 | } | ||
351 | __setup("code_bytes=", code_bytes_setup); | ||
diff --git a/arch/x86/kernel/dumpstack.h b/arch/x86/kernel/dumpstack.h new file mode 100644 index 000000000000..da87590b8698 --- /dev/null +++ b/arch/x86/kernel/dumpstack.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
3 | * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs | ||
4 | */ | ||
5 | |||
6 | #ifndef DUMPSTACK_H | ||
7 | #define DUMPSTACK_H | ||
8 | |||
9 | #ifdef CONFIG_X86_32 | ||
10 | #define STACKSLOTS_PER_LINE 8 | ||
11 | #define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :) | ||
12 | #else | ||
13 | #define STACKSLOTS_PER_LINE 4 | ||
14 | #define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :) | ||
15 | #endif | ||
16 | |||
17 | extern unsigned long | ||
18 | print_context_stack(struct thread_info *tinfo, | ||
19 | unsigned long *stack, unsigned long bp, | ||
20 | const struct stacktrace_ops *ops, void *data, | ||
21 | unsigned long *end, int *graph); | ||
22 | |||
23 | extern void | ||
24 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | ||
25 | unsigned long *stack, unsigned long bp, char *log_lvl); | ||
26 | |||
27 | extern void | ||
28 | show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | ||
29 | unsigned long *sp, unsigned long bp, char *log_lvl); | ||
30 | |||
31 | extern unsigned int code_bytes; | ||
32 | extern int kstack_depth_to_print; | ||
33 | |||
34 | /* The form of the top of the frame on the stack */ | ||
35 | struct stack_frame { | ||
36 | struct stack_frame *next_frame; | ||
37 | unsigned long return_address; | ||
38 | }; | ||
39 | #endif | ||
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c index b3614752197b..d593cd1f58dc 100644 --- a/arch/x86/kernel/dumpstack_32.c +++ b/arch/x86/kernel/dumpstack_32.c | |||
@@ -17,69 +17,14 @@ | |||
17 | 17 | ||
18 | #include <asm/stacktrace.h> | 18 | #include <asm/stacktrace.h> |
19 | 19 | ||
20 | #define STACKSLOTS_PER_LINE 8 | 20 | #include "dumpstack.h" |
21 | #define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :) | ||
22 | |||
23 | int panic_on_unrecovered_nmi; | ||
24 | int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE; | ||
25 | static unsigned int code_bytes = 64; | ||
26 | static int die_counter; | ||
27 | |||
28 | void printk_address(unsigned long address, int reliable) | ||
29 | { | ||
30 | printk(" [<%p>] %s%pS\n", (void *) address, | ||
31 | reliable ? "" : "? ", (void *) address); | ||
32 | } | ||
33 | |||
34 | static inline int valid_stack_ptr(struct thread_info *tinfo, | ||
35 | void *p, unsigned int size, void *end) | ||
36 | { | ||
37 | void *t = tinfo; | ||
38 | if (end) { | ||
39 | if (p < end && p >= (end-THREAD_SIZE)) | ||
40 | return 1; | ||
41 | else | ||
42 | return 0; | ||
43 | } | ||
44 | return p > t && p < t + THREAD_SIZE - size; | ||
45 | } | ||
46 | |||
47 | /* The form of the top of the frame on the stack */ | ||
48 | struct stack_frame { | ||
49 | struct stack_frame *next_frame; | ||
50 | unsigned long return_address; | ||
51 | }; | ||
52 | |||
53 | static inline unsigned long | ||
54 | print_context_stack(struct thread_info *tinfo, | ||
55 | unsigned long *stack, unsigned long bp, | ||
56 | const struct stacktrace_ops *ops, void *data, | ||
57 | unsigned long *end) | ||
58 | { | ||
59 | struct stack_frame *frame = (struct stack_frame *)bp; | ||
60 | |||
61 | while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) { | ||
62 | unsigned long addr; | ||
63 | |||
64 | addr = *stack; | ||
65 | if (__kernel_text_address(addr)) { | ||
66 | if ((unsigned long) stack == bp + sizeof(long)) { | ||
67 | ops->address(data, addr, 1); | ||
68 | frame = frame->next_frame; | ||
69 | bp = (unsigned long) frame; | ||
70 | } else { | ||
71 | ops->address(data, addr, bp == 0); | ||
72 | } | ||
73 | } | ||
74 | stack++; | ||
75 | } | ||
76 | return bp; | ||
77 | } | ||
78 | 21 | ||
79 | void dump_trace(struct task_struct *task, struct pt_regs *regs, | 22 | void dump_trace(struct task_struct *task, struct pt_regs *regs, |
80 | unsigned long *stack, unsigned long bp, | 23 | unsigned long *stack, unsigned long bp, |
81 | const struct stacktrace_ops *ops, void *data) | 24 | const struct stacktrace_ops *ops, void *data) |
82 | { | 25 | { |
26 | int graph = 0; | ||
27 | |||
83 | if (!task) | 28 | if (!task) |
84 | task = current; | 29 | task = current; |
85 | 30 | ||
@@ -107,7 +52,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
107 | 52 | ||
108 | context = (struct thread_info *) | 53 | context = (struct thread_info *) |
109 | ((unsigned long)stack & (~(THREAD_SIZE - 1))); | 54 | ((unsigned long)stack & (~(THREAD_SIZE - 1))); |
110 | bp = print_context_stack(context, stack, bp, ops, data, NULL); | 55 | bp = print_context_stack(context, stack, bp, ops, |
56 | data, NULL, &graph); | ||
111 | 57 | ||
112 | stack = (unsigned long *)context->previous_esp; | 58 | stack = (unsigned long *)context->previous_esp; |
113 | if (!stack) | 59 | if (!stack) |
@@ -119,57 +65,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
119 | } | 65 | } |
120 | EXPORT_SYMBOL(dump_trace); | 66 | EXPORT_SYMBOL(dump_trace); |
121 | 67 | ||
122 | static void | 68 | void |
123 | print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) | ||
124 | { | ||
125 | printk(data); | ||
126 | print_symbol(msg, symbol); | ||
127 | printk("\n"); | ||
128 | } | ||
129 | |||
130 | static void print_trace_warning(void *data, char *msg) | ||
131 | { | ||
132 | printk("%s%s\n", (char *)data, msg); | ||
133 | } | ||
134 | |||
135 | static int print_trace_stack(void *data, char *name) | ||
136 | { | ||
137 | printk("%s <%s> ", (char *)data, name); | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | /* | ||
142 | * Print one address/symbol entries per line. | ||
143 | */ | ||
144 | static void print_trace_address(void *data, unsigned long addr, int reliable) | ||
145 | { | ||
146 | touch_nmi_watchdog(); | ||
147 | printk(data); | ||
148 | printk_address(addr, reliable); | ||
149 | } | ||
150 | |||
151 | static const struct stacktrace_ops print_trace_ops = { | ||
152 | .warning = print_trace_warning, | ||
153 | .warning_symbol = print_trace_warning_symbol, | ||
154 | .stack = print_trace_stack, | ||
155 | .address = print_trace_address, | ||
156 | }; | ||
157 | |||
158 | static void | ||
159 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | ||
160 | unsigned long *stack, unsigned long bp, char *log_lvl) | ||
161 | { | ||
162 | printk("%sCall Trace:\n", log_lvl); | ||
163 | dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); | ||
164 | } | ||
165 | |||
166 | void show_trace(struct task_struct *task, struct pt_regs *regs, | ||
167 | unsigned long *stack, unsigned long bp) | ||
168 | { | ||
169 | show_trace_log_lvl(task, regs, stack, bp, ""); | ||
170 | } | ||
171 | |||
172 | static void | ||
173 | show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | 69 | show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, |
174 | unsigned long *sp, unsigned long bp, char *log_lvl) | 70 | unsigned long *sp, unsigned long bp, char *log_lvl) |
175 | { | 71 | { |
@@ -196,33 +92,6 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
196 | show_trace_log_lvl(task, regs, sp, bp, log_lvl); | 92 | show_trace_log_lvl(task, regs, sp, bp, log_lvl); |
197 | } | 93 | } |
198 | 94 | ||
199 | void show_stack(struct task_struct *task, unsigned long *sp) | ||
200 | { | ||
201 | show_stack_log_lvl(task, NULL, sp, 0, ""); | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | * The architecture-independent dump_stack generator | ||
206 | */ | ||
207 | void dump_stack(void) | ||
208 | { | ||
209 | unsigned long bp = 0; | ||
210 | unsigned long stack; | ||
211 | |||
212 | #ifdef CONFIG_FRAME_POINTER | ||
213 | if (!bp) | ||
214 | get_bp(bp); | ||
215 | #endif | ||
216 | |||
217 | printk("Pid: %d, comm: %.20s %s %s %.*s\n", | ||
218 | current->pid, current->comm, print_tainted(), | ||
219 | init_utsname()->release, | ||
220 | (int)strcspn(init_utsname()->version, " "), | ||
221 | init_utsname()->version); | ||
222 | show_trace(NULL, NULL, &stack, bp); | ||
223 | } | ||
224 | |||
225 | EXPORT_SYMBOL(dump_stack); | ||
226 | 95 | ||
227 | void show_registers(struct pt_regs *regs) | 96 | void show_registers(struct pt_regs *regs) |
228 | { | 97 | { |
@@ -283,167 +152,3 @@ int is_valid_bugaddr(unsigned long ip) | |||
283 | return ud2 == 0x0b0f; | 152 | return ud2 == 0x0b0f; |
284 | } | 153 | } |
285 | 154 | ||
286 | static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED; | ||
287 | static int die_owner = -1; | ||
288 | static unsigned int die_nest_count; | ||
289 | |||
290 | unsigned __kprobes long oops_begin(void) | ||
291 | { | ||
292 | unsigned long flags; | ||
293 | |||
294 | oops_enter(); | ||
295 | |||
296 | if (die_owner != raw_smp_processor_id()) { | ||
297 | console_verbose(); | ||
298 | raw_local_irq_save(flags); | ||
299 | __raw_spin_lock(&die_lock); | ||
300 | die_owner = smp_processor_id(); | ||
301 | die_nest_count = 0; | ||
302 | bust_spinlocks(1); | ||
303 | } else { | ||
304 | raw_local_irq_save(flags); | ||
305 | } | ||
306 | die_nest_count++; | ||
307 | return flags; | ||
308 | } | ||
309 | |||
310 | void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) | ||
311 | { | ||
312 | bust_spinlocks(0); | ||
313 | die_owner = -1; | ||
314 | add_taint(TAINT_DIE); | ||
315 | __raw_spin_unlock(&die_lock); | ||
316 | raw_local_irq_restore(flags); | ||
317 | |||
318 | if (!regs) | ||
319 | return; | ||
320 | |||
321 | if (kexec_should_crash(current)) | ||
322 | crash_kexec(regs); | ||
323 | if (in_interrupt()) | ||
324 | panic("Fatal exception in interrupt"); | ||
325 | if (panic_on_oops) | ||
326 | panic("Fatal exception"); | ||
327 | oops_exit(); | ||
328 | do_exit(signr); | ||
329 | } | ||
330 | |||
331 | int __kprobes __die(const char *str, struct pt_regs *regs, long err) | ||
332 | { | ||
333 | unsigned short ss; | ||
334 | unsigned long sp; | ||
335 | |||
336 | printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter); | ||
337 | #ifdef CONFIG_PREEMPT | ||
338 | printk("PREEMPT "); | ||
339 | #endif | ||
340 | #ifdef CONFIG_SMP | ||
341 | printk("SMP "); | ||
342 | #endif | ||
343 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
344 | printk("DEBUG_PAGEALLOC"); | ||
345 | #endif | ||
346 | printk("\n"); | ||
347 | sysfs_printk_last_file(); | ||
348 | if (notify_die(DIE_OOPS, str, regs, err, | ||
349 | current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) | ||
350 | return 1; | ||
351 | |||
352 | show_registers(regs); | ||
353 | /* Executive summary in case the oops scrolled away */ | ||
354 | sp = (unsigned long) (®s->sp); | ||
355 | savesegment(ss, ss); | ||
356 | if (user_mode(regs)) { | ||
357 | sp = regs->sp; | ||
358 | ss = regs->ss & 0xffff; | ||
359 | } | ||
360 | printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip); | ||
361 | print_symbol("%s", regs->ip); | ||
362 | printk(" SS:ESP %04x:%08lx\n", ss, sp); | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | /* | ||
367 | * This is gone through when something in the kernel has done something bad | ||
368 | * and is about to be terminated: | ||
369 | */ | ||
370 | void die(const char *str, struct pt_regs *regs, long err) | ||
371 | { | ||
372 | unsigned long flags = oops_begin(); | ||
373 | |||
374 | if (die_nest_count < 3) { | ||
375 | report_bug(regs->ip, regs); | ||
376 | |||
377 | if (__die(str, regs, err)) | ||
378 | regs = NULL; | ||
379 | } else { | ||
380 | printk(KERN_EMERG "Recursive die() failure, output suppressed\n"); | ||
381 | } | ||
382 | |||
383 | oops_end(flags, regs, SIGSEGV); | ||
384 | } | ||
385 | |||
386 | static DEFINE_SPINLOCK(nmi_print_lock); | ||
387 | |||
388 | void notrace __kprobes | ||
389 | die_nmi(char *str, struct pt_regs *regs, int do_panic) | ||
390 | { | ||
391 | if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP) | ||
392 | return; | ||
393 | |||
394 | spin_lock(&nmi_print_lock); | ||
395 | /* | ||
396 | * We are in trouble anyway, lets at least try | ||
397 | * to get a message out: | ||
398 | */ | ||
399 | bust_spinlocks(1); | ||
400 | printk(KERN_EMERG "%s", str); | ||
401 | printk(" on CPU%d, ip %08lx, registers:\n", | ||
402 | smp_processor_id(), regs->ip); | ||
403 | show_registers(regs); | ||
404 | if (do_panic) | ||
405 | panic("Non maskable interrupt"); | ||
406 | console_silent(); | ||
407 | spin_unlock(&nmi_print_lock); | ||
408 | |||
409 | /* | ||
410 | * If we are in kernel we are probably nested up pretty bad | ||
411 | * and might aswell get out now while we still can: | ||
412 | */ | ||
413 | if (!user_mode_vm(regs)) { | ||
414 | current->thread.trap_no = 2; | ||
415 | crash_kexec(regs); | ||
416 | } | ||
417 | |||
418 | bust_spinlocks(0); | ||
419 | do_exit(SIGSEGV); | ||
420 | } | ||
421 | |||
422 | static int __init oops_setup(char *s) | ||
423 | { | ||
424 | if (!s) | ||
425 | return -EINVAL; | ||
426 | if (!strcmp(s, "panic")) | ||
427 | panic_on_oops = 1; | ||
428 | return 0; | ||
429 | } | ||
430 | early_param("oops", oops_setup); | ||
431 | |||
432 | static int __init kstack_setup(char *s) | ||
433 | { | ||
434 | if (!s) | ||
435 | return -EINVAL; | ||
436 | kstack_depth_to_print = simple_strtoul(s, NULL, 0); | ||
437 | return 0; | ||
438 | } | ||
439 | early_param("kstack", kstack_setup); | ||
440 | |||
441 | static int __init code_bytes_setup(char *s) | ||
442 | { | ||
443 | code_bytes = simple_strtoul(s, NULL, 0); | ||
444 | if (code_bytes > 8192) | ||
445 | code_bytes = 8192; | ||
446 | |||
447 | return 1; | ||
448 | } | ||
449 | __setup("code_bytes=", code_bytes_setup); | ||
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index 96a5db7da8a7..c302d0707048 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c | |||
@@ -17,19 +17,7 @@ | |||
17 | 17 | ||
18 | #include <asm/stacktrace.h> | 18 | #include <asm/stacktrace.h> |
19 | 19 | ||
20 | #define STACKSLOTS_PER_LINE 4 | 20 | #include "dumpstack.h" |
21 | #define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :) | ||
22 | |||
23 | int panic_on_unrecovered_nmi; | ||
24 | int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE; | ||
25 | static unsigned int code_bytes = 64; | ||
26 | static int die_counter; | ||
27 | |||
28 | void printk_address(unsigned long address, int reliable) | ||
29 | { | ||
30 | printk(" [<%p>] %s%pS\n", (void *) address, | ||
31 | reliable ? "" : "? ", (void *) address); | ||
32 | } | ||
33 | 21 | ||
34 | static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | 22 | static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, |
35 | unsigned *usedp, char **idp) | 23 | unsigned *usedp, char **idp) |
@@ -113,51 +101,6 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | |||
113 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack | 101 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack |
114 | */ | 102 | */ |
115 | 103 | ||
116 | static inline int valid_stack_ptr(struct thread_info *tinfo, | ||
117 | void *p, unsigned int size, void *end) | ||
118 | { | ||
119 | void *t = tinfo; | ||
120 | if (end) { | ||
121 | if (p < end && p >= (end-THREAD_SIZE)) | ||
122 | return 1; | ||
123 | else | ||
124 | return 0; | ||
125 | } | ||
126 | return p > t && p < t + THREAD_SIZE - size; | ||
127 | } | ||
128 | |||
129 | /* The form of the top of the frame on the stack */ | ||
130 | struct stack_frame { | ||
131 | struct stack_frame *next_frame; | ||
132 | unsigned long return_address; | ||
133 | }; | ||
134 | |||
135 | static inline unsigned long | ||
136 | print_context_stack(struct thread_info *tinfo, | ||
137 | unsigned long *stack, unsigned long bp, | ||
138 | const struct stacktrace_ops *ops, void *data, | ||
139 | unsigned long *end) | ||
140 | { | ||
141 | struct stack_frame *frame = (struct stack_frame *)bp; | ||
142 | |||
143 | while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) { | ||
144 | unsigned long addr; | ||
145 | |||
146 | addr = *stack; | ||
147 | if (__kernel_text_address(addr)) { | ||
148 | if ((unsigned long) stack == bp + sizeof(long)) { | ||
149 | ops->address(data, addr, 1); | ||
150 | frame = frame->next_frame; | ||
151 | bp = (unsigned long) frame; | ||
152 | } else { | ||
153 | ops->address(data, addr, bp == 0); | ||
154 | } | ||
155 | } | ||
156 | stack++; | ||
157 | } | ||
158 | return bp; | ||
159 | } | ||
160 | |||
161 | void dump_trace(struct task_struct *task, struct pt_regs *regs, | 104 | void dump_trace(struct task_struct *task, struct pt_regs *regs, |
162 | unsigned long *stack, unsigned long bp, | 105 | unsigned long *stack, unsigned long bp, |
163 | const struct stacktrace_ops *ops, void *data) | 106 | const struct stacktrace_ops *ops, void *data) |
@@ -166,6 +109,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
166 | unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; | 109 | unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; |
167 | unsigned used = 0; | 110 | unsigned used = 0; |
168 | struct thread_info *tinfo; | 111 | struct thread_info *tinfo; |
112 | int graph = 0; | ||
169 | 113 | ||
170 | if (!task) | 114 | if (!task) |
171 | task = current; | 115 | task = current; |
@@ -206,7 +150,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
206 | break; | 150 | break; |
207 | 151 | ||
208 | bp = print_context_stack(tinfo, stack, bp, ops, | 152 | bp = print_context_stack(tinfo, stack, bp, ops, |
209 | data, estack_end); | 153 | data, estack_end, &graph); |
210 | ops->stack(data, "<EOE>"); | 154 | ops->stack(data, "<EOE>"); |
211 | /* | 155 | /* |
212 | * We link to the next stack via the | 156 | * We link to the next stack via the |
@@ -225,7 +169,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
225 | if (ops->stack(data, "IRQ") < 0) | 169 | if (ops->stack(data, "IRQ") < 0) |
226 | break; | 170 | break; |
227 | bp = print_context_stack(tinfo, stack, bp, | 171 | bp = print_context_stack(tinfo, stack, bp, |
228 | ops, data, irqstack_end); | 172 | ops, data, irqstack_end, &graph); |
229 | /* | 173 | /* |
230 | * We link to the next stack (which would be | 174 | * We link to the next stack (which would be |
231 | * the process stack normally) the last | 175 | * the process stack normally) the last |
@@ -243,62 +187,12 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
243 | /* | 187 | /* |
244 | * This handles the process stack: | 188 | * This handles the process stack: |
245 | */ | 189 | */ |
246 | bp = print_context_stack(tinfo, stack, bp, ops, data, NULL); | 190 | bp = print_context_stack(tinfo, stack, bp, ops, data, NULL, &graph); |
247 | put_cpu(); | 191 | put_cpu(); |
248 | } | 192 | } |
249 | EXPORT_SYMBOL(dump_trace); | 193 | EXPORT_SYMBOL(dump_trace); |
250 | 194 | ||
251 | static void | 195 | void |
252 | print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) | ||
253 | { | ||
254 | printk(data); | ||
255 | print_symbol(msg, symbol); | ||
256 | printk("\n"); | ||
257 | } | ||
258 | |||
259 | static void print_trace_warning(void *data, char *msg) | ||
260 | { | ||
261 | printk("%s%s\n", (char *)data, msg); | ||
262 | } | ||
263 | |||
264 | static int print_trace_stack(void *data, char *name) | ||
265 | { | ||
266 | printk("%s <%s> ", (char *)data, name); | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * Print one address/symbol entries per line. | ||
272 | */ | ||
273 | static void print_trace_address(void *data, unsigned long addr, int reliable) | ||
274 | { | ||
275 | touch_nmi_watchdog(); | ||
276 | printk(data); | ||
277 | printk_address(addr, reliable); | ||
278 | } | ||
279 | |||
280 | static const struct stacktrace_ops print_trace_ops = { | ||
281 | .warning = print_trace_warning, | ||
282 | .warning_symbol = print_trace_warning_symbol, | ||
283 | .stack = print_trace_stack, | ||
284 | .address = print_trace_address, | ||
285 | }; | ||
286 | |||
287 | static void | ||
288 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | ||
289 | unsigned long *stack, unsigned long bp, char *log_lvl) | ||
290 | { | ||
291 | printk("%sCall Trace:\n", log_lvl); | ||
292 | dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); | ||
293 | } | ||
294 | |||
295 | void show_trace(struct task_struct *task, struct pt_regs *regs, | ||
296 | unsigned long *stack, unsigned long bp) | ||
297 | { | ||
298 | show_trace_log_lvl(task, regs, stack, bp, ""); | ||
299 | } | ||
300 | |||
301 | static void | ||
302 | show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | 196 | show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, |
303 | unsigned long *sp, unsigned long bp, char *log_lvl) | 197 | unsigned long *sp, unsigned long bp, char *log_lvl) |
304 | { | 198 | { |
@@ -342,33 +236,6 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
342 | show_trace_log_lvl(task, regs, sp, bp, log_lvl); | 236 | show_trace_log_lvl(task, regs, sp, bp, log_lvl); |
343 | } | 237 | } |
344 | 238 | ||
345 | void show_stack(struct task_struct *task, unsigned long *sp) | ||
346 | { | ||
347 | show_stack_log_lvl(task, NULL, sp, 0, ""); | ||
348 | } | ||
349 | |||
350 | /* | ||
351 | * The architecture-independent dump_stack generator | ||
352 | */ | ||
353 | void dump_stack(void) | ||
354 | { | ||
355 | unsigned long bp = 0; | ||
356 | unsigned long stack; | ||
357 | |||
358 | #ifdef CONFIG_FRAME_POINTER | ||
359 | if (!bp) | ||
360 | get_bp(bp); | ||
361 | #endif | ||
362 | |||
363 | printk("Pid: %d, comm: %.20s %s %s %.*s\n", | ||
364 | current->pid, current->comm, print_tainted(), | ||
365 | init_utsname()->release, | ||
366 | (int)strcspn(init_utsname()->version, " "), | ||
367 | init_utsname()->version); | ||
368 | show_trace(NULL, NULL, &stack, bp); | ||
369 | } | ||
370 | EXPORT_SYMBOL(dump_stack); | ||
371 | |||
372 | void show_registers(struct pt_regs *regs) | 239 | void show_registers(struct pt_regs *regs) |
373 | { | 240 | { |
374 | int i; | 241 | int i; |
@@ -429,147 +296,3 @@ int is_valid_bugaddr(unsigned long ip) | |||
429 | return ud2 == 0x0b0f; | 296 | return ud2 == 0x0b0f; |
430 | } | 297 | } |
431 | 298 | ||
432 | static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED; | ||
433 | static int die_owner = -1; | ||
434 | static unsigned int die_nest_count; | ||
435 | |||
436 | unsigned __kprobes long oops_begin(void) | ||
437 | { | ||
438 | int cpu; | ||
439 | unsigned long flags; | ||
440 | |||
441 | oops_enter(); | ||
442 | |||
443 | /* racy, but better than risking deadlock. */ | ||
444 | raw_local_irq_save(flags); | ||
445 | cpu = smp_processor_id(); | ||
446 | if (!__raw_spin_trylock(&die_lock)) { | ||
447 | if (cpu == die_owner) | ||
448 | /* nested oops. should stop eventually */; | ||
449 | else | ||
450 | __raw_spin_lock(&die_lock); | ||
451 | } | ||
452 | die_nest_count++; | ||
453 | die_owner = cpu; | ||
454 | console_verbose(); | ||
455 | bust_spinlocks(1); | ||
456 | return flags; | ||
457 | } | ||
458 | |||
459 | void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) | ||
460 | { | ||
461 | die_owner = -1; | ||
462 | bust_spinlocks(0); | ||
463 | die_nest_count--; | ||
464 | if (!die_nest_count) | ||
465 | /* Nest count reaches zero, release the lock. */ | ||
466 | __raw_spin_unlock(&die_lock); | ||
467 | raw_local_irq_restore(flags); | ||
468 | if (!regs) { | ||
469 | oops_exit(); | ||
470 | return; | ||
471 | } | ||
472 | if (in_interrupt()) | ||
473 | panic("Fatal exception in interrupt"); | ||
474 | if (panic_on_oops) | ||
475 | panic("Fatal exception"); | ||
476 | oops_exit(); | ||
477 | do_exit(signr); | ||
478 | } | ||
479 | |||
480 | int __kprobes __die(const char *str, struct pt_regs *regs, long err) | ||
481 | { | ||
482 | printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter); | ||
483 | #ifdef CONFIG_PREEMPT | ||
484 | printk("PREEMPT "); | ||
485 | #endif | ||
486 | #ifdef CONFIG_SMP | ||
487 | printk("SMP "); | ||
488 | #endif | ||
489 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
490 | printk("DEBUG_PAGEALLOC"); | ||
491 | #endif | ||
492 | printk("\n"); | ||
493 | sysfs_printk_last_file(); | ||
494 | if (notify_die(DIE_OOPS, str, regs, err, | ||
495 | current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) | ||
496 | return 1; | ||
497 | |||
498 | show_registers(regs); | ||
499 | add_taint(TAINT_DIE); | ||
500 | /* Executive summary in case the oops scrolled away */ | ||
501 | printk(KERN_ALERT "RIP "); | ||
502 | printk_address(regs->ip, 1); | ||
503 | printk(" RSP <%016lx>\n", regs->sp); | ||
504 | if (kexec_should_crash(current)) | ||
505 | crash_kexec(regs); | ||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | void die(const char *str, struct pt_regs *regs, long err) | ||
510 | { | ||
511 | unsigned long flags = oops_begin(); | ||
512 | |||
513 | if (!user_mode(regs)) | ||
514 | report_bug(regs->ip, regs); | ||
515 | |||
516 | if (__die(str, regs, err)) | ||
517 | regs = NULL; | ||
518 | oops_end(flags, regs, SIGSEGV); | ||
519 | } | ||
520 | |||
521 | notrace __kprobes void | ||
522 | die_nmi(char *str, struct pt_regs *regs, int do_panic) | ||
523 | { | ||
524 | unsigned long flags; | ||
525 | |||
526 | if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP) | ||
527 | return; | ||
528 | |||
529 | flags = oops_begin(); | ||
530 | /* | ||
531 | * We are in trouble anyway, lets at least try | ||
532 | * to get a message out. | ||
533 | */ | ||
534 | printk(KERN_EMERG "%s", str); | ||
535 | printk(" on CPU%d, ip %08lx, registers:\n", | ||
536 | smp_processor_id(), regs->ip); | ||
537 | show_registers(regs); | ||
538 | if (kexec_should_crash(current)) | ||
539 | crash_kexec(regs); | ||
540 | if (do_panic || panic_on_oops) | ||
541 | panic("Non maskable interrupt"); | ||
542 | oops_end(flags, NULL, SIGBUS); | ||
543 | nmi_exit(); | ||
544 | local_irq_enable(); | ||
545 | do_exit(SIGBUS); | ||
546 | } | ||
547 | |||
548 | static int __init oops_setup(char *s) | ||
549 | { | ||
550 | if (!s) | ||
551 | return -EINVAL; | ||
552 | if (!strcmp(s, "panic")) | ||
553 | panic_on_oops = 1; | ||
554 | return 0; | ||
555 | } | ||
556 | early_param("oops", oops_setup); | ||
557 | |||
558 | static int __init kstack_setup(char *s) | ||
559 | { | ||
560 | if (!s) | ||
561 | return -EINVAL; | ||
562 | kstack_depth_to_print = simple_strtoul(s, NULL, 0); | ||
563 | return 0; | ||
564 | } | ||
565 | early_param("kstack", kstack_setup); | ||
566 | |||
567 | static int __init code_bytes_setup(char *s) | ||
568 | { | ||
569 | code_bytes = simple_strtoul(s, NULL, 0); | ||
570 | if (code_bytes > 8192) | ||
571 | code_bytes = 8192; | ||
572 | |||
573 | return 1; | ||
574 | } | ||
575 | __setup("code_bytes=", code_bytes_setup); | ||
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 28b597ef9ca1..43ceb3f454bf 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S | |||
@@ -1157,6 +1157,9 @@ ENTRY(mcount) | |||
1157 | END(mcount) | 1157 | END(mcount) |
1158 | 1158 | ||
1159 | ENTRY(ftrace_caller) | 1159 | ENTRY(ftrace_caller) |
1160 | cmpl $0, function_trace_stop | ||
1161 | jne ftrace_stub | ||
1162 | |||
1160 | pushl %eax | 1163 | pushl %eax |
1161 | pushl %ecx | 1164 | pushl %ecx |
1162 | pushl %edx | 1165 | pushl %edx |
@@ -1171,6 +1174,11 @@ ftrace_call: | |||
1171 | popl %edx | 1174 | popl %edx |
1172 | popl %ecx | 1175 | popl %ecx |
1173 | popl %eax | 1176 | popl %eax |
1177 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
1178 | .globl ftrace_graph_call | ||
1179 | ftrace_graph_call: | ||
1180 | jmp ftrace_stub | ||
1181 | #endif | ||
1174 | 1182 | ||
1175 | .globl ftrace_stub | 1183 | .globl ftrace_stub |
1176 | ftrace_stub: | 1184 | ftrace_stub: |
@@ -1180,8 +1188,18 @@ END(ftrace_caller) | |||
1180 | #else /* ! CONFIG_DYNAMIC_FTRACE */ | 1188 | #else /* ! CONFIG_DYNAMIC_FTRACE */ |
1181 | 1189 | ||
1182 | ENTRY(mcount) | 1190 | ENTRY(mcount) |
1191 | cmpl $0, function_trace_stop | ||
1192 | jne ftrace_stub | ||
1193 | |||
1183 | cmpl $ftrace_stub, ftrace_trace_function | 1194 | cmpl $ftrace_stub, ftrace_trace_function |
1184 | jnz trace | 1195 | jnz trace |
1196 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
1197 | cmpl $ftrace_stub, ftrace_graph_return | ||
1198 | jnz ftrace_graph_caller | ||
1199 | |||
1200 | cmpl $ftrace_graph_entry_stub, ftrace_graph_entry | ||
1201 | jnz ftrace_graph_caller | ||
1202 | #endif | ||
1185 | .globl ftrace_stub | 1203 | .globl ftrace_stub |
1186 | ftrace_stub: | 1204 | ftrace_stub: |
1187 | ret | 1205 | ret |
@@ -1200,12 +1218,43 @@ trace: | |||
1200 | popl %edx | 1218 | popl %edx |
1201 | popl %ecx | 1219 | popl %ecx |
1202 | popl %eax | 1220 | popl %eax |
1203 | |||
1204 | jmp ftrace_stub | 1221 | jmp ftrace_stub |
1205 | END(mcount) | 1222 | END(mcount) |
1206 | #endif /* CONFIG_DYNAMIC_FTRACE */ | 1223 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
1207 | #endif /* CONFIG_FUNCTION_TRACER */ | 1224 | #endif /* CONFIG_FUNCTION_TRACER */ |
1208 | 1225 | ||
1226 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
1227 | ENTRY(ftrace_graph_caller) | ||
1228 | cmpl $0, function_trace_stop | ||
1229 | jne ftrace_stub | ||
1230 | |||
1231 | pushl %eax | ||
1232 | pushl %ecx | ||
1233 | pushl %edx | ||
1234 | movl 0xc(%esp), %edx | ||
1235 | lea 0x4(%ebp), %eax | ||
1236 | subl $MCOUNT_INSN_SIZE, %edx | ||
1237 | call prepare_ftrace_return | ||
1238 | popl %edx | ||
1239 | popl %ecx | ||
1240 | popl %eax | ||
1241 | ret | ||
1242 | END(ftrace_graph_caller) | ||
1243 | |||
1244 | .globl return_to_handler | ||
1245 | return_to_handler: | ||
1246 | pushl $0 | ||
1247 | pushl %eax | ||
1248 | pushl %ecx | ||
1249 | pushl %edx | ||
1250 | call ftrace_return_to_handler | ||
1251 | movl %eax, 0xc(%esp) | ||
1252 | popl %edx | ||
1253 | popl %ecx | ||
1254 | popl %eax | ||
1255 | ret | ||
1256 | #endif | ||
1257 | |||
1209 | .section .rodata,"a" | 1258 | .section .rodata,"a" |
1210 | #include "syscall_table_32.S" | 1259 | #include "syscall_table_32.S" |
1211 | 1260 | ||
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index b86f332c96a6..54e0bbdccb99 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
@@ -68,6 +68,8 @@ ENTRY(mcount) | |||
68 | END(mcount) | 68 | END(mcount) |
69 | 69 | ||
70 | ENTRY(ftrace_caller) | 70 | ENTRY(ftrace_caller) |
71 | cmpl $0, function_trace_stop | ||
72 | jne ftrace_stub | ||
71 | 73 | ||
72 | /* taken from glibc */ | 74 | /* taken from glibc */ |
73 | subq $0x38, %rsp | 75 | subq $0x38, %rsp |
@@ -96,6 +98,12 @@ ftrace_call: | |||
96 | movq (%rsp), %rax | 98 | movq (%rsp), %rax |
97 | addq $0x38, %rsp | 99 | addq $0x38, %rsp |
98 | 100 | ||
101 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
102 | .globl ftrace_graph_call | ||
103 | ftrace_graph_call: | ||
104 | jmp ftrace_stub | ||
105 | #endif | ||
106 | |||
99 | .globl ftrace_stub | 107 | .globl ftrace_stub |
100 | ftrace_stub: | 108 | ftrace_stub: |
101 | retq | 109 | retq |
@@ -103,8 +111,20 @@ END(ftrace_caller) | |||
103 | 111 | ||
104 | #else /* ! CONFIG_DYNAMIC_FTRACE */ | 112 | #else /* ! CONFIG_DYNAMIC_FTRACE */ |
105 | ENTRY(mcount) | 113 | ENTRY(mcount) |
114 | cmpl $0, function_trace_stop | ||
115 | jne ftrace_stub | ||
116 | |||
106 | cmpq $ftrace_stub, ftrace_trace_function | 117 | cmpq $ftrace_stub, ftrace_trace_function |
107 | jnz trace | 118 | jnz trace |
119 | |||
120 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
121 | cmpq $ftrace_stub, ftrace_graph_return | ||
122 | jnz ftrace_graph_caller | ||
123 | |||
124 | cmpq $ftrace_graph_entry_stub, ftrace_graph_entry | ||
125 | jnz ftrace_graph_caller | ||
126 | #endif | ||
127 | |||
108 | .globl ftrace_stub | 128 | .globl ftrace_stub |
109 | ftrace_stub: | 129 | ftrace_stub: |
110 | retq | 130 | retq |
@@ -140,6 +160,69 @@ END(mcount) | |||
140 | #endif /* CONFIG_DYNAMIC_FTRACE */ | 160 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
141 | #endif /* CONFIG_FUNCTION_TRACER */ | 161 | #endif /* CONFIG_FUNCTION_TRACER */ |
142 | 162 | ||
163 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
164 | ENTRY(ftrace_graph_caller) | ||
165 | cmpl $0, function_trace_stop | ||
166 | jne ftrace_stub | ||
167 | |||
168 | subq $0x38, %rsp | ||
169 | movq %rax, (%rsp) | ||
170 | movq %rcx, 8(%rsp) | ||
171 | movq %rdx, 16(%rsp) | ||
172 | movq %rsi, 24(%rsp) | ||
173 | movq %rdi, 32(%rsp) | ||
174 | movq %r8, 40(%rsp) | ||
175 | movq %r9, 48(%rsp) | ||
176 | |||
177 | leaq 8(%rbp), %rdi | ||
178 | movq 0x38(%rsp), %rsi | ||
179 | subq $MCOUNT_INSN_SIZE, %rsi | ||
180 | |||
181 | call prepare_ftrace_return | ||
182 | |||
183 | movq 48(%rsp), %r9 | ||
184 | movq 40(%rsp), %r8 | ||
185 | movq 32(%rsp), %rdi | ||
186 | movq 24(%rsp), %rsi | ||
187 | movq 16(%rsp), %rdx | ||
188 | movq 8(%rsp), %rcx | ||
189 | movq (%rsp), %rax | ||
190 | addq $0x38, %rsp | ||
191 | retq | ||
192 | END(ftrace_graph_caller) | ||
193 | |||
194 | |||
195 | .globl return_to_handler | ||
196 | return_to_handler: | ||
197 | subq $80, %rsp | ||
198 | |||
199 | movq %rax, (%rsp) | ||
200 | movq %rcx, 8(%rsp) | ||
201 | movq %rdx, 16(%rsp) | ||
202 | movq %rsi, 24(%rsp) | ||
203 | movq %rdi, 32(%rsp) | ||
204 | movq %r8, 40(%rsp) | ||
205 | movq %r9, 48(%rsp) | ||
206 | movq %r10, 56(%rsp) | ||
207 | movq %r11, 64(%rsp) | ||
208 | |||
209 | call ftrace_return_to_handler | ||
210 | |||
211 | movq %rax, 72(%rsp) | ||
212 | movq 64(%rsp), %r11 | ||
213 | movq 56(%rsp), %r10 | ||
214 | movq 48(%rsp), %r9 | ||
215 | movq 40(%rsp), %r8 | ||
216 | movq 32(%rsp), %rdi | ||
217 | movq 24(%rsp), %rsi | ||
218 | movq 16(%rsp), %rdx | ||
219 | movq 8(%rsp), %rcx | ||
220 | movq (%rsp), %rax | ||
221 | addq $72, %rsp | ||
222 | retq | ||
223 | #endif | ||
224 | |||
225 | |||
143 | #ifndef CONFIG_PREEMPT | 226 | #ifndef CONFIG_PREEMPT |
144 | #define retint_kernel retint_restore_args | 227 | #define retint_kernel retint_restore_args |
145 | #endif | 228 | #endif |
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 50ea0ac8c9bf..1b43086b097a 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c | |||
@@ -14,14 +14,17 @@ | |||
14 | #include <linux/uaccess.h> | 14 | #include <linux/uaccess.h> |
15 | #include <linux/ftrace.h> | 15 | #include <linux/ftrace.h> |
16 | #include <linux/percpu.h> | 16 | #include <linux/percpu.h> |
17 | #include <linux/sched.h> | ||
17 | #include <linux/init.h> | 18 | #include <linux/init.h> |
18 | #include <linux/list.h> | 19 | #include <linux/list.h> |
19 | 20 | ||
20 | #include <asm/ftrace.h> | 21 | #include <asm/ftrace.h> |
22 | #include <linux/ftrace.h> | ||
21 | #include <asm/nops.h> | 23 | #include <asm/nops.h> |
24 | #include <asm/nmi.h> | ||
22 | 25 | ||
23 | 26 | ||
24 | static unsigned char ftrace_nop[MCOUNT_INSN_SIZE]; | 27 | #ifdef CONFIG_DYNAMIC_FTRACE |
25 | 28 | ||
26 | union ftrace_code_union { | 29 | union ftrace_code_union { |
27 | char code[MCOUNT_INSN_SIZE]; | 30 | char code[MCOUNT_INSN_SIZE]; |
@@ -31,18 +34,12 @@ union ftrace_code_union { | |||
31 | } __attribute__((packed)); | 34 | } __attribute__((packed)); |
32 | }; | 35 | }; |
33 | 36 | ||
34 | |||
35 | static int ftrace_calc_offset(long ip, long addr) | 37 | static int ftrace_calc_offset(long ip, long addr) |
36 | { | 38 | { |
37 | return (int)(addr - ip); | 39 | return (int)(addr - ip); |
38 | } | 40 | } |
39 | 41 | ||
40 | unsigned char *ftrace_nop_replace(void) | 42 | static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) |
41 | { | ||
42 | return ftrace_nop; | ||
43 | } | ||
44 | |||
45 | unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) | ||
46 | { | 43 | { |
47 | static union ftrace_code_union calc; | 44 | static union ftrace_code_union calc; |
48 | 45 | ||
@@ -56,7 +53,142 @@ unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) | |||
56 | return calc.code; | 53 | return calc.code; |
57 | } | 54 | } |
58 | 55 | ||
59 | int | 56 | /* |
57 | * Modifying code must take extra care. On an SMP machine, if | ||
58 | * the code being modified is also being executed on another CPU | ||
59 | * that CPU will have undefined results and possibly take a GPF. | ||
60 | * We use kstop_machine to stop other CPUS from exectuing code. | ||
61 | * But this does not stop NMIs from happening. We still need | ||
62 | * to protect against that. We separate out the modification of | ||
63 | * the code to take care of this. | ||
64 | * | ||
65 | * Two buffers are added: An IP buffer and a "code" buffer. | ||
66 | * | ||
67 | * 1) Put the instruction pointer into the IP buffer | ||
68 | * and the new code into the "code" buffer. | ||
69 | * 2) Set a flag that says we are modifying code | ||
70 | * 3) Wait for any running NMIs to finish. | ||
71 | * 4) Write the code | ||
72 | * 5) clear the flag. | ||
73 | * 6) Wait for any running NMIs to finish. | ||
74 | * | ||
75 | * If an NMI is executed, the first thing it does is to call | ||
76 | * "ftrace_nmi_enter". This will check if the flag is set to write | ||
77 | * and if it is, it will write what is in the IP and "code" buffers. | ||
78 | * | ||
79 | * The trick is, it does not matter if everyone is writing the same | ||
80 | * content to the code location. Also, if a CPU is executing code | ||
81 | * it is OK to write to that code location if the contents being written | ||
82 | * are the same as what exists. | ||
83 | */ | ||
84 | |||
85 | static atomic_t in_nmi = ATOMIC_INIT(0); | ||
86 | static int mod_code_status; /* holds return value of text write */ | ||
87 | static int mod_code_write; /* set when NMI should do the write */ | ||
88 | static void *mod_code_ip; /* holds the IP to write to */ | ||
89 | static void *mod_code_newcode; /* holds the text to write to the IP */ | ||
90 | |||
91 | static unsigned nmi_wait_count; | ||
92 | static atomic_t nmi_update_count = ATOMIC_INIT(0); | ||
93 | |||
94 | int ftrace_arch_read_dyn_info(char *buf, int size) | ||
95 | { | ||
96 | int r; | ||
97 | |||
98 | r = snprintf(buf, size, "%u %u", | ||
99 | nmi_wait_count, | ||
100 | atomic_read(&nmi_update_count)); | ||
101 | return r; | ||
102 | } | ||
103 | |||
104 | static void ftrace_mod_code(void) | ||
105 | { | ||
106 | /* | ||
107 | * Yes, more than one CPU process can be writing to mod_code_status. | ||
108 | * (and the code itself) | ||
109 | * But if one were to fail, then they all should, and if one were | ||
110 | * to succeed, then they all should. | ||
111 | */ | ||
112 | mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode, | ||
113 | MCOUNT_INSN_SIZE); | ||
114 | } | ||
115 | |||
116 | void ftrace_nmi_enter(void) | ||
117 | { | ||
118 | atomic_inc(&in_nmi); | ||
119 | /* Must have in_nmi seen before reading write flag */ | ||
120 | smp_mb(); | ||
121 | if (mod_code_write) { | ||
122 | ftrace_mod_code(); | ||
123 | atomic_inc(&nmi_update_count); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | void ftrace_nmi_exit(void) | ||
128 | { | ||
129 | /* Finish all executions before clearing in_nmi */ | ||
130 | smp_wmb(); | ||
131 | atomic_dec(&in_nmi); | ||
132 | } | ||
133 | |||
134 | static void wait_for_nmi(void) | ||
135 | { | ||
136 | int waited = 0; | ||
137 | |||
138 | while (atomic_read(&in_nmi)) { | ||
139 | waited = 1; | ||
140 | cpu_relax(); | ||
141 | } | ||
142 | |||
143 | if (waited) | ||
144 | nmi_wait_count++; | ||
145 | } | ||
146 | |||
147 | static int | ||
148 | do_ftrace_mod_code(unsigned long ip, void *new_code) | ||
149 | { | ||
150 | mod_code_ip = (void *)ip; | ||
151 | mod_code_newcode = new_code; | ||
152 | |||
153 | /* The buffers need to be visible before we let NMIs write them */ | ||
154 | smp_wmb(); | ||
155 | |||
156 | mod_code_write = 1; | ||
157 | |||
158 | /* Make sure write bit is visible before we wait on NMIs */ | ||
159 | smp_mb(); | ||
160 | |||
161 | wait_for_nmi(); | ||
162 | |||
163 | /* Make sure all running NMIs have finished before we write the code */ | ||
164 | smp_mb(); | ||
165 | |||
166 | ftrace_mod_code(); | ||
167 | |||
168 | /* Make sure the write happens before clearing the bit */ | ||
169 | smp_wmb(); | ||
170 | |||
171 | mod_code_write = 0; | ||
172 | |||
173 | /* make sure NMIs see the cleared bit */ | ||
174 | smp_mb(); | ||
175 | |||
176 | wait_for_nmi(); | ||
177 | |||
178 | return mod_code_status; | ||
179 | } | ||
180 | |||
181 | |||
182 | |||
183 | |||
184 | static unsigned char ftrace_nop[MCOUNT_INSN_SIZE]; | ||
185 | |||
186 | static unsigned char *ftrace_nop_replace(void) | ||
187 | { | ||
188 | return ftrace_nop; | ||
189 | } | ||
190 | |||
191 | static int | ||
60 | ftrace_modify_code(unsigned long ip, unsigned char *old_code, | 192 | ftrace_modify_code(unsigned long ip, unsigned char *old_code, |
61 | unsigned char *new_code) | 193 | unsigned char *new_code) |
62 | { | 194 | { |
@@ -81,7 +213,7 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code, | |||
81 | return -EINVAL; | 213 | return -EINVAL; |
82 | 214 | ||
83 | /* replace the text with the new text */ | 215 | /* replace the text with the new text */ |
84 | if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE)) | 216 | if (do_ftrace_mod_code(ip, new_code)) |
85 | return -EPERM; | 217 | return -EPERM; |
86 | 218 | ||
87 | sync_core(); | 219 | sync_core(); |
@@ -89,6 +221,29 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code, | |||
89 | return 0; | 221 | return 0; |
90 | } | 222 | } |
91 | 223 | ||
224 | int ftrace_make_nop(struct module *mod, | ||
225 | struct dyn_ftrace *rec, unsigned long addr) | ||
226 | { | ||
227 | unsigned char *new, *old; | ||
228 | unsigned long ip = rec->ip; | ||
229 | |||
230 | old = ftrace_call_replace(ip, addr); | ||
231 | new = ftrace_nop_replace(); | ||
232 | |||
233 | return ftrace_modify_code(rec->ip, old, new); | ||
234 | } | ||
235 | |||
236 | int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | ||
237 | { | ||
238 | unsigned char *new, *old; | ||
239 | unsigned long ip = rec->ip; | ||
240 | |||
241 | old = ftrace_nop_replace(); | ||
242 | new = ftrace_call_replace(ip, addr); | ||
243 | |||
244 | return ftrace_modify_code(rec->ip, old, new); | ||
245 | } | ||
246 | |||
92 | int ftrace_update_ftrace_func(ftrace_func_t func) | 247 | int ftrace_update_ftrace_func(ftrace_func_t func) |
93 | { | 248 | { |
94 | unsigned long ip = (unsigned long)(&ftrace_call); | 249 | unsigned long ip = (unsigned long)(&ftrace_call); |
@@ -165,3 +320,218 @@ int __init ftrace_dyn_arch_init(void *data) | |||
165 | 320 | ||
166 | return 0; | 321 | return 0; |
167 | } | 322 | } |
323 | #endif | ||
324 | |||
325 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
326 | |||
327 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
328 | extern void ftrace_graph_call(void); | ||
329 | |||
330 | static int ftrace_mod_jmp(unsigned long ip, | ||
331 | int old_offset, int new_offset) | ||
332 | { | ||
333 | unsigned char code[MCOUNT_INSN_SIZE]; | ||
334 | |||
335 | if (probe_kernel_read(code, (void *)ip, MCOUNT_INSN_SIZE)) | ||
336 | return -EFAULT; | ||
337 | |||
338 | if (code[0] != 0xe9 || old_offset != *(int *)(&code[1])) | ||
339 | return -EINVAL; | ||
340 | |||
341 | *(int *)(&code[1]) = new_offset; | ||
342 | |||
343 | if (do_ftrace_mod_code(ip, &code)) | ||
344 | return -EPERM; | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | int ftrace_enable_ftrace_graph_caller(void) | ||
350 | { | ||
351 | unsigned long ip = (unsigned long)(&ftrace_graph_call); | ||
352 | int old_offset, new_offset; | ||
353 | |||
354 | old_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE); | ||
355 | new_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE); | ||
356 | |||
357 | return ftrace_mod_jmp(ip, old_offset, new_offset); | ||
358 | } | ||
359 | |||
360 | int ftrace_disable_ftrace_graph_caller(void) | ||
361 | { | ||
362 | unsigned long ip = (unsigned long)(&ftrace_graph_call); | ||
363 | int old_offset, new_offset; | ||
364 | |||
365 | old_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE); | ||
366 | new_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE); | ||
367 | |||
368 | return ftrace_mod_jmp(ip, old_offset, new_offset); | ||
369 | } | ||
370 | |||
371 | #else /* CONFIG_DYNAMIC_FTRACE */ | ||
372 | |||
373 | /* | ||
374 | * These functions are picked from those used on | ||
375 | * this page for dynamic ftrace. They have been | ||
376 | * simplified to ignore all traces in NMI context. | ||
377 | */ | ||
378 | static atomic_t in_nmi; | ||
379 | |||
380 | void ftrace_nmi_enter(void) | ||
381 | { | ||
382 | atomic_inc(&in_nmi); | ||
383 | } | ||
384 | |||
385 | void ftrace_nmi_exit(void) | ||
386 | { | ||
387 | atomic_dec(&in_nmi); | ||
388 | } | ||
389 | |||
390 | #endif /* !CONFIG_DYNAMIC_FTRACE */ | ||
391 | |||
392 | /* Add a function return address to the trace stack on thread info.*/ | ||
393 | static int push_return_trace(unsigned long ret, unsigned long long time, | ||
394 | unsigned long func, int *depth) | ||
395 | { | ||
396 | int index; | ||
397 | |||
398 | if (!current->ret_stack) | ||
399 | return -EBUSY; | ||
400 | |||
401 | /* The return trace stack is full */ | ||
402 | if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) { | ||
403 | atomic_inc(¤t->trace_overrun); | ||
404 | return -EBUSY; | ||
405 | } | ||
406 | |||
407 | index = ++current->curr_ret_stack; | ||
408 | barrier(); | ||
409 | current->ret_stack[index].ret = ret; | ||
410 | current->ret_stack[index].func = func; | ||
411 | current->ret_stack[index].calltime = time; | ||
412 | *depth = index; | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | /* Retrieve a function return address to the trace stack on thread info.*/ | ||
418 | static void pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret) | ||
419 | { | ||
420 | int index; | ||
421 | |||
422 | index = current->curr_ret_stack; | ||
423 | |||
424 | if (unlikely(index < 0)) { | ||
425 | ftrace_graph_stop(); | ||
426 | WARN_ON(1); | ||
427 | /* Might as well panic, otherwise we have no where to go */ | ||
428 | *ret = (unsigned long)panic; | ||
429 | return; | ||
430 | } | ||
431 | |||
432 | *ret = current->ret_stack[index].ret; | ||
433 | trace->func = current->ret_stack[index].func; | ||
434 | trace->calltime = current->ret_stack[index].calltime; | ||
435 | trace->overrun = atomic_read(¤t->trace_overrun); | ||
436 | trace->depth = index; | ||
437 | barrier(); | ||
438 | current->curr_ret_stack--; | ||
439 | |||
440 | } | ||
441 | |||
442 | /* | ||
443 | * Send the trace to the ring-buffer. | ||
444 | * @return the original return address. | ||
445 | */ | ||
446 | unsigned long ftrace_return_to_handler(void) | ||
447 | { | ||
448 | struct ftrace_graph_ret trace; | ||
449 | unsigned long ret; | ||
450 | |||
451 | pop_return_trace(&trace, &ret); | ||
452 | trace.rettime = cpu_clock(raw_smp_processor_id()); | ||
453 | ftrace_graph_return(&trace); | ||
454 | |||
455 | if (unlikely(!ret)) { | ||
456 | ftrace_graph_stop(); | ||
457 | WARN_ON(1); | ||
458 | /* Might as well panic. What else to do? */ | ||
459 | ret = (unsigned long)panic; | ||
460 | } | ||
461 | |||
462 | return ret; | ||
463 | } | ||
464 | |||
465 | /* | ||
466 | * Hook the return address and push it in the stack of return addrs | ||
467 | * in current thread info. | ||
468 | */ | ||
469 | void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) | ||
470 | { | ||
471 | unsigned long old; | ||
472 | unsigned long long calltime; | ||
473 | int faulted; | ||
474 | struct ftrace_graph_ent trace; | ||
475 | unsigned long return_hooker = (unsigned long) | ||
476 | &return_to_handler; | ||
477 | |||
478 | /* Nmi's are currently unsupported */ | ||
479 | if (unlikely(atomic_read(&in_nmi))) | ||
480 | return; | ||
481 | |||
482 | if (unlikely(atomic_read(¤t->tracing_graph_pause))) | ||
483 | return; | ||
484 | |||
485 | /* | ||
486 | * Protect against fault, even if it shouldn't | ||
487 | * happen. This tool is too much intrusive to | ||
488 | * ignore such a protection. | ||
489 | */ | ||
490 | asm volatile( | ||
491 | "1: " _ASM_MOV " (%[parent_old]), %[old]\n" | ||
492 | "2: " _ASM_MOV " %[return_hooker], (%[parent_replaced])\n" | ||
493 | " movl $0, %[faulted]\n" | ||
494 | |||
495 | ".section .fixup, \"ax\"\n" | ||
496 | "3: movl $1, %[faulted]\n" | ||
497 | ".previous\n" | ||
498 | |||
499 | _ASM_EXTABLE(1b, 3b) | ||
500 | _ASM_EXTABLE(2b, 3b) | ||
501 | |||
502 | : [parent_replaced] "=r" (parent), [old] "=r" (old), | ||
503 | [faulted] "=r" (faulted) | ||
504 | : [parent_old] "0" (parent), [return_hooker] "r" (return_hooker) | ||
505 | : "memory" | ||
506 | ); | ||
507 | |||
508 | if (unlikely(faulted)) { | ||
509 | ftrace_graph_stop(); | ||
510 | WARN_ON(1); | ||
511 | return; | ||
512 | } | ||
513 | |||
514 | if (unlikely(!__kernel_text_address(old))) { | ||
515 | ftrace_graph_stop(); | ||
516 | *parent = old; | ||
517 | WARN_ON(1); | ||
518 | return; | ||
519 | } | ||
520 | |||
521 | calltime = cpu_clock(raw_smp_processor_id()); | ||
522 | |||
523 | if (push_return_trace(old, calltime, | ||
524 | self_addr, &trace.depth) == -EBUSY) { | ||
525 | *parent = old; | ||
526 | return; | ||
527 | } | ||
528 | |||
529 | trace.func = self_addr; | ||
530 | |||
531 | /* Only trace if the calling function expects to */ | ||
532 | if (!ftrace_graph_entry(&trace)) { | ||
533 | current->curr_ret_stack--; | ||
534 | *parent = old; | ||
535 | } | ||
536 | } | ||
537 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index c622772744d8..c27af49a4ede 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/module.h> | 7 | #include <linux/module.h> |
8 | #include <linux/pm.h> | 8 | #include <linux/pm.h> |
9 | #include <linux/clockchips.h> | 9 | #include <linux/clockchips.h> |
10 | #include <linux/ftrace.h> | ||
10 | #include <asm/system.h> | 11 | #include <asm/system.h> |
11 | 12 | ||
12 | unsigned long idle_halt; | 13 | unsigned long idle_halt; |
@@ -100,6 +101,9 @@ static inline int hlt_use_halt(void) | |||
100 | void default_idle(void) | 101 | void default_idle(void) |
101 | { | 102 | { |
102 | if (hlt_use_halt()) { | 103 | if (hlt_use_halt()) { |
104 | struct power_trace it; | ||
105 | |||
106 | trace_power_start(&it, POWER_CSTATE, 1); | ||
103 | current_thread_info()->status &= ~TS_POLLING; | 107 | current_thread_info()->status &= ~TS_POLLING; |
104 | /* | 108 | /* |
105 | * TS_POLLING-cleared state must be visible before we | 109 | * TS_POLLING-cleared state must be visible before we |
@@ -112,6 +116,7 @@ void default_idle(void) | |||
112 | else | 116 | else |
113 | local_irq_enable(); | 117 | local_irq_enable(); |
114 | current_thread_info()->status |= TS_POLLING; | 118 | current_thread_info()->status |= TS_POLLING; |
119 | trace_power_end(&it); | ||
115 | } else { | 120 | } else { |
116 | local_irq_enable(); | 121 | local_irq_enable(); |
117 | /* loop is done by the caller */ | 122 | /* loop is done by the caller */ |
@@ -154,24 +159,31 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait); | |||
154 | */ | 159 | */ |
155 | void mwait_idle_with_hints(unsigned long ax, unsigned long cx) | 160 | void mwait_idle_with_hints(unsigned long ax, unsigned long cx) |
156 | { | 161 | { |
162 | struct power_trace it; | ||
163 | |||
164 | trace_power_start(&it, POWER_CSTATE, (ax>>4)+1); | ||
157 | if (!need_resched()) { | 165 | if (!need_resched()) { |
158 | __monitor((void *)¤t_thread_info()->flags, 0, 0); | 166 | __monitor((void *)¤t_thread_info()->flags, 0, 0); |
159 | smp_mb(); | 167 | smp_mb(); |
160 | if (!need_resched()) | 168 | if (!need_resched()) |
161 | __mwait(ax, cx); | 169 | __mwait(ax, cx); |
162 | } | 170 | } |
171 | trace_power_end(&it); | ||
163 | } | 172 | } |
164 | 173 | ||
165 | /* Default MONITOR/MWAIT with no hints, used for default C1 state */ | 174 | /* Default MONITOR/MWAIT with no hints, used for default C1 state */ |
166 | static void mwait_idle(void) | 175 | static void mwait_idle(void) |
167 | { | 176 | { |
177 | struct power_trace it; | ||
168 | if (!need_resched()) { | 178 | if (!need_resched()) { |
179 | trace_power_start(&it, POWER_CSTATE, 1); | ||
169 | __monitor((void *)¤t_thread_info()->flags, 0, 0); | 180 | __monitor((void *)¤t_thread_info()->flags, 0, 0); |
170 | smp_mb(); | 181 | smp_mb(); |
171 | if (!need_resched()) | 182 | if (!need_resched()) |
172 | __sti_mwait(0, 0); | 183 | __sti_mwait(0, 0); |
173 | else | 184 | else |
174 | local_irq_enable(); | 185 | local_irq_enable(); |
186 | trace_power_end(&it); | ||
175 | } else | 187 | } else |
176 | local_irq_enable(); | 188 | local_irq_enable(); |
177 | } | 189 | } |
@@ -183,9 +195,13 @@ static void mwait_idle(void) | |||
183 | */ | 195 | */ |
184 | static void poll_idle(void) | 196 | static void poll_idle(void) |
185 | { | 197 | { |
198 | struct power_trace it; | ||
199 | |||
200 | trace_power_start(&it, POWER_CSTATE, 0); | ||
186 | local_irq_enable(); | 201 | local_irq_enable(); |
187 | while (!need_resched()) | 202 | while (!need_resched()) |
188 | cpu_relax(); | 203 | cpu_relax(); |
204 | trace_power_end(&it); | ||
189 | } | 205 | } |
190 | 206 | ||
191 | /* | 207 | /* |
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 0a1302fe6d45..24c2276aa453 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/percpu.h> | 38 | #include <linux/percpu.h> |
39 | #include <linux/prctl.h> | 39 | #include <linux/prctl.h> |
40 | #include <linux/dmi.h> | 40 | #include <linux/dmi.h> |
41 | #include <linux/ftrace.h> | ||
41 | 42 | ||
42 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
43 | #include <asm/pgtable.h> | 44 | #include <asm/pgtable.h> |
@@ -548,7 +549,8 @@ __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, | |||
548 | * the task-switch, and shows up in ret_from_fork in entry.S, | 549 | * the task-switch, and shows up in ret_from_fork in entry.S, |
549 | * for example. | 550 | * for example. |
550 | */ | 551 | */ |
551 | struct task_struct * __switch_to(struct task_struct *prev_p, struct task_struct *next_p) | 552 | __notrace_funcgraph struct task_struct * |
553 | __switch_to(struct task_struct *prev_p, struct task_struct *next_p) | ||
552 | { | 554 | { |
553 | struct thread_struct *prev = &prev_p->thread, | 555 | struct thread_struct *prev = &prev_p->thread, |
554 | *next = &next_p->thread; | 556 | *next = &next_p->thread; |
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index c958120fb1b6..fbb321d53d34 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/prctl.h> | 39 | #include <linux/prctl.h> |
40 | #include <linux/uaccess.h> | 40 | #include <linux/uaccess.h> |
41 | #include <linux/io.h> | 41 | #include <linux/io.h> |
42 | #include <linux/ftrace.h> | ||
42 | 43 | ||
43 | #include <asm/pgtable.h> | 44 | #include <asm/pgtable.h> |
44 | #include <asm/system.h> | 45 | #include <asm/system.h> |
@@ -551,8 +552,9 @@ static inline void __switch_to_xtra(struct task_struct *prev_p, | |||
551 | * - could test fs/gs bitsliced | 552 | * - could test fs/gs bitsliced |
552 | * | 553 | * |
553 | * Kprobes not supported here. Set the probe on schedule instead. | 554 | * Kprobes not supported here. Set the probe on schedule instead. |
555 | * Function graph tracer not supported too. | ||
554 | */ | 556 | */ |
555 | struct task_struct * | 557 | __notrace_funcgraph struct task_struct * |
556 | __switch_to(struct task_struct *prev_p, struct task_struct *next_p) | 558 | __switch_to(struct task_struct *prev_p, struct task_struct *next_p) |
557 | { | 559 | { |
558 | struct thread_struct *prev = &prev_p->thread; | 560 | struct thread_struct *prev = &prev_p->thread; |
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 0a6d8c12e10d..2c8ec1ba75e6 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -668,14 +668,14 @@ static int ptrace_bts_read_record(struct task_struct *child, size_t index, | |||
668 | size_t bts_index, bts_end; | 668 | size_t bts_index, bts_end; |
669 | int error; | 669 | int error; |
670 | 670 | ||
671 | error = ds_get_bts_end(child, &bts_end); | 671 | error = ds_get_bts_end(child->bts, &bts_end); |
672 | if (error < 0) | 672 | if (error < 0) |
673 | return error; | 673 | return error; |
674 | 674 | ||
675 | if (bts_end <= index) | 675 | if (bts_end <= index) |
676 | return -EINVAL; | 676 | return -EINVAL; |
677 | 677 | ||
678 | error = ds_get_bts_index(child, &bts_index); | 678 | error = ds_get_bts_index(child->bts, &bts_index); |
679 | if (error < 0) | 679 | if (error < 0) |
680 | return error; | 680 | return error; |
681 | 681 | ||
@@ -684,7 +684,7 @@ static int ptrace_bts_read_record(struct task_struct *child, size_t index, | |||
684 | if (bts_end <= bts_index) | 684 | if (bts_end <= bts_index) |
685 | bts_index -= bts_end; | 685 | bts_index -= bts_end; |
686 | 686 | ||
687 | error = ds_access_bts(child, bts_index, &bts_record); | 687 | error = ds_access_bts(child->bts, bts_index, &bts_record); |
688 | if (error < 0) | 688 | if (error < 0) |
689 | return error; | 689 | return error; |
690 | 690 | ||
@@ -705,14 +705,14 @@ static int ptrace_bts_drain(struct task_struct *child, | |||
705 | size_t end, i; | 705 | size_t end, i; |
706 | int error; | 706 | int error; |
707 | 707 | ||
708 | error = ds_get_bts_index(child, &end); | 708 | error = ds_get_bts_index(child->bts, &end); |
709 | if (error < 0) | 709 | if (error < 0) |
710 | return error; | 710 | return error; |
711 | 711 | ||
712 | if (size < (end * sizeof(struct bts_struct))) | 712 | if (size < (end * sizeof(struct bts_struct))) |
713 | return -EIO; | 713 | return -EIO; |
714 | 714 | ||
715 | error = ds_access_bts(child, 0, (const void **)&raw); | 715 | error = ds_access_bts(child->bts, 0, (const void **)&raw); |
716 | if (error < 0) | 716 | if (error < 0) |
717 | return error; | 717 | return error; |
718 | 718 | ||
@@ -723,18 +723,13 @@ static int ptrace_bts_drain(struct task_struct *child, | |||
723 | return -EFAULT; | 723 | return -EFAULT; |
724 | } | 724 | } |
725 | 725 | ||
726 | error = ds_clear_bts(child); | 726 | error = ds_clear_bts(child->bts); |
727 | if (error < 0) | 727 | if (error < 0) |
728 | return error; | 728 | return error; |
729 | 729 | ||
730 | return end; | 730 | return end; |
731 | } | 731 | } |
732 | 732 | ||
733 | static void ptrace_bts_ovfl(struct task_struct *child) | ||
734 | { | ||
735 | send_sig(child->thread.bts_ovfl_signal, child, 0); | ||
736 | } | ||
737 | |||
738 | static int ptrace_bts_config(struct task_struct *child, | 733 | static int ptrace_bts_config(struct task_struct *child, |
739 | long cfg_size, | 734 | long cfg_size, |
740 | const struct ptrace_bts_config __user *ucfg) | 735 | const struct ptrace_bts_config __user *ucfg) |
@@ -760,23 +755,45 @@ static int ptrace_bts_config(struct task_struct *child, | |||
760 | goto errout; | 755 | goto errout; |
761 | 756 | ||
762 | if (cfg.flags & PTRACE_BTS_O_ALLOC) { | 757 | if (cfg.flags & PTRACE_BTS_O_ALLOC) { |
763 | ds_ovfl_callback_t ovfl = NULL; | 758 | bts_ovfl_callback_t ovfl = NULL; |
764 | unsigned int sig = 0; | 759 | unsigned int sig = 0; |
765 | 760 | ||
766 | /* we ignore the error in case we were not tracing child */ | 761 | error = -EINVAL; |
767 | (void)ds_release_bts(child); | 762 | if (cfg.size < (10 * bts_cfg.sizeof_bts)) |
763 | goto errout; | ||
768 | 764 | ||
769 | if (cfg.flags & PTRACE_BTS_O_SIGNAL) { | 765 | if (cfg.flags & PTRACE_BTS_O_SIGNAL) { |
770 | if (!cfg.signal) | 766 | if (!cfg.signal) |
771 | goto errout; | 767 | goto errout; |
772 | 768 | ||
769 | error = -EOPNOTSUPP; | ||
770 | goto errout; | ||
771 | |||
773 | sig = cfg.signal; | 772 | sig = cfg.signal; |
774 | ovfl = ptrace_bts_ovfl; | ||
775 | } | 773 | } |
776 | 774 | ||
777 | error = ds_request_bts(child, /* base = */ NULL, cfg.size, ovfl); | 775 | if (child->bts) { |
778 | if (error < 0) | 776 | (void)ds_release_bts(child->bts); |
777 | kfree(child->bts_buffer); | ||
778 | |||
779 | child->bts = NULL; | ||
780 | child->bts_buffer = NULL; | ||
781 | } | ||
782 | |||
783 | error = -ENOMEM; | ||
784 | child->bts_buffer = kzalloc(cfg.size, GFP_KERNEL); | ||
785 | if (!child->bts_buffer) | ||
786 | goto errout; | ||
787 | |||
788 | child->bts = ds_request_bts(child, child->bts_buffer, cfg.size, | ||
789 | ovfl, /* th = */ (size_t)-1); | ||
790 | if (IS_ERR(child->bts)) { | ||
791 | error = PTR_ERR(child->bts); | ||
792 | kfree(child->bts_buffer); | ||
793 | child->bts = NULL; | ||
794 | child->bts_buffer = NULL; | ||
779 | goto errout; | 795 | goto errout; |
796 | } | ||
780 | 797 | ||
781 | child->thread.bts_ovfl_signal = sig; | 798 | child->thread.bts_ovfl_signal = sig; |
782 | } | 799 | } |
@@ -823,15 +840,15 @@ static int ptrace_bts_status(struct task_struct *child, | |||
823 | if (cfg_size < sizeof(cfg)) | 840 | if (cfg_size < sizeof(cfg)) |
824 | return -EIO; | 841 | return -EIO; |
825 | 842 | ||
826 | error = ds_get_bts_end(child, &end); | 843 | error = ds_get_bts_end(child->bts, &end); |
827 | if (error < 0) | 844 | if (error < 0) |
828 | return error; | 845 | return error; |
829 | 846 | ||
830 | error = ds_access_bts(child, /* index = */ 0, &base); | 847 | error = ds_access_bts(child->bts, /* index = */ 0, &base); |
831 | if (error < 0) | 848 | if (error < 0) |
832 | return error; | 849 | return error; |
833 | 850 | ||
834 | error = ds_access_bts(child, /* index = */ end, &max); | 851 | error = ds_access_bts(child->bts, /* index = */ end, &max); |
835 | if (error < 0) | 852 | if (error < 0) |
836 | return error; | 853 | return error; |
837 | 854 | ||
@@ -884,10 +901,7 @@ static int ptrace_bts_write_record(struct task_struct *child, | |||
884 | return -EINVAL; | 901 | return -EINVAL; |
885 | } | 902 | } |
886 | 903 | ||
887 | /* The writing task will be the switched-to task on a context | 904 | return ds_write_bts(child->bts, bts_record, bts_cfg.sizeof_bts); |
888 | * switch. It needs to write into the switched-from task's BTS | ||
889 | * buffer. */ | ||
890 | return ds_unchecked_write_bts(child, bts_record, bts_cfg.sizeof_bts); | ||
891 | } | 905 | } |
892 | 906 | ||
893 | void ptrace_bts_take_timestamp(struct task_struct *tsk, | 907 | void ptrace_bts_take_timestamp(struct task_struct *tsk, |
@@ -929,17 +943,16 @@ void __cpuinit ptrace_bts_init_intel(struct cpuinfo_x86 *c) | |||
929 | switch (c->x86) { | 943 | switch (c->x86) { |
930 | case 0x6: | 944 | case 0x6: |
931 | switch (c->x86_model) { | 945 | switch (c->x86_model) { |
946 | case 0 ... 0xC: | ||
947 | /* sorry, don't know about them */ | ||
948 | break; | ||
932 | case 0xD: | 949 | case 0xD: |
933 | case 0xE: /* Pentium M */ | 950 | case 0xE: /* Pentium M */ |
934 | bts_configure(&bts_cfg_pentium_m); | 951 | bts_configure(&bts_cfg_pentium_m); |
935 | break; | 952 | break; |
936 | case 0xF: /* Core2 */ | 953 | default: /* Core2, Atom, ... */ |
937 | case 0x1C: /* Atom */ | ||
938 | bts_configure(&bts_cfg_core2); | 954 | bts_configure(&bts_cfg_core2); |
939 | break; | 955 | break; |
940 | default: | ||
941 | /* sorry, don't know about them */ | ||
942 | break; | ||
943 | } | 956 | } |
944 | break; | 957 | break; |
945 | case 0xF: | 958 | case 0xF: |
@@ -973,13 +986,17 @@ void ptrace_disable(struct task_struct *child) | |||
973 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); | 986 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); |
974 | #endif | 987 | #endif |
975 | #ifdef CONFIG_X86_PTRACE_BTS | 988 | #ifdef CONFIG_X86_PTRACE_BTS |
976 | (void)ds_release_bts(child); | 989 | if (child->bts) { |
990 | (void)ds_release_bts(child->bts); | ||
991 | kfree(child->bts_buffer); | ||
992 | child->bts_buffer = NULL; | ||
977 | 993 | ||
978 | child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask; | 994 | child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask; |
979 | if (!child->thread.debugctlmsr) | 995 | if (!child->thread.debugctlmsr) |
980 | clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR); | 996 | clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR); |
981 | 997 | ||
982 | clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS); | 998 | clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS); |
999 | } | ||
983 | #endif /* CONFIG_X86_PTRACE_BTS */ | 1000 | #endif /* CONFIG_X86_PTRACE_BTS */ |
984 | } | 1001 | } |
985 | 1002 | ||
@@ -1111,9 +1128,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
1111 | (child, data, (struct ptrace_bts_config __user *)addr); | 1128 | (child, data, (struct ptrace_bts_config __user *)addr); |
1112 | break; | 1129 | break; |
1113 | 1130 | ||
1114 | case PTRACE_BTS_SIZE: | 1131 | case PTRACE_BTS_SIZE: { |
1115 | ret = ds_get_bts_index(child, /* pos = */ NULL); | 1132 | size_t size; |
1133 | |||
1134 | ret = ds_get_bts_index(child->bts, &size); | ||
1135 | if (ret == 0) { | ||
1136 | BUG_ON(size != (int) size); | ||
1137 | ret = (int) size; | ||
1138 | } | ||
1116 | break; | 1139 | break; |
1140 | } | ||
1117 | 1141 | ||
1118 | case PTRACE_BTS_GET: | 1142 | case PTRACE_BTS_GET: |
1119 | ret = ptrace_bts_read_record | 1143 | ret = ptrace_bts_read_record |
@@ -1121,7 +1145,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
1121 | break; | 1145 | break; |
1122 | 1146 | ||
1123 | case PTRACE_BTS_CLEAR: | 1147 | case PTRACE_BTS_CLEAR: |
1124 | ret = ds_clear_bts(child); | 1148 | ret = ds_clear_bts(child->bts); |
1125 | break; | 1149 | break; |
1126 | 1150 | ||
1127 | case PTRACE_BTS_DRAIN: | 1151 | case PTRACE_BTS_DRAIN: |
diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c index a03e7f6d90c3..10786af95545 100644 --- a/arch/x86/kernel/stacktrace.c +++ b/arch/x86/kernel/stacktrace.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <linux/sched.h> | 6 | #include <linux/sched.h> |
7 | #include <linux/stacktrace.h> | 7 | #include <linux/stacktrace.h> |
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
9 | #include <linux/uaccess.h> | ||
9 | #include <asm/stacktrace.h> | 10 | #include <asm/stacktrace.h> |
10 | 11 | ||
11 | static void save_stack_warning(void *data, char *msg) | 12 | static void save_stack_warning(void *data, char *msg) |
@@ -83,3 +84,66 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | |||
83 | trace->entries[trace->nr_entries++] = ULONG_MAX; | 84 | trace->entries[trace->nr_entries++] = ULONG_MAX; |
84 | } | 85 | } |
85 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); | 86 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); |
87 | |||
88 | /* Userspace stacktrace - based on kernel/trace/trace_sysprof.c */ | ||
89 | |||
90 | struct stack_frame { | ||
91 | const void __user *next_fp; | ||
92 | unsigned long ret_addr; | ||
93 | }; | ||
94 | |||
95 | static int copy_stack_frame(const void __user *fp, struct stack_frame *frame) | ||
96 | { | ||
97 | int ret; | ||
98 | |||
99 | if (!access_ok(VERIFY_READ, fp, sizeof(*frame))) | ||
100 | return 0; | ||
101 | |||
102 | ret = 1; | ||
103 | pagefault_disable(); | ||
104 | if (__copy_from_user_inatomic(frame, fp, sizeof(*frame))) | ||
105 | ret = 0; | ||
106 | pagefault_enable(); | ||
107 | |||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | static inline void __save_stack_trace_user(struct stack_trace *trace) | ||
112 | { | ||
113 | const struct pt_regs *regs = task_pt_regs(current); | ||
114 | const void __user *fp = (const void __user *)regs->bp; | ||
115 | |||
116 | if (trace->nr_entries < trace->max_entries) | ||
117 | trace->entries[trace->nr_entries++] = regs->ip; | ||
118 | |||
119 | while (trace->nr_entries < trace->max_entries) { | ||
120 | struct stack_frame frame; | ||
121 | |||
122 | frame.next_fp = NULL; | ||
123 | frame.ret_addr = 0; | ||
124 | if (!copy_stack_frame(fp, &frame)) | ||
125 | break; | ||
126 | if ((unsigned long)fp < regs->sp) | ||
127 | break; | ||
128 | if (frame.ret_addr) { | ||
129 | trace->entries[trace->nr_entries++] = | ||
130 | frame.ret_addr; | ||
131 | } | ||
132 | if (fp == frame.next_fp) | ||
133 | break; | ||
134 | fp = frame.next_fp; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | void save_stack_trace_user(struct stack_trace *trace) | ||
139 | { | ||
140 | /* | ||
141 | * Trace user stack if we are not a kernel thread | ||
142 | */ | ||
143 | if (current->mm) { | ||
144 | __save_stack_trace_user(trace); | ||
145 | } | ||
146 | if (trace->nr_entries < trace->max_entries) | ||
147 | trace->entries[trace->nr_entries++] = ULONG_MAX; | ||
148 | } | ||
149 | |||
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c index 0b8b6690a86d..6f3d3d4cd973 100644 --- a/arch/x86/kernel/vsyscall_64.c +++ b/arch/x86/kernel/vsyscall_64.c | |||
@@ -17,6 +17,9 @@ | |||
17 | * want per guest time just set the kernel.vsyscall64 sysctl to 0. | 17 | * want per guest time just set the kernel.vsyscall64 sysctl to 0. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | /* Disable profiling for userspace code: */ | ||
21 | #define DISABLE_BRANCH_PROFILING | ||
22 | |||
20 | #include <linux/time.h> | 23 | #include <linux/time.h> |
21 | #include <linux/init.h> | 24 | #include <linux/init.h> |
22 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c index 9e68075544f6..4a20b2f9a381 100644 --- a/arch/x86/lib/usercopy_32.c +++ b/arch/x86/lib/usercopy_32.c | |||
@@ -39,7 +39,7 @@ static inline int __movsl_is_ok(unsigned long a1, unsigned long a2, unsigned lon | |||
39 | #define __do_strncpy_from_user(dst, src, count, res) \ | 39 | #define __do_strncpy_from_user(dst, src, count, res) \ |
40 | do { \ | 40 | do { \ |
41 | int __d0, __d1, __d2; \ | 41 | int __d0, __d1, __d2; \ |
42 | might_sleep(); \ | 42 | might_fault(); \ |
43 | __asm__ __volatile__( \ | 43 | __asm__ __volatile__( \ |
44 | " testl %1,%1\n" \ | 44 | " testl %1,%1\n" \ |
45 | " jz 2f\n" \ | 45 | " jz 2f\n" \ |
@@ -126,7 +126,7 @@ EXPORT_SYMBOL(strncpy_from_user); | |||
126 | #define __do_clear_user(addr,size) \ | 126 | #define __do_clear_user(addr,size) \ |
127 | do { \ | 127 | do { \ |
128 | int __d0; \ | 128 | int __d0; \ |
129 | might_sleep(); \ | 129 | might_fault(); \ |
130 | __asm__ __volatile__( \ | 130 | __asm__ __volatile__( \ |
131 | "0: rep; stosl\n" \ | 131 | "0: rep; stosl\n" \ |
132 | " movl %2,%0\n" \ | 132 | " movl %2,%0\n" \ |
@@ -155,7 +155,7 @@ do { \ | |||
155 | unsigned long | 155 | unsigned long |
156 | clear_user(void __user *to, unsigned long n) | 156 | clear_user(void __user *to, unsigned long n) |
157 | { | 157 | { |
158 | might_sleep(); | 158 | might_fault(); |
159 | if (access_ok(VERIFY_WRITE, to, n)) | 159 | if (access_ok(VERIFY_WRITE, to, n)) |
160 | __do_clear_user(to, n); | 160 | __do_clear_user(to, n); |
161 | return n; | 161 | return n; |
@@ -197,7 +197,7 @@ long strnlen_user(const char __user *s, long n) | |||
197 | unsigned long mask = -__addr_ok(s); | 197 | unsigned long mask = -__addr_ok(s); |
198 | unsigned long res, tmp; | 198 | unsigned long res, tmp; |
199 | 199 | ||
200 | might_sleep(); | 200 | might_fault(); |
201 | 201 | ||
202 | __asm__ __volatile__( | 202 | __asm__ __volatile__( |
203 | " testl %0, %0\n" | 203 | " testl %0, %0\n" |
diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c index f4df6e7c718b..64d6c84e6353 100644 --- a/arch/x86/lib/usercopy_64.c +++ b/arch/x86/lib/usercopy_64.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #define __do_strncpy_from_user(dst,src,count,res) \ | 15 | #define __do_strncpy_from_user(dst,src,count,res) \ |
16 | do { \ | 16 | do { \ |
17 | long __d0, __d1, __d2; \ | 17 | long __d0, __d1, __d2; \ |
18 | might_sleep(); \ | 18 | might_fault(); \ |
19 | __asm__ __volatile__( \ | 19 | __asm__ __volatile__( \ |
20 | " testq %1,%1\n" \ | 20 | " testq %1,%1\n" \ |
21 | " jz 2f\n" \ | 21 | " jz 2f\n" \ |
@@ -64,7 +64,7 @@ EXPORT_SYMBOL(strncpy_from_user); | |||
64 | unsigned long __clear_user(void __user *addr, unsigned long size) | 64 | unsigned long __clear_user(void __user *addr, unsigned long size) |
65 | { | 65 | { |
66 | long __d0; | 66 | long __d0; |
67 | might_sleep(); | 67 | might_fault(); |
68 | /* no memory constraint because it doesn't change any memory gcc knows | 68 | /* no memory constraint because it doesn't change any memory gcc knows |
69 | about */ | 69 | about */ |
70 | asm volatile( | 70 | asm volatile( |
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index fea4565ff576..d8cc96a2738f 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile | |||
@@ -8,9 +8,8 @@ obj-$(CONFIG_X86_PTDUMP) += dump_pagetables.o | |||
8 | 8 | ||
9 | obj-$(CONFIG_HIGHMEM) += highmem_32.o | 9 | obj-$(CONFIG_HIGHMEM) += highmem_32.o |
10 | 10 | ||
11 | obj-$(CONFIG_MMIOTRACE_HOOKS) += kmmio.o | ||
12 | obj-$(CONFIG_MMIOTRACE) += mmiotrace.o | 11 | obj-$(CONFIG_MMIOTRACE) += mmiotrace.o |
13 | mmiotrace-y := pf_in.o mmio-mod.o | 12 | mmiotrace-y := kmmio.o pf_in.o mmio-mod.o |
14 | obj-$(CONFIG_MMIOTRACE_TEST) += testmmiotrace.o | 13 | obj-$(CONFIG_MMIOTRACE_TEST) += testmmiotrace.o |
15 | 14 | ||
16 | obj-$(CONFIG_NUMA) += numa_$(BITS).o | 15 | obj-$(CONFIG_NUMA) += numa_$(BITS).o |
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 31e8730fa246..21e996a70d68 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
@@ -53,7 +53,7 @@ | |||
53 | 53 | ||
54 | static inline int kmmio_fault(struct pt_regs *regs, unsigned long addr) | 54 | static inline int kmmio_fault(struct pt_regs *regs, unsigned long addr) |
55 | { | 55 | { |
56 | #ifdef CONFIG_MMIOTRACE_HOOKS | 56 | #ifdef CONFIG_MMIOTRACE |
57 | if (unlikely(is_kmmio_active())) | 57 | if (unlikely(is_kmmio_active())) |
58 | if (kmmio_handler(regs, addr) == 1) | 58 | if (kmmio_handler(regs, addr) == 1) |
59 | return -1; | 59 | return -1; |
@@ -413,6 +413,7 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, | |||
413 | unsigned long error_code) | 413 | unsigned long error_code) |
414 | { | 414 | { |
415 | unsigned long flags = oops_begin(); | 415 | unsigned long flags = oops_begin(); |
416 | int sig = SIGKILL; | ||
416 | struct task_struct *tsk; | 417 | struct task_struct *tsk; |
417 | 418 | ||
418 | printk(KERN_ALERT "%s: Corrupted page table at address %lx\n", | 419 | printk(KERN_ALERT "%s: Corrupted page table at address %lx\n", |
@@ -423,8 +424,8 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, | |||
423 | tsk->thread.trap_no = 14; | 424 | tsk->thread.trap_no = 14; |
424 | tsk->thread.error_code = error_code; | 425 | tsk->thread.error_code = error_code; |
425 | if (__die("Bad pagetable", regs, error_code)) | 426 | if (__die("Bad pagetable", regs, error_code)) |
426 | regs = NULL; | 427 | sig = 0; |
427 | oops_end(flags, regs, SIGKILL); | 428 | oops_end(flags, regs, sig); |
428 | } | 429 | } |
429 | #endif | 430 | #endif |
430 | 431 | ||
@@ -590,6 +591,7 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code) | |||
590 | int fault; | 591 | int fault; |
591 | #ifdef CONFIG_X86_64 | 592 | #ifdef CONFIG_X86_64 |
592 | unsigned long flags; | 593 | unsigned long flags; |
594 | int sig; | ||
593 | #endif | 595 | #endif |
594 | 596 | ||
595 | tsk = current; | 597 | tsk = current; |
@@ -849,11 +851,12 @@ no_context: | |||
849 | bust_spinlocks(0); | 851 | bust_spinlocks(0); |
850 | do_exit(SIGKILL); | 852 | do_exit(SIGKILL); |
851 | #else | 853 | #else |
854 | sig = SIGKILL; | ||
852 | if (__die("Oops", regs, error_code)) | 855 | if (__die("Oops", regs, error_code)) |
853 | regs = NULL; | 856 | sig = 0; |
854 | /* Executive summary in case the body of the oops scrolled away */ | 857 | /* Executive summary in case the body of the oops scrolled away */ |
855 | printk(KERN_EMERG "CR2: %016lx\n", address); | 858 | printk(KERN_EMERG "CR2: %016lx\n", address); |
856 | oops_end(flags, regs, SIGKILL); | 859 | oops_end(flags, regs, sig); |
857 | #endif | 860 | #endif |
858 | 861 | ||
859 | /* | 862 | /* |
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c index 1ef0f90813d6..d9d35824c56f 100644 --- a/arch/x86/vdso/vclock_gettime.c +++ b/arch/x86/vdso/vclock_gettime.c | |||
@@ -9,6 +9,9 @@ | |||
9 | * Also alternative() doesn't work. | 9 | * Also alternative() doesn't work. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | /* Disable profiling for userspace code: */ | ||
13 | #define DISABLE_BRANCH_PROFILING | ||
14 | |||
12 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
13 | #include <linux/posix-timers.h> | 16 | #include <linux/posix-timers.h> |
14 | #include <linux/time.h> | 17 | #include <linux/time.h> |