aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-12-12 06:43:05 -0500
committerIngo Molnar <mingo@elte.hu>2008-12-12 06:43:05 -0500
commit81444a799550214f549caf579cf65a0ca55e70b7 (patch)
tree3288dac0740be2e1e7d1af4ee51d792a6e91edf3 /arch/powerpc/kernel
parenta64d31baed104be25305e9c71585d3ea4ee9a418 (diff)
parentda485e0cb16726797e99a595a399b9fc721b91bc (diff)
Merge branch 'tracing/fastboot' into cpus4096
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/Makefile1
-rw-r--r--arch/powerpc/kernel/dma.c1
-rw-r--r--arch/powerpc/kernel/entry_32.S40
-rw-r--r--arch/powerpc/kernel/entry_64.S12
-rw-r--r--arch/powerpc/kernel/ftrace.c182
5 files changed, 96 insertions, 140 deletions
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
17CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog 17CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog
18CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog 18CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog
19CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog 19CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog
20CFLAGS_REMOVE_prom.o = -pg -mno-sched-epilog
20 21
21ifdef CONFIG_DYNAMIC_FTRACE 22ifdef CONFIG_DYNAMIC_FTRACE
22# dynamic ftrace setup. 23# dynamic ftrace setup.
diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c
index 1562daf8839a..3a6eaa876ee1 100644
--- a/arch/powerpc/kernel/dma.c
+++ b/arch/powerpc/kernel/dma.c
@@ -75,6 +75,7 @@ static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
75 for_each_sg(sgl, sg, nents, i) { 75 for_each_sg(sgl, sg, nents, i) {
76 sg->dma_address = sg_phys(sg) + get_dma_direct_offset(dev); 76 sg->dma_address = sg_phys(sg) + get_dma_direct_offset(dev);
77 sg->dma_length = sg->length; 77 sg->dma_length = sg->length;
78 __dma_sync_page(sg_page(sg), sg->offset, sg->length, direction);
78 } 79 }
79 80
80 return nents; 81 return nents;
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
1180mcount_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
903mcount_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 3271cd698e4c..5355244c99ff 100644
--- a/arch/powerpc/kernel/ftrace.c
+++ b/arch/powerpc/kernel/ftrace.c
@@ -114,19 +114,9 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
114 */ 114 */
115static int test_24bit_addr(unsigned long ip, unsigned long addr) 115static int test_24bit_addr(unsigned long ip, unsigned long addr)
116{ 116{
117 long diff;
118 117
119 /* 118 /* use the create_branch to verify that this offset can be branched */
120 * Can we get to addr from ip in 24 bits? 119 return create_branch((unsigned int *)ip, addr, 0);
121 * (26 really, since we mulitply by 4 for 4 byte alignment)
122 */
123 diff = addr - ip;
124
125 /*
126 * Return true if diff is less than 1 << 25
127 * and greater than -1 << 26.
128 */
129 return (diff < (1 << 25)) && (diff > (-1 << 26));
130} 120}
131 121
132static int is_bl_op(unsigned int op) 122static int is_bl_op(unsigned int op)
@@ -134,11 +124,6 @@ static int is_bl_op(unsigned int op)
134 return (op & 0xfc000003) == 0x48000001; 124 return (op & 0xfc000003) == 0x48000001;
135} 125}
136 126
137static int test_offset(unsigned long offset)
138{
139 return (offset + 0x2000000 > 0x3ffffff) || ((offset & 3) != 0);
140}
141
142static unsigned long find_bl_target(unsigned long ip, unsigned int op) 127static unsigned long find_bl_target(unsigned long ip, unsigned int op)
143{ 128{
144 static int offset; 129 static int offset;
@@ -151,37 +136,30 @@ static unsigned long find_bl_target(unsigned long ip, unsigned int op)
151 return ip + (long)offset; 136 return ip + (long)offset;
152} 137}
153 138
154static unsigned int branch_offset(unsigned long offset)
155{
156 /* return "bl ip+offset" */
157 return 0x48000001 | (offset & 0x03fffffc);
158}
159
160#ifdef CONFIG_PPC64 139#ifdef CONFIG_PPC64
161static int 140static int
162__ftrace_make_nop(struct module *mod, 141__ftrace_make_nop(struct module *mod,
163 struct dyn_ftrace *rec, unsigned long addr) 142 struct dyn_ftrace *rec, unsigned long addr)
164{ 143{
165 unsigned char replaced[MCOUNT_INSN_SIZE * 2]; 144 unsigned int op;
166 unsigned int *op = (unsigned *)&replaced; 145 unsigned int jmp[5];
167 unsigned char jmp[8]; 146 unsigned long ptr;
168 unsigned long *ptr = (unsigned long *)&jmp;
169 unsigned long ip = rec->ip; 147 unsigned long ip = rec->ip;
170 unsigned long tramp; 148 unsigned long tramp;
171 int offset; 149 int offset;
172 150
173 /* read where this goes */ 151 /* read where this goes */
174 if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE)) 152 if (probe_kernel_read(&op, (void *)ip, sizeof(int)))
175 return -EFAULT; 153 return -EFAULT;
176 154
177 /* Make sure that that this is still a 24bit jump */ 155 /* Make sure that that this is still a 24bit jump */
178 if (!is_bl_op(*op)) { 156 if (!is_bl_op(op)) {
179 printk(KERN_ERR "Not expected bl: opcode is %x\n", *op); 157 printk(KERN_ERR "Not expected bl: opcode is %x\n", op);
180 return -EINVAL; 158 return -EINVAL;
181 } 159 }
182 160
183 /* lets find where the pointer goes */ 161 /* lets find where the pointer goes */
184 tramp = find_bl_target(ip, *op); 162 tramp = find_bl_target(ip, op);
185 163
186 /* 164 /*
187 * On PPC64 the trampoline looks like: 165 * On PPC64 the trampoline looks like:
@@ -200,19 +178,25 @@ __ftrace_make_nop(struct module *mod,
200 DEBUGP("ip:%lx jumps to %lx r2: %lx", ip, tramp, mod->arch.toc); 178 DEBUGP("ip:%lx jumps to %lx r2: %lx", ip, tramp, mod->arch.toc);
201 179
202 /* Find where the trampoline jumps to */ 180 /* Find where the trampoline jumps to */
203 if (probe_kernel_read(jmp, (void *)tramp, 8)) { 181 if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) {
204 printk(KERN_ERR "Failed to read %lx\n", tramp); 182 printk(KERN_ERR "Failed to read %lx\n", tramp);
205 return -EFAULT; 183 return -EFAULT;
206 } 184 }
207 185
208 DEBUGP(" %08x %08x", 186 DEBUGP(" %08x %08x", jmp[0], jmp[1]);
209 (unsigned)(*ptr >> 32), 187
210 (unsigned)*ptr); 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 }
211 197
212 offset = (unsigned)jmp[2] << 24 | 198 offset = (unsigned)((unsigned short)jmp[0]) << 16 |
213 (unsigned)jmp[3] << 16 | 199 (unsigned)((unsigned short)jmp[1]);
214 (unsigned)jmp[6] << 8 |
215 (unsigned)jmp[7];
216 200
217 DEBUGP(" %x ", offset); 201 DEBUGP(" %x ", offset);
218 202
@@ -225,13 +209,13 @@ __ftrace_make_nop(struct module *mod,
225 return -EFAULT; 209 return -EFAULT;
226 } 210 }
227 211
228 DEBUGP(" %08x %08x\n", 212 DEBUGP(" %08x %08x\n", jmp[0], jmp[1]);
229 (unsigned)(*ptr >> 32), 213
230 (unsigned)*ptr); 214 ptr = ((unsigned long)jmp[0] << 32) + jmp[1];
231 215
232 /* This should match what was called */ 216 /* This should match what was called */
233 if (*ptr != GET_ADDR(addr)) { 217 if (ptr != GET_ADDR(addr)) {
234 printk(KERN_ERR "addr does not match %lx\n", *ptr); 218 printk(KERN_ERR "addr does not match %lx\n", ptr);
235 return -EINVAL; 219 return -EINVAL;
236 } 220 }
237 221
@@ -240,11 +224,11 @@ __ftrace_make_nop(struct module *mod,
240 * 0xe8, 0x41, 0x00, 0x28 ld r2,40(r1) 224 * 0xe8, 0x41, 0x00, 0x28 ld r2,40(r1)
241 * This needs to be turned to a nop too. 225 * This needs to be turned to a nop too.
242 */ 226 */
243 if (probe_kernel_read(replaced, (void *)(ip+4), MCOUNT_INSN_SIZE)) 227 if (probe_kernel_read(&op, (void *)(ip+4), MCOUNT_INSN_SIZE))
244 return -EFAULT; 228 return -EFAULT;
245 229
246 if (*op != 0xe8410028) { 230 if (op != 0xe8410028) {
247 printk(KERN_ERR "Next line is not ld! (%08x)\n", *op); 231 printk(KERN_ERR "Next line is not ld! (%08x)\n", op);
248 return -EINVAL; 232 return -EINVAL;
249 } 233 }
250 234
@@ -261,11 +245,14 @@ __ftrace_make_nop(struct module *mod,
261 * ld r2,40(r1) 245 * ld r2,40(r1)
262 * 1: 246 * 1:
263 */ 247 */
264 op[0] = 0x48000008; /* b +8 */ 248 op = 0x48000008; /* b +8 */
265 249
266 if (probe_kernel_write((void *)ip, replaced, MCOUNT_INSN_SIZE)) 250 if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE))
267 return -EPERM; 251 return -EPERM;
268 252
253
254 flush_icache_range(ip, ip + 8);
255
269 return 0; 256 return 0;
270} 257}
271 258
@@ -274,46 +261,52 @@ static int
274__ftrace_make_nop(struct module *mod, 261__ftrace_make_nop(struct module *mod,
275 struct dyn_ftrace *rec, unsigned long addr) 262 struct dyn_ftrace *rec, unsigned long addr)
276{ 263{
277 unsigned char replaced[MCOUNT_INSN_SIZE]; 264 unsigned int op;
278 unsigned int *op = (unsigned *)&replaced; 265 unsigned int jmp[4];
279 unsigned char jmp[8];
280 unsigned int *ptr = (unsigned int *)&jmp;
281 unsigned long ip = rec->ip; 266 unsigned long ip = rec->ip;
282 unsigned long tramp; 267 unsigned long tramp;
283 int offset;
284 268
285 if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE)) 269 if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE))
286 return -EFAULT; 270 return -EFAULT;
287 271
288 /* Make sure that that this is still a 24bit jump */ 272 /* Make sure that that this is still a 24bit jump */
289 if (!is_bl_op(*op)) { 273 if (!is_bl_op(op)) {
290 printk(KERN_ERR "Not expected bl: opcode is %x\n", *op); 274 printk(KERN_ERR "Not expected bl: opcode is %x\n", op);
291 return -EINVAL; 275 return -EINVAL;
292 } 276 }
293 277
294 /* lets find where the pointer goes */ 278 /* lets find where the pointer goes */
295 tramp = find_bl_target(ip, *op); 279 tramp = find_bl_target(ip, op);
296 280
297 /* 281 /*
298 * On PPC32 the trampoline looks like: 282 * On PPC32 the trampoline looks like:
299 * lis r11,sym@ha 283 * 0x3d, 0x60, 0x00, 0x00 lis r11,sym@ha
300 * addi r11,r11,sym@l 284 * 0x39, 0x6b, 0x00, 0x00 addi r11,r11,sym@l
301 * mtctr r11 285 * 0x7d, 0x69, 0x03, 0xa6 mtctr r11
302 * bctr 286 * 0x4e, 0x80, 0x04, 0x20 bctr
303 */ 287 */
304 288
305 DEBUGP("ip:%lx jumps to %lx", ip, tramp); 289 DEBUGP("ip:%lx jumps to %lx", ip, tramp);
306 290
307 /* Find where the trampoline jumps to */ 291 /* Find where the trampoline jumps to */
308 if (probe_kernel_read(jmp, (void *)tramp, 8)) { 292 if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) {
309 printk(KERN_ERR "Failed to read %lx\n", tramp); 293 printk(KERN_ERR "Failed to read %lx\n", tramp);
310 return -EFAULT; 294 return -EFAULT;
311 } 295 }
312 296
313 DEBUGP(" %08x %08x ", ptr[0], ptr[1]); 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 }
314 307
315 tramp = (ptr[1] & 0xffff) | 308 tramp = (jmp[1] & 0xffff) |
316 ((ptr[0] & 0xffff) << 16); 309 ((jmp[0] & 0xffff) << 16);
317 if (tramp & 0x8000) 310 if (tramp & 0x8000)
318 tramp -= 0x10000; 311 tramp -= 0x10000;
319 312
@@ -326,11 +319,13 @@ __ftrace_make_nop(struct module *mod,
326 return -EINVAL; 319 return -EINVAL;
327 } 320 }
328 321
329 op[0] = PPC_NOP_INSTR; 322 op = PPC_NOP_INSTR;
330 323
331 if (probe_kernel_write((void *)ip, replaced, MCOUNT_INSN_SIZE)) 324 if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE))
332 return -EPERM; 325 return -EPERM;
333 326
327 flush_icache_range(ip, ip + 8);
328
334 return 0; 329 return 0;
335} 330}
336#endif /* PPC64 */ 331#endif /* PPC64 */
@@ -384,13 +379,11 @@ int ftrace_make_nop(struct module *mod,
384static int 379static int
385__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) 380__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
386{ 381{
387 unsigned char replaced[MCOUNT_INSN_SIZE * 2]; 382 unsigned int op[2];
388 unsigned int *op = (unsigned *)&replaced;
389 unsigned long ip = rec->ip; 383 unsigned long ip = rec->ip;
390 unsigned long offset;
391 384
392 /* read where this goes */ 385 /* read where this goes */
393 if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE * 2)) 386 if (probe_kernel_read(op, (void *)ip, MCOUNT_INSN_SIZE * 2))
394 return -EFAULT; 387 return -EFAULT;
395 388
396 /* 389 /*
@@ -409,43 +402,40 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
409 return -EINVAL; 402 return -EINVAL;
410 } 403 }
411 404
412 /* now calculate a jump to the ftrace caller trampoline */ 405 /* create the branch to the trampoline */
413 offset = rec->arch.mod->arch.tramp - ip; 406 op[0] = create_branch((unsigned int *)ip,
414 407 rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
415 if (test_offset(offset)) { 408 if (!op[0]) {
416 printk(KERN_ERR "REL24 %li out of range!\n", 409 printk(KERN_ERR "REL24 out of range!\n");
417 (long int)offset);
418 return -EINVAL; 410 return -EINVAL;
419 } 411 }
420 412
421 /* Set to "bl addr" */
422 op[0] = branch_offset(offset);
423 /* ld r2,40(r1) */ 413 /* ld r2,40(r1) */
424 op[1] = 0xe8410028; 414 op[1] = 0xe8410028;
425 415
426 DEBUGP("write to %lx\n", rec->ip); 416 DEBUGP("write to %lx\n", rec->ip);
427 417
428 if (probe_kernel_write((void *)ip, replaced, MCOUNT_INSN_SIZE * 2)) 418 if (probe_kernel_write((void *)ip, op, MCOUNT_INSN_SIZE * 2))
429 return -EPERM; 419 return -EPERM;
430 420
421 flush_icache_range(ip, ip + 8);
422
431 return 0; 423 return 0;
432} 424}
433#else 425#else
434static int 426static int
435__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) 427__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
436{ 428{
437 unsigned char replaced[MCOUNT_INSN_SIZE]; 429 unsigned int op;
438 unsigned int *op = (unsigned *)&replaced;
439 unsigned long ip = rec->ip; 430 unsigned long ip = rec->ip;
440 unsigned long offset;
441 431
442 /* read where this goes */ 432 /* read where this goes */
443 if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE)) 433 if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE))
444 return -EFAULT; 434 return -EFAULT;
445 435
446 /* It should be pointing to a nop */ 436 /* It should be pointing to a nop */
447 if (op[0] != PPC_NOP_INSTR) { 437 if (op != PPC_NOP_INSTR) {
448 printk(KERN_ERR "Expected NOP but have %x\n", op[0]); 438 printk(KERN_ERR "Expected NOP but have %x\n", op);
449 return -EINVAL; 439 return -EINVAL;
450 } 440 }
451 441
@@ -455,23 +445,21 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
455 return -EINVAL; 445 return -EINVAL;
456 } 446 }
457 447
458 /* now calculate a jump to the ftrace caller trampoline */ 448 /* create the branch to the trampoline */
459 offset = rec->arch.mod->arch.tramp - ip; 449 op = create_branch((unsigned int *)ip,
460 450 rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
461 if (test_offset(offset)) { 451 if (!op) {
462 printk(KERN_ERR "REL24 %li out of range!\n", 452 printk(KERN_ERR "REL24 out of range!\n");
463 (long int)offset);
464 return -EINVAL; 453 return -EINVAL;
465 } 454 }
466 455
467 /* Set to "bl addr" */
468 op[0] = branch_offset(offset);
469
470 DEBUGP("write to %lx\n", rec->ip); 456 DEBUGP("write to %lx\n", rec->ip);
471 457
472 if (probe_kernel_write((void *)ip, replaced, MCOUNT_INSN_SIZE)) 458 if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE))
473 return -EPERM; 459 return -EPERM;
474 460
461 flush_icache_range(ip, ip + 8);
462
475 return 0; 463 return 0;
476} 464}
477#endif /* CONFIG_PPC64 */ 465#endif /* CONFIG_PPC64 */