diff options
Diffstat (limited to 'arch/powerpc/kernel')
| -rw-r--r-- | arch/powerpc/kernel/Makefile | 11 | ||||
| -rw-r--r-- | arch/powerpc/kernel/align.c | 38 | ||||
| -rw-r--r-- | arch/powerpc/kernel/crash_dump.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/kernel/dbell.c | 44 | ||||
| -rw-r--r-- | arch/powerpc/kernel/entry_32.S | 129 | ||||
| -rw-r--r-- | arch/powerpc/kernel/entry_64.S | 89 | ||||
| -rw-r--r-- | arch/powerpc/kernel/ftrace.c | 222 | ||||
| -rw-r--r-- | arch/powerpc/kernel/head_booke.h | 2 | ||||
| -rw-r--r-- | arch/powerpc/kernel/head_fsl_booke.S | 20 | ||||
| -rw-r--r-- | arch/powerpc/kernel/module_64.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/kernel/pci-common.c | 41 | ||||
| -rw-r--r-- | arch/powerpc/kernel/pci_32.c | 36 | ||||
| -rw-r--r-- | arch/powerpc/kernel/pci_64.c | 19 | ||||
| -rw-r--r-- | arch/powerpc/kernel/process.c | 58 | ||||
| -rw-r--r-- | arch/powerpc/kernel/rtas.c | 10 | ||||
| -rw-r--r-- | arch/powerpc/kernel/signal.h | 10 | ||||
| -rw-r--r-- | arch/powerpc/kernel/traps.c | 79 | ||||
| -rw-r--r-- | arch/powerpc/kernel/vmlinux.lds.S | 1 |
18 files changed, 549 insertions, 264 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index d15992119085..dfec3d2790b2 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -18,12 +18,10 @@ CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog CFLAGS_REMOVE_prom.o = -pg -mno-sched-epilog - -ifdef CONFIG_DYNAMIC_FTRACE -# dynamic ftrace setup. +# do not trace tracer code CFLAGS_REMOVE_ftrace.o = -pg -mno-sched-epilog -endif - +# timers used by tracing +CFLAGS_REMOVE_time.o = -pg -mno-sched-epilog endif obj-y := cputable.o ptrace.o syscalls.o \ @@ -61,7 +59,7 @@ obj-$(CONFIG_HIBERNATION) += swsusp.o suspend.o \ obj64-$(CONFIG_HIBERNATION) += swsusp_asm64.o obj-$(CONFIG_MODULES) += module.o module_$(CONFIG_WORD_SIZE).o obj-$(CONFIG_44x) += cpu_setup_44x.o -obj-$(CONFIG_FSL_BOOKE) += cpu_setup_fsl_booke.o +obj-$(CONFIG_FSL_BOOKE) += cpu_setup_fsl_booke.o dbell.o extra-$(CONFIG_PPC_STD_MMU) := head_32.o extra-$(CONFIG_PPC64) := head_64.o @@ -95,6 +93,7 @@ obj-$(CONFIG_AUDIT) += audit.o obj64-$(CONFIG_AUDIT) += compat_audit.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o +obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c index 5af4e9b2dbe2..5ffcfaa77d6a 100644 --- a/arch/powerpc/kernel/align.c +++ b/arch/powerpc/kernel/align.c @@ -187,7 +187,7 @@ static struct aligninfo aligninfo[128] = { { 4, ST+F+S+U }, /* 11 1 1010: stfsux */ { 8, ST+F+U }, /* 11 1 1011: stfdux */ INVALID, /* 11 1 1100 */ - INVALID, /* 11 1 1101 */ + { 4, LD+F }, /* 11 1 1101: lfiwzx */ INVALID, /* 11 1 1110 */ INVALID, /* 11 1 1111 */ }; @@ -367,27 +367,24 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg, unsigned int flags) { - char *ptr = (char *) ¤t->thread.TS_FPR(reg); - int i, ret; + char *ptr0 = (char *) ¤t->thread.TS_FPR(reg); + char *ptr1 = (char *) ¤t->thread.TS_FPR(reg+1); + int i, ret, sw = 0; if (!(flags & F)) return 0; if (reg & 1) return 0; /* invalid form: FRS/FRT must be even */ - if (!(flags & SW)) { - /* not byte-swapped - easy */ - if (!(flags & ST)) - ret = __copy_from_user(ptr, addr, 16); - else - ret = __copy_to_user(addr, ptr, 16); - } else { - /* each FPR value is byte-swapped separately */ - ret = 0; - for (i = 0; i < 16; ++i) { - if (!(flags & ST)) - ret |= __get_user(ptr[i^7], addr + i); - else - ret |= __put_user(ptr[i^7], addr + i); + if (flags & SW) + sw = 7; + ret = 0; + for (i = 0; i < 8; ++i) { + if (!(flags & ST)) { + ret |= __get_user(ptr0[i^sw], addr + i); + ret |= __get_user(ptr1[i^sw], addr + i + 8); + } else { + ret |= __put_user(ptr0[i^sw], addr + i); + ret |= __put_user(ptr1[i^sw], addr + i + 8); } } if (ret) @@ -646,11 +643,16 @@ static int emulate_vsx(unsigned char __user *addr, unsigned int reg, unsigned int areg, struct pt_regs *regs, unsigned int flags, unsigned int length) { - char *ptr = (char *) ¤t->thread.TS_FPR(reg); + char *ptr; int ret = 0; flush_vsx_to_thread(current); + if (reg < 32) + ptr = (char *) ¤t->thread.TS_FPR(reg); + else + ptr = (char *) ¤t->thread.vr[reg - 32]; + if (flags & ST) ret = __copy_to_user(addr, ptr, length); else { diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index 19671aca6591..5fb667a60894 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c @@ -48,7 +48,7 @@ static void __init create_trampoline(unsigned long addr) * branch to "addr" we jump to ("addr" + 32 MB). Although it requires * two instructions it doesn't require any registers. */ - patch_instruction(p, PPC_NOP_INSTR); + patch_instruction(p, PPC_INST_NOP); patch_branch(++p, addr + PHYSICAL_START, 0); } diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c new file mode 100644 index 000000000000..1493734cd871 --- /dev/null +++ b/arch/powerpc/kernel/dbell.c @@ -0,0 +1,44 @@ +/* + * Author: Kumar Gala <galak@kernel.crashing.org> + * + * Copyright 2009 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/smp.h> +#include <linux/threads.h> + +#include <asm/dbell.h> + +#ifdef CONFIG_SMP +unsigned long dbell_smp_message[NR_CPUS]; + +void smp_dbell_message_pass(int target, int msg) +{ + int i; + + if(target < NR_CPUS) { + set_bit(msg, &dbell_smp_message[target]); + ppc_msgsnd(PPC_DBELL, 0, target); + } + else if(target == MSG_ALL_BUT_SELF) { + for_each_online_cpu(i) { + if (i == smp_processor_id()) + continue; + set_bit(msg, &dbell_smp_message[i]); + ppc_msgsnd(PPC_DBELL, 0, i); + } + } + else { /* target == MSG_ALL */ + for_each_online_cpu(i) + set_bit(msg, &dbell_smp_message[i]); + ppc_msgsnd(PPC_DBELL, PPC_DBELL_MSG_BRDCAST, 0); + } +} +#endif diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 6f7eb7e00c79..4dd38f129153 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -63,7 +63,7 @@ debug_transfer_to_handler: .globl crit_transfer_to_handler crit_transfer_to_handler: -#ifdef CONFIG_FSL_BOOKE +#ifdef CONFIG_PPC_BOOK3E_MMU mfspr r0,SPRN_MAS0 stw r0,MAS0(r11) mfspr r0,SPRN_MAS1 @@ -78,7 +78,7 @@ crit_transfer_to_handler: mfspr r0,SPRN_MAS7 stw r0,MAS7(r11) #endif /* CONFIG_PHYS_64BIT */ -#endif /* CONFIG_FSL_BOOKE */ +#endif /* CONFIG_PPC_BOOK3E_MMU */ #ifdef CONFIG_44x mfspr r0,SPRN_MMUCR stw r0,MMUCR(r11) @@ -914,7 +914,7 @@ exc_exit_restart_end: mtspr SPRN_##exc_lvl_srr0,r9; \ mtspr SPRN_##exc_lvl_srr1,r10; -#if defined(CONFIG_FSL_BOOKE) +#if defined(CONFIG_PPC_BOOK3E_MMU) #ifdef CONFIG_PHYS_64BIT #define RESTORE_MAS7 \ lwz r11,MAS7(r1); \ @@ -956,7 +956,7 @@ ret_from_crit_exc: lwz r10,crit_srr1@l(r10); mtspr SPRN_SRR0,r9; mtspr SPRN_SRR1,r10; - RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI) + RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, PPC_RFCI) #endif /* CONFIG_40x */ #ifdef CONFIG_BOOKE @@ -967,7 +967,7 @@ ret_from_crit_exc: stw r10,KSP_LIMIT(r9) RESTORE_xSRR(SRR0,SRR1); RESTORE_MMU_REGS; - RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI) + RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, PPC_RFCI) .globl ret_from_debug_exc ret_from_debug_exc: @@ -981,7 +981,7 @@ ret_from_debug_exc: RESTORE_xSRR(SRR0,SRR1); RESTORE_xSRR(CSRR0,CSRR1); RESTORE_MMU_REGS; - RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, RFDI) + RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, PPC_RFDI) .globl ret_from_mcheck_exc ret_from_mcheck_exc: @@ -992,7 +992,7 @@ ret_from_mcheck_exc: RESTORE_xSRR(CSRR0,CSRR1); RESTORE_xSRR(DSRR0,DSRR1); RESTORE_MMU_REGS; - RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI) + RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, PPC_RFMCI) #endif /* CONFIG_BOOKE */ /* @@ -1176,59 +1176,27 @@ _GLOBAL(_mcount) bctr _GLOBAL(ftrace_caller) - /* Based off of objdump optput from glibc */ - stwu r1,-48(r1) - stw r3, 12(r1) - stw r4, 16(r1) - stw r5, 20(r1) - stw r6, 24(r1) - mflr r3 - lwz r4, 52(r1) - mfcr r5 - stw r7, 28(r1) - stw r8, 32(r1) - stw r9, 36(r1) - stw r10,40(r1) - stw r3, 44(r1) - stw r5, 8(r1) + MCOUNT_SAVE_FRAME + /* r3 ends up with link register */ subi r3, r3, MCOUNT_INSN_SIZE .globl ftrace_call ftrace_call: bl ftrace_stub nop - lwz r6, 8(r1) - lwz r0, 44(r1) - lwz r3, 12(r1) - mtctr r0 - lwz r4, 16(r1) - mtcr r6 - lwz r5, 20(r1) - lwz r6, 24(r1) - lwz r0, 52(r1) - lwz r7, 28(r1) - lwz r8, 32(r1) - mtlr r0 - lwz r9, 36(r1) - lwz r10,40(r1) - addi r1, r1, 48 +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +.globl ftrace_graph_call +ftrace_graph_call: + b ftrace_graph_stub +_GLOBAL(ftrace_graph_stub) +#endif + MCOUNT_RESTORE_FRAME + /* old link register ends up in ctr reg */ bctr #else _GLOBAL(mcount) _GLOBAL(_mcount) - stwu r1,-48(r1) - stw r3, 12(r1) - stw r4, 16(r1) - stw r5, 20(r1) - stw r6, 24(r1) - mflr r3 - lwz r4, 52(r1) - mfcr r5 - stw r7, 28(r1) - stw r8, 32(r1) - stw r9, 36(r1) - stw r10,40(r1) - stw r3, 44(r1) - stw r5, 8(r1) + + MCOUNT_SAVE_FRAME subi r3, r3, MCOUNT_INSN_SIZE LOAD_REG_ADDR(r5, ftrace_trace_function) @@ -1236,28 +1204,55 @@ _GLOBAL(_mcount) mtctr r5 bctrl - nop - lwz r6, 8(r1) - lwz r0, 44(r1) - lwz r3, 12(r1) - mtctr r0 - lwz r4, 16(r1) - mtcr r6 - lwz r5, 20(r1) - lwz r6, 24(r1) - lwz r0, 52(r1) - lwz r7, 28(r1) - lwz r8, 32(r1) - mtlr r0 - lwz r9, 36(r1) - lwz r10,40(r1) - addi r1, r1, 48 +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + b ftrace_graph_caller +#endif + MCOUNT_RESTORE_FRAME bctr #endif _GLOBAL(ftrace_stub) blr +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +_GLOBAL(ftrace_graph_caller) + /* load r4 with local address */ + lwz r4, 44(r1) + subi r4, r4, MCOUNT_INSN_SIZE + + /* get the parent address */ + addi r3, r1, 52 + + bl prepare_ftrace_return + nop + + MCOUNT_RESTORE_FRAME + /* old link register ends up in ctr reg */ + bctr + +_GLOBAL(return_to_handler) + /* need to save return values */ + stwu r1, -32(r1) + stw r3, 20(r1) + stw r4, 16(r1) + stw r31, 12(r1) + mr r31, r1 + + bl ftrace_return_to_handler + nop + + /* return value has real return address */ + mtlr r3 + + lwz r3, 20(r1) + lwz r4, 16(r1) + lwz r31,12(r1) + lwz r1, 0(r1) + + /* Jump back to real return address */ + blr +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ + #endif /* CONFIG_MCOUNT */ diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 383ed6eb0085..abfc32330479 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -908,6 +908,12 @@ _GLOBAL(ftrace_caller) ftrace_call: bl ftrace_stub nop +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +.globl ftrace_graph_call +ftrace_graph_call: + b ftrace_graph_stub +_GLOBAL(ftrace_graph_stub) +#endif ld r0, 128(r1) mtlr r0 addi r1, r1, 112 @@ -931,13 +937,90 @@ _GLOBAL(_mcount) ld r5,0(r5) mtctr r5 bctrl - nop + + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + b ftrace_graph_caller +#endif ld r0, 128(r1) mtlr r0 addi r1, r1, 112 _GLOBAL(ftrace_stub) blr -#endif -#endif +#endif /* CONFIG_DYNAMIC_FTRACE */ + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +_GLOBAL(ftrace_graph_caller) + /* load r4 with local address */ + ld r4, 128(r1) + subi r4, r4, MCOUNT_INSN_SIZE + + /* get the parent address */ + ld r11, 112(r1) + addi r3, r11, 16 + + bl .prepare_ftrace_return + nop + + ld r0, 128(r1) + mtlr r0 + addi r1, r1, 112 + blr + +_GLOBAL(return_to_handler) + /* need to save return values */ + std r4, -24(r1) + std r3, -16(r1) + std r31, -8(r1) + mr r31, r1 + stdu r1, -112(r1) + + bl .ftrace_return_to_handler + nop + + /* return value has real return address */ + mtlr r3 + + ld r1, 0(r1) + ld r4, -24(r1) + ld r3, -16(r1) + ld r31, -8(r1) + + /* Jump back to real return address */ + blr + +_GLOBAL(mod_return_to_handler) + /* need to save return values */ + std r4, -32(r1) + std r3, -24(r1) + /* save TOC */ + std r2, -16(r1) + std r31, -8(r1) + mr r31, r1 + stdu r1, -112(r1) + + /* + * We are in a module using the module's TOC. + * Switch to our TOC to run inside the core kernel. + */ + LOAD_REG_IMMEDIATE(r4,ftrace_return_to_handler) + ld r2, 8(r4) + + bl .ftrace_return_to_handler + nop + + /* return value has real return address */ + mtlr r3 + + ld r1, 0(r1) + ld r4, -32(r1) + ld r3, -24(r1) + ld r2, -16(r1) + ld r31, -8(r1) + + /* Jump back to real return address */ + blr +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ +#endif /* CONFIG_FUNCTION_TRACER */ diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c index 60c60ccf5e3c..5b5d16b2cac8 100644 --- a/arch/powerpc/kernel/ftrace.c +++ b/arch/powerpc/kernel/ftrace.c @@ -5,6 +5,9 @@ * * Thanks goes out to P.A. Semi, Inc for supplying me with a PPC64 box. * + * Added function graph tracer code, taken from x86 that was written + * by Frederic Weisbecker, and ported to PPC by Steven Rostedt. + * */ #include <linux/spinlock.h> @@ -20,14 +23,6 @@ #include <asm/code-patching.h> #include <asm/ftrace.h> -#if 0 -#define DEBUGP printk -#else -#define DEBUGP(fmt , ...) do { } while (0) -#endif - -static unsigned int ftrace_nop = PPC_NOP_INSTR; - #ifdef CONFIG_PPC32 # define GET_ADDR(addr) addr #else @@ -35,37 +30,23 @@ static unsigned int ftrace_nop = PPC_NOP_INSTR; # define GET_ADDR(addr) (*(unsigned long *)addr) #endif - -static unsigned int ftrace_calc_offset(long ip, long addr) +#ifdef CONFIG_DYNAMIC_FTRACE +static unsigned int ftrace_nop_replace(void) { - return (int)(addr - ip); + return PPC_INST_NOP; } -static unsigned char *ftrace_nop_replace(void) +static unsigned int +ftrace_call_replace(unsigned long ip, unsigned long addr, int link) { - return (char *)&ftrace_nop; -} - -static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) -{ - static unsigned int op; + unsigned int op; - /* - * It would be nice to just use create_function_call, but that will - * update the code itself. Here we need to just return the - * instruction that is going to be modified, without modifying the - * code. - */ addr = GET_ADDR(addr); - /* Set to "bl addr" */ - op = 0x48000001 | (ftrace_calc_offset(ip, addr) & 0x03fffffc); + /* if (link) set op to 'bl' else 'b' */ + op = create_branch((unsigned int *)ip, addr, link ? 1 : 0); - /* - * No locking needed, this must be called via kstop_machine - * which in essence is like running on a uniprocessor machine. - */ - return (unsigned char *)&op; + return op; } #ifdef CONFIG_PPC64 @@ -77,10 +58,9 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) #endif static int -ftrace_modify_code(unsigned long ip, unsigned char *old_code, - unsigned char *new_code) +ftrace_modify_code(unsigned long ip, unsigned int old, unsigned int new) { - unsigned char replaced[MCOUNT_INSN_SIZE]; + unsigned int replaced; /* * Note: Due to modules and __init, code can @@ -93,15 +73,15 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code, */ /* read the text we want to modify */ - if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE)) + if (probe_kernel_read(&replaced, (void *)ip, MCOUNT_INSN_SIZE)) return -EFAULT; /* Make sure it is what we expect it to be */ - if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0) + if (replaced != old) return -EINVAL; /* replace the text with the new text */ - if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE)) + if (probe_kernel_write((void *)ip, &new, MCOUNT_INSN_SIZE)) return -EPERM; flush_icache_range(ip, ip + 8); @@ -119,6 +99,8 @@ static int test_24bit_addr(unsigned long ip, unsigned long addr) return create_branch((unsigned int *)ip, addr, 0); } +#ifdef CONFIG_MODULES + static int is_bl_op(unsigned int op) { return (op & 0xfc000003) == 0x48000001; @@ -175,7 +157,7 @@ __ftrace_make_nop(struct module *mod, * 0xe8, 0x4c, 0x00, 0x28, ld r2,40(r12) */ - DEBUGP("ip:%lx jumps to %lx r2: %lx", ip, tramp, mod->arch.toc); + pr_debug("ip:%lx jumps to %lx r2: %lx", ip, tramp, mod->arch.toc); /* Find where the trampoline jumps to */ if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) { @@ -183,7 +165,7 @@ __ftrace_make_nop(struct module *mod, return -EFAULT; } - DEBUGP(" %08x %08x", jmp[0], jmp[1]); + pr_debug(" %08x %08x", jmp[0], jmp[1]); /* verify that this is what we expect it to be */ if (((jmp[0] & 0xffff0000) != 0x3d820000) || @@ -199,18 +181,18 @@ __ftrace_make_nop(struct module *mod, offset = ((unsigned)((unsigned short)jmp[0]) << 16) + (int)((short)jmp[1]); - DEBUGP(" %x ", offset); + pr_debug(" %x ", offset); /* get the address this jumps too */ tramp = mod->arch.toc + offset + 32; - DEBUGP("toc: %lx", tramp); + pr_debug("toc: %lx", tramp); if (probe_kernel_read(jmp, (void *)tramp, 8)) { printk(KERN_ERR "Failed to read %lx\n", tramp); return -EFAULT; } - DEBUGP(" %08x %08x\n", jmp[0], jmp[1]); + pr_debug(" %08x %08x\n", jmp[0], jmp[1]); ptr = ((unsigned long)jmp[0] << 32) + jmp[1]; @@ -287,7 +269,7 @@ __ftrace_make_nop(struct module *mod, * 0x4e, 0x80, 0x04, 0x20 bctr */ - DEBUGP("ip:%lx jumps to %lx", ip, tramp); + pr_debug("ip:%lx jumps to %lx", ip, tramp); /* Find where the trampoline jumps to */ if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) { @@ -295,7 +277,7 @@ __ftrace_make_nop(struct module *mod, return -EFAULT; } - DEBUGP(" %08x %08x ", jmp[0], jmp[1]); + pr_debug(" %08x %08x ", jmp[0], jmp[1]); /* verify that this is what we expect it to be */ if (((jmp[0] & 0xffff0000) != 0x3d600000) || @@ -311,7 +293,7 @@ __ftrace_make_nop(struct module *mod, if (tramp & 0x8000) tramp -= 0x10000; - DEBUGP(" %x ", tramp); + pr_debug(" %x ", tramp); if (tramp != addr) { printk(KERN_ERR @@ -320,7 +302,7 @@ __ftrace_make_nop(struct module *mod, return -EINVAL; } - op = PPC_NOP_INSTR; + op = PPC_INST_NOP; if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE)) return -EPERM; @@ -330,12 +312,13 @@ __ftrace_make_nop(struct module *mod, return 0; } #endif /* PPC64 */ +#endif /* CONFIG_MODULES */ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) { - unsigned char *old, *new; unsigned long ip = rec->ip; + unsigned int old, new; /* * If the calling address is more that 24 bits away, @@ -344,11 +327,12 @@ int ftrace_make_nop(struct module *mod, */ if (test_24bit_addr(ip, addr)) { /* within range */ - old = ftrace_call_replace(ip, addr); + old = ftrace_call_replace(ip, addr, 1); new = ftrace_nop_replace(); return ftrace_modify_code(ip, old, new); } +#ifdef CONFIG_MODULES /* * Out of range jumps are called from modules. * We should either already have a pointer to the module @@ -373,9 +357,13 @@ int ftrace_make_nop(struct module *mod, mod = rec->arch.mod; return __ftrace_make_nop(mod, rec, addr); - +#else + /* We should not get here without modules */ + return -EINVAL; +#endif /* CONFIG_MODULES */ } +#ifdef CONFIG_MODULES #ifdef CONFIG_PPC64 static int __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) @@ -392,7 +380,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) * b +8; ld r2,40(r1) */ if (((op[0] != 0x48000008) || (op[1] != 0xe8410028)) && - ((op[0] != PPC_NOP_INSTR) || (op[1] != PPC_NOP_INSTR))) { + ((op[0] != PPC_INST_NOP) || (op[1] != PPC_INST_NOP))) { printk(KERN_ERR "Expected NOPs but have %x %x\n", op[0], op[1]); return -EINVAL; } @@ -414,7 +402,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) /* ld r2,40(r1) */ op[1] = 0xe8410028; - DEBUGP("write to %lx\n", rec->ip); + pr_debug("write to %lx\n", rec->ip); if (probe_kernel_write((void *)ip, op, MCOUNT_INSN_SIZE * 2)) return -EPERM; @@ -435,7 +423,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) return -EFAULT; /* It should be pointing to a nop */ - if (op != PPC_NOP_INSTR) { + if (op != PPC_INST_NOP) { printk(KERN_ERR "Expected NOP but have %x\n", op); return -EINVAL; } @@ -454,7 +442,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) return -EINVAL; } - DEBUGP("write to %lx\n", rec->ip); + pr_debug("write to %lx\n", rec->ip); if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE)) return -EPERM; @@ -464,11 +452,12 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) return 0; } #endif /* CONFIG_PPC64 */ +#endif /* CONFIG_MODULES */ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) { - unsigned char *old, *new; unsigned long ip = rec->ip; + unsigned int old, new; /* * If the calling address is more that 24 bits away, @@ -478,10 +467,11 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) if (test_24bit_addr(ip, addr)) { /* within range */ old = ftrace_nop_replace(); - new = ftrace_call_replace(ip, addr); + new = ftrace_call_replace(ip, addr, 1); return ftrace_modify_code(ip, old, new); } +#ifdef CONFIG_MODULES /* * Out of range jumps are called from modules. * Being that we are converting from nop, it had better @@ -493,16 +483,20 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) } return __ftrace_make_call(rec, addr); +#else + /* We should not get here without modules */ + return -EINVAL; +#endif /* CONFIG_MODULES */ } int ftrace_update_ftrace_func(ftrace_func_t func) { unsigned long ip = (unsigned long)(&ftrace_call); - unsigned char old[MCOUNT_INSN_SIZE], *new; + unsigned int old, new; int ret; - memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE); - new = ftrace_call_replace(ip, (unsigned long)func); + old = *(unsigned int *)&ftrace_call; + new = ftrace_call_replace(ip, (unsigned long)func, 1); ret = ftrace_modify_code(ip, old, new); return ret; @@ -517,3 +511,115 @@ int __init ftrace_dyn_arch_init(void *data) return 0; } +#endif /* CONFIG_DYNAMIC_FTRACE */ + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + +#ifdef CONFIG_DYNAMIC_FTRACE +extern void ftrace_graph_call(void); +extern void ftrace_graph_stub(void); + +int ftrace_enable_ftrace_graph_caller(void) +{ + unsigned long ip = (unsigned long)(&ftrace_graph_call); + unsigned long addr = (unsigned long)(&ftrace_graph_caller); + unsigned long stub = (unsigned long)(&ftrace_graph_stub); + unsigned int old, new; + + old = ftrace_call_replace(ip, stub, 0); + new = ftrace_call_replace(ip, addr, 0); + + return ftrace_modify_code(ip, old, new); +} + +int ftrace_disable_ftrace_graph_caller(void) +{ + unsigned long ip = (unsigned long)(&ftrace_graph_call); + unsigned long addr = (unsigned long)(&ftrace_graph_caller); + unsigned long stub = (unsigned long)(&ftrace_graph_stub); + unsigned int old, new; + + old = ftrace_call_replace(ip, addr, 0); + new = ftrace_call_replace(ip, stub, 0); + + return ftrace_modify_code(ip, old, new); +} +#endif /* CONFIG_DYNAMIC_FTRACE */ + +#ifdef CONFIG_PPC64 +extern void mod_return_to_handler(void); +#endif + +/* + * Hook the return address and push it in the stack of return addrs + * in current thread info. + */ +void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) +{ + unsigned long old; + unsigned long long calltime; + int faulted; + struct ftrace_graph_ent trace; + unsigned long return_hooker = (unsigned long)&return_to_handler; + + if (unlikely(atomic_read(¤t->tracing_graph_pause))) + return; + +#if CONFIG_PPC64 + /* non core kernel code needs to save and restore the TOC */ + if (REGION_ID(self_addr) != KERNEL_REGION_ID) + return_hooker = (unsigned long)&mod_return_to_handler; +#endif + + return_hooker = GET_ADDR(return_hooker); + + /* + * Protect against fault, even if it shouldn't + * happen. This tool is too much intrusive to + * ignore such a protection. + */ + asm volatile( + "1: " PPC_LL "%[old], 0(%[parent])\n" + "2: " PPC_STL "%[return_hooker], 0(%[parent])\n" + " li %[faulted], 0\n" + "3:\n" + + ".section .fixup, \"ax\"\n" + "4: li %[faulted], 1\n" + " b 3b\n" + ".previous\n" + + ".section __ex_table,\"a\"\n" + PPC_LONG_ALIGN "\n" + PPC_LONG "1b,4b\n" + PPC_LONG "2b,4b\n" + ".previous" + + : [old] "=r" (old), [faulted] "=r" (faulted) + : [parent] "r" (parent), [return_hooker] "r" (return_hooker) + : "memory" + ); + + if (unlikely(faulted)) { + ftrace_graph_stop(); + WARN_ON(1); + return; + } + + calltime = cpu_clock(raw_smp_processor_id()); + + if (ftrace_push_return_trace(old, calltime, + self_addr, &trace.depth) == -EBUSY) { + *parent = old; + return; + } + + trace.func = self_addr; + + /* Only trace if the calling function expects to */ + if (!ftrace_graph_entry(&trace)) { + current->curr_ret_stack--; + *parent = old; + } +} +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h index 69a4489bc86a..95f39f1e68d4 100644 --- a/arch/powerpc/kernel/head_booke.h +++ b/arch/powerpc/kernel/head_booke.h @@ -288,7 +288,7 @@ label: lwz r11,GPR11(r8); \ mfspr r8,DEBUG_SPRG; \ \ - RFDI; \ + PPC_RFDI; \ b .; \ \ /* continue normal handling for a debug exception... */ \ diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 64ecb1603a77..4c22620d009b 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -173,7 +173,7 @@ skpinv: addi r6,r6,1 /* Increment */ /* grab and fixup the RPN */ mfspr r6,SPRN_MAS1 /* extract MAS1[SIZE] */ - rlwinm r6,r6,25,27,30 + rlwinm r6,r6,25,27,31 li r8,-1 addi r6,r6,10 slw r6,r8,r6 /* convert to mask */ @@ -199,7 +199,7 @@ skpinv: addi r6,r6,1 /* Increment */ xori r6,r4,1 /* Setup TMP mapping in the other Address space */ slwi r6,r6,12 oris r6,r6,(MAS1_VALID|MAS1_IPROT)@h - ori r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_4K))@l + ori r6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_4K))@l mtspr SPRN_MAS1,r6 mfspr r6,SPRN_MAS2 li r7,0 /* temp EPN = 0 */ @@ -257,10 +257,10 @@ skpinv: addi r6,r6,1 /* Increment */ lis r6,0x1000 /* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */ mtspr SPRN_MAS0,r6 lis r6,(MAS1_VALID|MAS1_IPROT)@h - ori r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_64M))@l + ori r6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_64M))@l mtspr SPRN_MAS1,r6 - lis r6,MAS2_VAL(PAGE_OFFSET, BOOKE_PAGESZ_64M, M_IF_SMP)@h - ori r6,r6,MAS2_VAL(PAGE_OFFSET, BOOKE_PAGESZ_64M, M_IF_SMP)@l + lis r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@h + ori r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@l mtspr SPRN_MAS2,r6 mtspr SPRN_MAS3,r8 tlbwe @@ -315,7 +315,7 @@ skpinv: addi r6,r6,1 /* Increment */ mtspr SPRN_IVPR,r4 /* Setup the defaults for TLB entries */ - li r2,(MAS4_TSIZED(BOOKE_PAGESZ_4K))@l + li r2,(MAS4_TSIZED(BOOK3E_PAGESZ_4K))@l #ifdef CONFIG_E200 oris r2,r2,MAS4_TLBSELD(1)@h #endif @@ -698,7 +698,9 @@ interrupt_base: /* Performance Monitor */ EXCEPTION(0x2060, PerformanceMonitor, performance_monitor_exception, EXC_XFER_STD) - EXCEPTION(0x2070, Doorbell, unknown_exception, EXC_XFER_STD) + EXCEPTION(0x2070, Doorbell, doorbell_exception, EXC_XFER_STD) + + CRITICAL_EXCEPTION(0x2080, CriticalDoorbell, unknown_exception) /* Debug Interrupt */ |
