diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-03 09:52:04 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-03 09:52:04 -0700 |
commit | 3ba113d14cedcd88105a3b9c90f8ecce829e1095 (patch) | |
tree | 357f50c6a45bf57a16d46b3157dfcd4e28233079 /arch/parisc/kernel | |
parent | bad6a5c08c119572c888d5df2bd7691a4da6b9e8 (diff) | |
parent | b609308e1415efebdf79ebd553f4dd47b0ff2722 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/kyle/parisc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/kyle/parisc-2.6: (23 commits)
parisc: move dereference_function_descriptor to process.c
parisc: Move kernel Elf_Fdesc define to <asm/elf.h>
parisc: fix build when ARCH_HAS_KMAP
parisc: fix "make tar-pkg"
parisc: drivers: fix warnings
parisc: select BUG always
parisc: asm/pdc.h should include asm/page.h
parisc: led: remove proc_dir_entry::owner
parisc: fix macro expansion in atomic.h
parisc: iosapic: fix build breakage
parisc: oops_enter()/oops_exit() in die()
parisc: document light weight syscall ABI
parisc: blink all or loadavg LEDs on oops
parisc: add ftrace (function and graph tracer) functionality
parisc: simplify sys_clone()
parisc: add LATENCYTOP_SUPPORT and CONFIG_STACKTRACE_SUPPORT
parisc: allow to build with 16k default kernel page size
parisc: expose 32/64-bit capabilities in cpuinfo
parisc: use constants instead of numbers in assembly
parisc: fix usage of 32bit PTE page table entries on 32bit kernels
...
Diffstat (limited to 'arch/parisc/kernel')
-rw-r--r-- | arch/parisc/kernel/Makefile | 15 | ||||
-rw-r--r-- | arch/parisc/kernel/entry.S | 60 | ||||
-rw-r--r-- | arch/parisc/kernel/firmware.c | 6 | ||||
-rw-r--r-- | arch/parisc/kernel/ftrace.c | 185 | ||||
-rw-r--r-- | arch/parisc/kernel/irq.c | 4 | ||||
-rw-r--r-- | arch/parisc/kernel/module.c | 18 | ||||
-rw-r--r-- | arch/parisc/kernel/parisc_ksyms.c | 5 | ||||
-rw-r--r-- | arch/parisc/kernel/process.c | 29 | ||||
-rw-r--r-- | arch/parisc/kernel/processor.c | 13 | ||||
-rw-r--r-- | arch/parisc/kernel/smp.c | 21 | ||||
-rw-r--r-- | arch/parisc/kernel/stacktrace.c | 63 | ||||
-rw-r--r-- | arch/parisc/kernel/syscall.S | 58 | ||||
-rw-r--r-- | arch/parisc/kernel/time.c | 3 | ||||
-rw-r--r-- | arch/parisc/kernel/traps.c | 5 | ||||
-rw-r--r-- | arch/parisc/kernel/vmlinux.lds.S | 2 |
15 files changed, 416 insertions, 71 deletions
diff --git a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile index 016d3fc4111c..67db0722e6ca 100644 --- a/arch/parisc/kernel/Makefile +++ b/arch/parisc/kernel/Makefile @@ -11,10 +11,25 @@ obj-y := cache.o pacache.o setup.o traps.o time.o irq.o \ process.o processor.o pdc_cons.o pdc_chassis.o unwind.o \ topology.o +ifdef CONFIG_FUNCTION_TRACER +# Do not profile debug and lowlevel utilities +CFLAGS_REMOVE_ftrace.o = -pg +CFLAGS_REMOVE_cache.o = -pg +CFLAGS_REMOVE_irq.o = -pg +CFLAGS_REMOVE_pacache.o = -pg +CFLAGS_REMOVE_perf.o = -pg +CFLAGS_REMOVE_traps.o = -pg +CFLAGS_REMOVE_unaligned.o = -pg +CFLAGS_REMOVE_unwind.o = -pg +endif + obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_PA11) += pci-dma.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_64BIT) += binfmt_elf32.o sys_parisc32.o signal32.o +obj-$(CONFIG_STACKTRACE)+= stacktrace.o # only supported for PCX-W/U in 64-bit mode at the moment obj-$(CONFIG_64BIT) += perf.o perf_asm.o +obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o +obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 0db9fdcb7709..ae3e70cd1e14 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -505,6 +505,18 @@ STREG \pte,0(\ptep) .endm + /* bitshift difference between a PFN (based on kernel's PAGE_SIZE) + * to a CPU TLB 4k PFN (4k => 12 bits to shift) */ + #define PAGE_ADD_SHIFT (PAGE_SHIFT-12) + + /* Drop prot bits and convert to page addr for iitlbt and idtlbt */ + .macro convert_for_tlb_insert20 pte + extrd,u \pte,(63-ASM_PFN_PTE_SHIFT)+(63-58)+PAGE_ADD_SHIFT,\ + 64-PAGE_SHIFT-PAGE_ADD_SHIFT,\pte + depdi _PAGE_SIZE_ENCODING_DEFAULT,63,\ + (63-58)+PAGE_ADD_SHIFT,\pte + .endm + /* Convert the pte and prot to tlb insertion values. How * this happens is quite subtle, read below */ .macro make_insert_tlb spc,pte,prot @@ -544,8 +556,7 @@ depi 1,12,1,\prot /* Drop prot bits and convert to page addr for iitlbt and idtlbt */ - extrd,u \pte,(63-ASM_PFN_PTE_SHIFT)+(63-58),64-PAGE_SHIFT,\pte - depdi _PAGE_SIZE_ENCODING_DEFAULT,63,63-58,\pte + convert_for_tlb_insert20 \pte .endm /* Identical macro to make_insert_tlb above, except it @@ -563,8 +574,8 @@ /* Get rid of prot bits and convert to page addr for iitlba */ - depi _PAGE_SIZE_ENCODING_DEFAULT,31,ASM_PFN_PTE_SHIFT,\pte - extru \pte,24,25,\pte + depi 0,31,ASM_PFN_PTE_SHIFT,\pte + SHRREG \pte,(ASM_PFN_PTE_SHIFT-(31-26)),\pte .endm /* This is for ILP32 PA2.0 only. The TLB insertion needs @@ -1244,10 +1255,9 @@ nadtlb_check_flush_20w: depdi,z 7,7,3,prot depdi 1,10,1,prot - /* Get rid of prot bits and convert to page addr for idtlbt */ + /* Drop prot bits from pte and convert to page addr for idtlbt */ + convert_for_tlb_insert20 pte - depdi 0,63,12,pte - extrd,u pte,56,52,pte idtlbt pte,prot rfir @@ -1337,8 +1347,8 @@ nadtlb_check_flush_11: /* Get rid of prot bits and convert to page addr for idtlba */ - depi 0,31,12,pte - extru pte,24,25,pte + depi 0,31,ASM_PFN_PTE_SHIFT,pte + SHRREG pte,(ASM_PFN_PTE_SHIFT-(31-26)),pte mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */ mtsp spc,%sr1 @@ -1403,10 +1413,9 @@ nadtlb_check_flush_20: depdi,z 7,7,3,prot depdi 1,10,1,prot - /* Get rid of prot bits and convert to page addr for idtlbt */ + /* Drop prot bits from pte and convert to page addr for idtlbt */ + convert_for_tlb_insert20 pte - depdi 0,63,12,pte - extrd,u pte,56,32,pte idtlbt pte,prot rfir @@ -2176,6 +2185,33 @@ syscall_do_resched: ENDPROC(syscall_exit) +#ifdef CONFIG_FUNCTION_TRACER + .import ftrace_function_trampoline,code +ENTRY(_mcount) + copy %r3, %arg2 + b ftrace_function_trampoline + nop +ENDPROC(_mcount) + +ENTRY(return_to_handler) + load32 return_trampoline, %rp + copy %ret0, %arg0 + copy %ret1, %arg1 + b ftrace_return_to_handler + nop +return_trampoline: + copy %ret0, %rp + copy %r23, %ret0 + copy %r24, %ret1 + +.globl ftrace_stub +ftrace_stub: + bv %r0(%rp) + nop +ENDPROC(return_to_handler) +#endif /* CONFIG_FUNCTION_TRACER */ + + get_register: /* * get_register is used by the non access tlb miss handlers to diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index f6d241238a78..4c247e02d9b1 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -527,7 +527,11 @@ int pdc_model_capabilities(unsigned long *capabilities) pdc_result[0] = 0; /* preset zero (call may not be implemented!) */ retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES, __pa(pdc_result), 0); convert_to_wide(pdc_result); - *capabilities = pdc_result[0]; + if (retval == PDC_OK) { + *capabilities = pdc_result[0]; + } else { + *capabilities = PDC_MODEL_OS32; + } spin_unlock_irqrestore(&pdc_lock, flags); return retval; diff --git a/arch/parisc/kernel/ftrace.c b/arch/parisc/kernel/ftrace.c new file mode 100644 index 000000000000..9877372ffdba --- /dev/null +++ b/arch/parisc/kernel/ftrace.c @@ -0,0 +1,185 @@ +/* + * Code for tracing calls in Linux kernel. + * Copyright (C) 2009 Helge Deller <deller@gmx.de> + * + * based on code for x86 which is: + * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com> + * + * future possible enhancements: + * - add CONFIG_DYNAMIC_FTRACE + * - add CONFIG_STACK_TRACER + */ + +#include <linux/init.h> +#include <linux/ftrace.h> + +#include <asm/sections.h> +#include <asm/ftrace.h> + + + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + +/* Add a function return address to the trace stack on thread info.*/ +static int push_return_trace(unsigned long ret, unsigned long long time, + unsigned long func, int *depth) +{ + int index; + + if (!current->ret_stack) + return -EBUSY; + + /* The return trace stack is full */ + if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) { + atomic_inc(¤t->trace_overrun); + return -EBUSY; + } + + index = ++current->curr_ret_stack; + barrier(); + current->ret_stack[index].ret = ret; + current->ret_stack[index].func = func; + current->ret_stack[index].calltime = time; + *depth = index; + + return 0; +} + +/* Retrieve a function return address to the trace stack on thread info.*/ +static void pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret) +{ + int index; + + index = current->curr_ret_stack; + + if (unlikely(index < 0)) { + ftrace_graph_stop(); + WARN_ON(1); + /* Might as well panic, otherwise we have no where to go */ + *ret = (unsigned long) + dereference_function_descriptor(&panic); + return; + } + + *ret = current->ret_stack[index].ret; + trace->func = current->ret_stack[index].func; + trace->calltime = current->ret_stack[index].calltime; + trace->overrun = atomic_read(¤t->trace_overrun); + trace->depth = index; + barrier(); + current->curr_ret_stack--; + +} + +/* + * Send the trace to the ring-buffer. + * @return the original return address. + */ +unsigned long ftrace_return_to_handler(unsigned long retval0, + unsigned long retval1) +{ + struct ftrace_graph_ret trace; + unsigned long ret; + + pop_return_trace(&trace, &ret); + trace.rettime = cpu_clock(raw_smp_processor_id()); + ftrace_graph_return(&trace); + + if (unlikely(!ret)) { + ftrace_graph_stop(); + WARN_ON(1); + /* Might as well panic. What else to do? */ + ret = (unsigned long) + dereference_function_descriptor(&panic); + } + + /* HACK: we hand over the old functions' return values + in %r23 and %r24. Assembly in entry.S will take care + and move those to their final registers %ret0 and %ret1 */ + asm( "copy %0, %%r23 \n\t" + "copy %1, %%r24 \n" : : "r" (retval0), "r" (retval1) ); + + return ret; +} + +/* + * 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; + struct ftrace_graph_ent trace; + + if (unlikely(atomic_read(¤t->tracing_graph_pause))) + return; + + old = *parent; + *parent = (unsigned long) + dereference_function_descriptor(&return_to_handler); + + if (unlikely(!__kernel_text_address(old))) { + ftrace_graph_stop(); + *parent = old; + WARN_ON(1); + return; + } + + calltime = cpu_clock(raw_smp_processor_id()); + + if (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 */ + + +void ftrace_function_trampoline(unsigned long parent, + unsigned long self_addr, + unsigned long org_sp_gr3) +{ + extern ftrace_func_t ftrace_trace_function; + + if (function_trace_stop) + return; + + if (ftrace_trace_function != ftrace_stub) { + ftrace_trace_function(parent, self_addr); + return; + } +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + if (ftrace_graph_entry && ftrace_graph_return) { + unsigned long sp; + unsigned long *parent_rp; + + asm volatile ("copy %%r30, %0" : "=r"(sp)); + /* sanity check: is stack pointer which we got from + assembler function in entry.S in a reasonable + range compared to current stack pointer? */ + if ((sp - org_sp_gr3) > 0x400) + return; + + /* calculate pointer to %rp in stack */ + parent_rp = (unsigned long *) org_sp_gr3 - 0x10; + /* sanity check: parent_rp should hold parent */ + if (*parent_rp != parent) + return; + + prepare_ftrace_return(parent_rp, self_addr); + return; + } +#endif +} + diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 1c740f5cbd63..4ea4229d765c 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -311,12 +311,12 @@ unsigned long txn_alloc_addr(unsigned int virt_irq) next_cpu++; /* assign to "next" CPU we want this bugger on */ /* validate entry */ - while ((next_cpu < NR_CPUS) && + while ((next_cpu < nr_cpu_ids) && (!per_cpu(cpu_data, next_cpu).txn_addr || !cpu_online(next_cpu))) next_cpu++; - if (next_cpu >= NR_CPUS) + if (next_cpu >= nr_cpu_ids) next_cpu = 0; /* nothing else, assign monarch */ return txn_affinity_addr(virt_irq, next_cpu); diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c index 9013243cecca..ecd1c5024447 100644 --- a/arch/parisc/kernel/module.c +++ b/arch/parisc/kernel/module.c @@ -61,9 +61,7 @@ #include <linux/string.h> #include <linux/kernel.h> #include <linux/bug.h> -#include <linux/uaccess.h> -#include <asm/sections.h> #include <asm/unwind.h> #if 0 @@ -115,8 +113,6 @@ struct got_entry { Elf32_Addr addr; }; -#define Elf_Fdesc Elf32_Fdesc - struct stub_entry { Elf32_Word insns[2]; /* each stub entry has two insns */ }; @@ -125,8 +121,6 @@ struct got_entry { Elf64_Addr addr; }; -#define Elf_Fdesc Elf64_Fdesc - struct stub_entry { Elf64_Word insns[4]; /* each stub entry has four insns */ }; @@ -916,15 +910,3 @@ void module_arch_cleanup(struct module *mod) deregister_unwind_table(mod); module_bug_cleanup(mod); } - -#ifdef CONFIG_64BIT -void *dereference_function_descriptor(void *ptr) -{ - Elf64_Fdesc *desc = ptr; - void *p; - - if (!probe_kernel_address(&desc->addr, p)) - ptr = p; - return ptr; -} -#endif diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c index 0eecfbbc59cd..df653663d3db 100644 --- a/arch/parisc/kernel/parisc_ksyms.c +++ b/arch/parisc/kernel/parisc_ksyms.c @@ -153,5 +153,10 @@ EXPORT_SYMBOL(node_data); EXPORT_SYMBOL(pfnnid_map); #endif +#ifdef CONFIG_FUNCTION_TRACER +extern void _mcount(void); +EXPORT_SYMBOL(_mcount); +#endif + /* from pacache.S -- needed for copy_page */ EXPORT_SYMBOL(copy_user_page_asm); diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 8aa591ed9127..6f69101f90bb 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -46,14 +46,15 @@ #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/kallsyms.h> +#include <linux/uaccess.h> #include <asm/io.h> #include <asm/asm-offsets.h> #include <asm/pdc.h> #include <asm/pdc_chassis.h> #include <asm/pgalloc.h> -#include <asm/uaccess.h> #include <asm/unwind.h> +#include <asm/sections.h> /* * The idle thread. There's no useful work to be @@ -231,8 +232,8 @@ sys_clone(unsigned long clone_flags, unsigned long usp, However, these last 3 args are only examined if the proper flags are set. */ - int __user *child_tidptr; - int __user *parent_tidptr; + int __user *parent_tidptr = (int __user *)regs->gr[24]; + int __user *child_tidptr = (int __user *)regs->gr[22]; /* usp must be word aligned. This also prevents users from * passing in the value 1 (which is the signal for a special @@ -243,16 +244,6 @@ sys_clone(unsigned long clone_flags, unsigned long usp, if (usp == 0) usp = regs->gr[30]; - if (clone_flags & CLONE_PARENT_SETTID) - parent_tidptr = (int __user *)regs->gr[24]; - else - parent_tidptr = NULL; - - if (clone_flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) - child_tidptr = (int __user *)regs->gr[22]; - else - child_tidptr = NULL; - return do_fork(clone_flags, usp, regs, 0, parent_tidptr, child_tidptr); } @@ -400,3 +391,15 @@ get_wchan(struct task_struct *p) } while (count++ < 16); return 0; } + +#ifdef CONFIG_64BIT +void *dereference_function_descriptor(void *ptr) +{ + Elf64_Fdesc *desc = ptr; + void *p; + + if (!probe_kernel_address(&desc->addr, p)) + ptr = p; + return ptr; +} +#endif diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c index ecb609342feb..e09d0f7fb6b0 100644 --- a/arch/parisc/kernel/processor.c +++ b/arch/parisc/kernel/processor.c @@ -100,8 +100,8 @@ static int __cpuinit processor_probe(struct parisc_device *dev) struct cpuinfo_parisc *p; #ifdef CONFIG_SMP - if (num_online_cpus() >= NR_CPUS) { - printk(KERN_INFO "num_online_cpus() >= NR_CPUS\n"); + if (num_online_cpus() >= nr_cpu_ids) { + printk(KERN_INFO "num_online_cpus() >= nr_cpu_ids\n"); return 1; } #else @@ -214,7 +214,7 @@ static int __cpuinit processor_probe(struct parisc_device *dev) */ #ifdef CONFIG_SMP if (cpuid) { - cpu_set(cpuid, cpu_present_map); + set_cpu_present(cpuid, true); cpu_up(cpuid); } #endif @@ -364,6 +364,13 @@ show_cpuinfo (struct seq_file *m, void *v) boot_cpu_data.cpu_hz / 1000000, boot_cpu_data.cpu_hz % 1000000 ); + seq_printf(m, "capabilities\t:"); + if (boot_cpu_data.pdc.capabilities & PDC_MODEL_OS32) + seq_printf(m, " os32"); + if (boot_cpu_data.pdc.capabilities & PDC_MODEL_OS64) + seq_printf(m, " os64"); + seq_printf(m, "\n"); + seq_printf(m, "model\t\t: %s\n" "model name\t: %s\n", boot_cpu_data.pdc.sys_model_name, diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index 9995d7ed5819..1fd0f0cec037 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -31,6 +31,7 @@ #include <linux/err.h> #include <linux/delay.h> #include <linux/bitops.h> +#include <linux/ftrace.h> #include <asm/system.h> #include <asm/atomic.h> @@ -113,14 +114,14 @@ halt_processor(void) { /* REVISIT : redirect I/O Interrupts to another CPU? */ /* REVISIT : does PM *know* this CPU isn't available? */ - cpu_clear(smp_processor_id(), cpu_online_map); + set_cpu_online(smp_processor_id(), false); local_irq_disable(); for (;;) ; } -irqreturn_t +irqreturn_t __irq_entry ipi_interrupt(int irq, void *dev_id) { int this_cpu = smp_processor_id(); @@ -214,11 +215,11 @@ ipi_send(int cpu, enum ipi_message_type op) } static void -send_IPI_mask(cpumask_t mask, enum ipi_message_type op) +send_IPI_mask(const struct cpumask *mask, enum ipi_message_type op) { int cpu; - for_each_cpu_mask(cpu, mask) + for_each_cpu(cpu, mask) ipi_send(cpu, op); } @@ -257,7 +258,7 @@ smp_send_all_nop(void) send_IPI_allbutself(IPI_NOP); } -void arch_send_call_function_ipi(cpumask_t mask) +void arch_send_call_function_ipi_mask(const struct cpumask *mask) { send_IPI_mask(mask, IPI_CALL_FUNC); } @@ -296,13 +297,14 @@ smp_cpu_init(int cpunum) mb(); /* Well, support 2.4 linux scheme as well. */ - if (cpu_test_and_set(cpunum, cpu_online_map)) + if (cpu_isset(cpunum, cpu_online_map)) { extern void machine_halt(void); /* arch/parisc.../process.c */ printk(KERN_CRIT "CPU#%d already initialized!\n", cpunum); machine_halt(); } + set_cpu_online(cpunum, true); /* Initialise the idle task for this CPU */ atomic_inc(&init_mm.mm_count); @@ -424,8 +426,8 @@ void __init smp_prepare_boot_cpu(void) /* Setup BSP mappings */ printk(KERN_INFO "SMP: bootstrap CPU ID is %d\n", bootstrap_processor); - cpu_set(bootstrap_processor, cpu_online_map); - cpu_set(bootstrap_processor, cpu_present_map); + set_cpu_online(bootstrap_processor, true); + set_cpu_present(bootstrap_processor, true); } @@ -436,8 +438,7 @@ void __init smp_prepare_boot_cpu(void) */ void __init smp_prepare_cpus(unsigned int max_cpus) { - cpus_clear(cpu_present_map); - cpu_set(0, cpu_present_map); + init_cpu_present(cpumask_of(0)); parisc_max_cpus = max_cpus; if (!max_cpus) diff --git a/arch/parisc/kernel/stacktrace.c b/arch/parisc/kernel/stacktrace.c new file mode 100644 index 000000000000..2fe914c5f533 --- /dev/null +++ b/arch/parisc/kernel/stacktrace.c @@ -0,0 +1,63 @@ +/* + * Stack trace management functions + * + * Copyright (C) 2009 Helge Deller <deller@gmx.de> + * based on arch/x86/kernel/stacktrace.c by Ingo Molnar <mingo@redhat.com> + * and parisc unwind functions by Randolph Chung <tausq@debian.org> + * + * TODO: Userspace stacktrace (CONFIG_USER_STACKTRACE_SUPPORT) + */ +#include <linux/module.h> +#include <linux/stacktrace.h> + +#include <asm/unwind.h> + +static void dump_trace(struct task_struct *task, struct stack_trace *trace) +{ + struct unwind_frame_info info; + + /* initialize unwind info */ + if (task == current) { + unsigned long sp; + struct pt_regs r; +HERE: + asm volatile ("copy %%r30, %0" : "=r"(sp)); + memset(&r, 0, sizeof(struct pt_regs)); + r.iaoq[0] = (unsigned long)&&HERE; + r.gr[2] = (unsigned long)__builtin_return_address(0); + r.gr[30] = sp; + unwind_frame_init(&info, task, &r); + } else { + unwind_frame_init_from_blocked_task(&info, task); + } + + /* unwind stack and save entries in stack_trace struct */ + trace->nr_entries = 0; + while (trace->nr_entries < trace->max_entries) { + if (unwind_once(&info) < 0 || info.ip == 0) + break; + + if (__kernel_text_address(info.ip)) + trace->entries[trace->nr_entries++] = info.ip; + } +} + + +/* + * Save stack-backtrace addresses into a stack_trace buffer. + */ +void save_stack_trace(struct stack_trace *trace) +{ + dump_trace(current, trace); + if (trace->nr_entries < trace->max_entries) + trace->entries[trace->nr_entries++] = ULONG_MAX; +} +EXPORT_SYMBOL_GPL(save_stack_trace); + +void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +{ + dump_trace(tsk, trace); + if (trace->nr_entries < trace->max_entries) + trace->entries[trace->nr_entries++] = ULONG_MAX; +} +EXPORT_SYMBOL_GPL(save_stack_trace_tsk); diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index 69b6eebc466e..59fc1a43ec3e 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -365,17 +365,51 @@ tracesys_sigexit: /********************************************************* - Light-weight-syscall code + 32/64-bit Light-Weight-Syscall ABI - r20 - lws number - r26,r25,r24,r23,r22 - Input registers - r28 - Function return register - r21 - Error code. + * - Indicates a hint for userspace inline asm + implementations. - Scracth: Any of the above that aren't being - currently used, including r1. + Syscall number (caller-saves) + - %r20 + * In asm clobber. - Return pointer: r31 (Not usable) + Argument registers (caller-saves) + - %r26, %r25, %r24, %r23, %r22 + * In asm input. + + Return registers (caller-saves) + - %r28 (return), %r21 (errno) + * In asm output. + + Caller-saves registers + - %r1, %r27, %r29 + - %r2 (return pointer) + - %r31 (ble link register) + * In asm clobber. + + Callee-saves registers + - %r3-%r18 + - %r30 (stack pointer) + * Not in asm clobber. + + If userspace is 32-bit: + Callee-saves registers + - %r19 (32-bit PIC register) + + Differences from 32-bit calling convention: + - Syscall number in %r20 + - Additional argument register %r22 (arg4) + - Callee-saves %r19. + + If userspace is 64-bit: + Callee-saves registers + - %r27 (64-bit PIC register) + + Differences from 64-bit calling convention: + - Syscall number in %r20 + - Additional argument register %r22 (arg4) + - Callee-saves %r27. Error codes returned by entry path: @@ -473,7 +507,8 @@ lws_compare_and_swap64: b,n lws_compare_and_swap #else /* If we are not a 64-bit kernel, then we don't - * implement having 64-bit input registers + * have 64-bit input registers, and calling + * the 64-bit LWS CAS returns ENOSYS. */ b,n lws_exit_nosys #endif @@ -635,12 +670,15 @@ END(sys_call_table64) /* All light-weight-syscall atomic operations will use this set of locks + + NOTE: The lws_lock_start symbol must be + at least 16-byte aligned for safe use + with ldcw. */ .section .data .align PAGE_SIZE ENTRY(lws_lock_start) /* lws locks */ - .align 16 .rept 16 /* Keep locks aligned at 16-bytes */ .word 1 diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 86a99d02234f..d4dd05674c62 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -24,6 +24,7 @@ #include <linux/profile.h> #include <linux/clocksource.h> #include <linux/platform_device.h> +#include <linux/ftrace.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -53,7 +54,7 @@ static unsigned long clocktick __read_mostly; /* timer cycles per tick */ * held off for an arbitrarily long period of time by interrupts being * disabled, so we may miss one or more ticks. */ -irqreturn_t timer_interrupt(int irq, void *dev_id) +irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id) { unsigned long now; unsigned long next_tick; diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index ba658d2086f7..c32f5d6d778e 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -247,6 +247,8 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) oops_in_progress = 1; + oops_enter(); + /* Amuse the user in a SPARC fashion */ if (err) printk( KERN_CRIT " _______________________________ \n" @@ -293,6 +295,7 @@ KERN_CRIT " || ||\n"); panic("Fatal exception"); } + oops_exit(); do_exit(SIGSEGV); } @@ -494,7 +497,7 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o panic(msg); } -void handle_interruption(int code, struct pt_regs *regs) +void notrace handle_interruption(int code, struct pt_regs *regs) { unsigned long fault_address = 0; unsigned long fault_space = 0; diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index 1a3b6ccd3620..fd2cc4fd2b65 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -54,6 +54,8 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT + KPROBES_TEXT + IRQENTRY_TEXT *(.text.do_softirq) *(.text.sys_exit) *(.text.do_sigaltstack) |