Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6: sparc64: Add some more commentary to __raw_local_irq_save() sparc64: Fix memory leak in pci_register_iommu_region(). sparc64: Add kmemleak annotation to sun4v_build_virq() sparc64: Support kmemleak. sparc64: Add function graph tracer support. sparc64: Give a stack frame to the ftrace call sites. sparc64: Use a seperate counter for timer interrupts and NMI checks, like x86. sparc64: Remove profiling from some low-level bits. sparc64: Kill unnecessary static on local var in ftrace_call_replace(). sparc64: Kill CONFIG_STACK_DEBUG code. sparc64: Add HAVE_FUNCTION_TRACE_MCOUNT_TEST and tidy up. sparc64: Adjust __raw_local_irq_save() to cooperate in NMIs. sparc64: Use kstack_valid() in die_if_kernel().
This commit is contained in:
@ -37,6 +37,9 @@ config SPARC64
|
|||||||
def_bool 64BIT
|
def_bool 64BIT
|
||||||
select ARCH_SUPPORTS_MSI
|
select ARCH_SUPPORTS_MSI
|
||||||
select HAVE_FUNCTION_TRACER
|
select HAVE_FUNCTION_TRACER
|
||||||
|
select HAVE_FUNCTION_GRAPH_TRACER
|
||||||
|
select HAVE_FUNCTION_GRAPH_FP_TEST
|
||||||
|
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
|
||||||
select HAVE_KRETPROBES
|
select HAVE_KRETPROBES
|
||||||
select HAVE_KPROBES
|
select HAVE_KPROBES
|
||||||
select HAVE_LMB
|
select HAVE_LMB
|
||||||
|
@ -19,13 +19,10 @@ config DEBUG_DCFLUSH
|
|||||||
bool "D-cache flush debugging"
|
bool "D-cache flush debugging"
|
||||||
depends on SPARC64 && DEBUG_KERNEL
|
depends on SPARC64 && DEBUG_KERNEL
|
||||||
|
|
||||||
config STACK_DEBUG
|
|
||||||
bool "Stack Overflow Detection Support"
|
|
||||||
|
|
||||||
config MCOUNT
|
config MCOUNT
|
||||||
bool
|
bool
|
||||||
depends on SPARC64
|
depends on SPARC64
|
||||||
depends on STACK_DEBUG || FUNCTION_TRACER
|
depends on FUNCTION_TRACER
|
||||||
default y
|
default y
|
||||||
|
|
||||||
config FRAME_POINTER
|
config FRAME_POINTER
|
||||||
|
@ -17,7 +17,7 @@ typedef struct {
|
|||||||
unsigned int __nmi_count;
|
unsigned int __nmi_count;
|
||||||
unsigned long clock_tick; /* %tick's per second */
|
unsigned long clock_tick; /* %tick's per second */
|
||||||
unsigned long __pad;
|
unsigned long __pad;
|
||||||
unsigned int __pad1;
|
unsigned int irq0_irqs;
|
||||||
unsigned int __pad2;
|
unsigned int __pad2;
|
||||||
|
|
||||||
/* Dcache line 2, rarely used */
|
/* Dcache line 2, rarely used */
|
||||||
|
@ -76,9 +76,26 @@ static inline int raw_irqs_disabled(void)
|
|||||||
*/
|
*/
|
||||||
static inline unsigned long __raw_local_irq_save(void)
|
static inline unsigned long __raw_local_irq_save(void)
|
||||||
{
|
{
|
||||||
unsigned long flags = __raw_local_save_flags();
|
unsigned long flags, tmp;
|
||||||
|
|
||||||
raw_local_irq_disable();
|
/* Disable interrupts to PIL_NORMAL_MAX unless we already
|
||||||
|
* are using PIL_NMI, in which case PIL_NMI is retained.
|
||||||
|
*
|
||||||
|
* The only values we ever program into the %pil are 0,
|
||||||
|
* PIL_NORMAL_MAX and PIL_NMI.
|
||||||
|
*
|
||||||
|
* Since PIL_NMI is the largest %pil value and all bits are
|
||||||
|
* set in it (0xf), it doesn't matter what PIL_NORMAL_MAX
|
||||||
|
* actually is.
|
||||||
|
*/
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"rdpr %%pil, %0\n\t"
|
||||||
|
"or %0, %2, %1\n\t"
|
||||||
|
"wrpr %1, 0x0, %%pil"
|
||||||
|
: "=r" (flags), "=r" (tmp)
|
||||||
|
: "i" (PIL_NORMAL_MAX)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,14 @@ extra-y += init_task.o
|
|||||||
CPPFLAGS_vmlinux.lds := -Usparc -m$(BITS)
|
CPPFLAGS_vmlinux.lds := -Usparc -m$(BITS)
|
||||||
extra-y += vmlinux.lds
|
extra-y += vmlinux.lds
|
||||||
|
|
||||||
|
ifdef CONFIG_FUNCTION_TRACER
|
||||||
|
# Do not profile debug and lowlevel utilities
|
||||||
|
CFLAGS_REMOVE_ftrace.o := -pg
|
||||||
|
CFLAGS_REMOVE_time_$(BITS).o := -pg
|
||||||
|
CFLAGS_REMOVE_perf_event.o := -pg
|
||||||
|
CFLAGS_REMOVE_pcr.o := -pg
|
||||||
|
endif
|
||||||
|
|
||||||
obj-$(CONFIG_SPARC32) += entry.o wof.o wuf.o
|
obj-$(CONFIG_SPARC32) += entry.o wof.o wuf.o
|
||||||
obj-$(CONFIG_SPARC32) += etrap_32.o
|
obj-$(CONFIG_SPARC32) += etrap_32.o
|
||||||
obj-$(CONFIG_SPARC32) += rtrap_32.o
|
obj-$(CONFIG_SPARC32) += rtrap_32.o
|
||||||
@ -85,7 +93,7 @@ obj-$(CONFIG_KGDB) += kgdb_$(BITS).o
|
|||||||
|
|
||||||
|
|
||||||
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
|
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
|
||||||
CFLAGS_REMOVE_ftrace.o := -pg
|
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
|
||||||
|
|
||||||
obj-$(CONFIG_EARLYFB) += btext.o
|
obj-$(CONFIG_EARLYFB) += btext.o
|
||||||
obj-$(CONFIG_STACKTRACE) += stacktrace.o
|
obj-$(CONFIG_STACKTRACE) += stacktrace.o
|
||||||
|
@ -13,7 +13,7 @@ static const u32 ftrace_nop = 0x01000000;
|
|||||||
|
|
||||||
static u32 ftrace_call_replace(unsigned long ip, unsigned long addr)
|
static u32 ftrace_call_replace(unsigned long ip, unsigned long addr)
|
||||||
{
|
{
|
||||||
static u32 call;
|
u32 call;
|
||||||
s32 off;
|
s32 off;
|
||||||
|
|
||||||
off = ((s32)addr - (s32)ip);
|
off = ((s32)addr - (s32)ip);
|
||||||
@ -91,3 +91,61 @@ int __init ftrace_dyn_arch_init(void *data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||||
|
|
||||||
|
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||||
|
extern void ftrace_graph_call(void);
|
||||||
|
|
||||||
|
int ftrace_enable_ftrace_graph_caller(void)
|
||||||
|
{
|
||||||
|
unsigned long ip = (unsigned long)(&ftrace_graph_call);
|
||||||
|
u32 old, new;
|
||||||
|
|
||||||
|
old = *(u32 *) &ftrace_graph_call;
|
||||||
|
new = ftrace_call_replace(ip, (unsigned long) &ftrace_graph_caller);
|
||||||
|
return ftrace_modify_code(ip, old, new);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ftrace_disable_ftrace_graph_caller(void)
|
||||||
|
{
|
||||||
|
unsigned long ip = (unsigned long)(&ftrace_graph_call);
|
||||||
|
u32 old, new;
|
||||||
|
|
||||||
|
old = *(u32 *) &ftrace_graph_call;
|
||||||
|
new = ftrace_call_replace(ip, (unsigned long) &ftrace_stub);
|
||||||
|
|
||||||
|
return ftrace_modify_code(ip, old, new);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !CONFIG_DYNAMIC_FTRACE */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hook the return address and push it in the stack of return addrs
|
||||||
|
* in current thread info.
|
||||||
|
*/
|
||||||
|
unsigned long prepare_ftrace_return(unsigned long parent,
|
||||||
|
unsigned long self_addr,
|
||||||
|
unsigned long frame_pointer)
|
||||||
|
{
|
||||||
|
unsigned long return_hooker = (unsigned long) &return_to_handler;
|
||||||
|
struct ftrace_graph_ent trace;
|
||||||
|
|
||||||
|
if (unlikely(atomic_read(¤t->tracing_graph_pause)))
|
||||||
|
return parent + 8UL;
|
||||||
|
|
||||||
|
if (ftrace_push_return_trace(parent, self_addr, &trace.depth,
|
||||||
|
frame_pointer) == -EBUSY)
|
||||||
|
return parent + 8UL;
|
||||||
|
|
||||||
|
trace.func = self_addr;
|
||||||
|
|
||||||
|
/* Only trace if the calling function expects to */
|
||||||
|
if (!ftrace_graph_entry(&trace)) {
|
||||||
|
current->curr_ret_stack--;
|
||||||
|
return parent + 8UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return return_hooker;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/proc_fs.h>
|
#include <linux/proc_fs.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
|
#include <linux/ftrace.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
|
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
@ -647,6 +648,14 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
|
|||||||
bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC);
|
bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC);
|
||||||
if (unlikely(!bucket))
|
if (unlikely(!bucket))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* The only reference we store to the IRQ bucket is
|
||||||
|
* by physical address which kmemleak can't see, tell
|
||||||
|
* it that this object explicitly is not a leak and
|
||||||
|
* should be scanned.
|
||||||
|
*/
|
||||||
|
kmemleak_not_leak(bucket);
|
||||||
|
|
||||||
__flush_dcache_range((unsigned long) bucket,
|
__flush_dcache_range((unsigned long) bucket,
|
||||||
((unsigned long) bucket +
|
((unsigned long) bucket +
|
||||||
sizeof(struct ino_bucket)));
|
sizeof(struct ino_bucket)));
|
||||||
@ -721,7 +730,7 @@ static __attribute__((always_inline)) void restore_hardirq_stack(void *orig_sp)
|
|||||||
__asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp));
|
__asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp));
|
||||||
}
|
}
|
||||||
|
|
||||||
void handler_irq(int irq, struct pt_regs *regs)
|
void __irq_entry handler_irq(int irq, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
unsigned long pstate, bucket_pa;
|
unsigned long pstate, bucket_pa;
|
||||||
struct pt_regs *old_regs;
|
struct pt_regs *old_regs;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <linux/kgdb.h>
|
#include <linux/kgdb.h>
|
||||||
#include <linux/kdebug.h>
|
#include <linux/kdebug.h>
|
||||||
|
#include <linux/ftrace.h>
|
||||||
|
|
||||||
#include <asm/kdebug.h>
|
#include <asm/kdebug.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
@ -108,7 +109,7 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
void smp_kgdb_capture_client(int irq, struct pt_regs *regs)
|
void __irq_entry smp_kgdb_capture_client(int irq, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
@ -92,7 +92,6 @@ static void die_nmi(const char *str, struct pt_regs *regs, int do_panic)
|
|||||||
notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs)
|
notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
unsigned int sum, touched = 0;
|
unsigned int sum, touched = 0;
|
||||||
int cpu = smp_processor_id();
|
|
||||||
|
|
||||||
clear_softint(1 << irq);
|
clear_softint(1 << irq);
|
||||||
|
|
||||||
@ -106,7 +105,7 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs)
|
|||||||
else
|
else
|
||||||
pcr_ops->write(PCR_PIC_PRIV);
|
pcr_ops->write(PCR_PIC_PRIV);
|
||||||
|
|
||||||
sum = kstat_irqs_cpu(0, cpu);
|
sum = local_cpu_data().irq0_irqs;
|
||||||
if (__get_cpu_var(nmi_touch)) {
|
if (__get_cpu_var(nmi_touch)) {
|
||||||
__get_cpu_var(nmi_touch) = 0;
|
__get_cpu_var(nmi_touch) = 0;
|
||||||
touched = 1;
|
touched = 1;
|
||||||
|
@ -371,14 +371,19 @@ static void pci_register_iommu_region(struct pci_pbm_info *pbm)
|
|||||||
struct resource *rp = kzalloc(sizeof(*rp), GFP_KERNEL);
|
struct resource *rp = kzalloc(sizeof(*rp), GFP_KERNEL);
|
||||||
|
|
||||||
if (!rp) {
|
if (!rp) {
|
||||||
prom_printf("Cannot allocate IOMMU resource.\n");
|
pr_info("%s: Cannot allocate IOMMU resource.\n",
|
||||||
prom_halt();
|
pbm->name);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
rp->name = "IOMMU";
|
rp->name = "IOMMU";
|
||||||
rp->start = pbm->mem_space.start + (unsigned long) vdma[0];
|
rp->start = pbm->mem_space.start + (unsigned long) vdma[0];
|
||||||
rp->end = rp->start + (unsigned long) vdma[1] - 1UL;
|
rp->end = rp->start + (unsigned long) vdma[1] - 1UL;
|
||||||
rp->flags = IORESOURCE_BUSY;
|
rp->flags = IORESOURCE_BUSY;
|
||||||
request_resource(&pbm->mem_space, rp);
|
if (request_resource(&pbm->mem_space, rp)) {
|
||||||
|
pr_info("%s: Unable to request IOMMU resource.\n",
|
||||||
|
pbm->name);
|
||||||
|
kfree(rp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
|
|
||||||
#include <linux/perf_event.h>
|
#include <linux/perf_event.h>
|
||||||
|
#include <linux/ftrace.h>
|
||||||
|
|
||||||
#include <asm/pil.h>
|
#include <asm/pil.h>
|
||||||
#include <asm/pcr.h>
|
#include <asm/pcr.h>
|
||||||
@ -34,7 +35,7 @@ unsigned int picl_shift;
|
|||||||
* Therefore in such situations we defer the work by signalling
|
* Therefore in such situations we defer the work by signalling
|
||||||
* a lower level cpu IRQ.
|
* a lower level cpu IRQ.
|
||||||
*/
|
*/
|
||||||
void deferred_pcr_work_irq(int irq, struct pt_regs *regs)
|
void __irq_entry deferred_pcr_work_irq(int irq, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct pt_regs *old_regs;
|
struct pt_regs *old_regs;
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <linux/profile.h>
|
#include <linux/profile.h>
|
||||||
#include <linux/bootmem.h>
|
#include <linux/bootmem.h>
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
|
#include <linux/ftrace.h>
|
||||||
#include <linux/cpu.h>
|
#include <linux/cpu.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
@ -823,13 +824,13 @@ void arch_send_call_function_single_ipi(int cpu)
|
|||||||
&cpumask_of_cpu(cpu));
|
&cpumask_of_cpu(cpu));
|
||||||
}
|
}
|
||||||
|
|
||||||
void smp_call_function_client(int irq, struct pt_regs *regs)
|
void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
clear_softint(1 << irq);
|
clear_softint(1 << irq);
|
||||||
generic_smp_call_function_interrupt();
|
generic_smp_call_function_interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void smp_call_function_single_client(int irq, struct pt_regs *regs)
|
void __irq_entry smp_call_function_single_client(int irq, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
clear_softint(1 << irq);
|
clear_softint(1 << irq);
|
||||||
generic_smp_call_function_single_interrupt();
|
generic_smp_call_function_single_interrupt();
|
||||||
@ -965,7 +966,7 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page)
|
|||||||
put_cpu();
|
put_cpu();
|
||||||
}
|
}
|
||||||
|
|
||||||
void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
|
void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct mm_struct *mm;
|
struct mm_struct *mm;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
@ -1149,7 +1150,7 @@ void smp_release(void)
|
|||||||
*/
|
*/
|
||||||
extern void prom_world(int);
|
extern void prom_world(int);
|
||||||
|
|
||||||
void smp_penguin_jailcell(int irq, struct pt_regs *regs)
|
void __irq_entry smp_penguin_jailcell(int irq, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
clear_softint(1 << irq);
|
clear_softint(1 << irq);
|
||||||
|
|
||||||
@ -1365,7 +1366,7 @@ void smp_send_reschedule(int cpu)
|
|||||||
&cpumask_of_cpu(cpu));
|
&cpumask_of_cpu(cpu));
|
||||||
}
|
}
|
||||||
|
|
||||||
void smp_receive_signal_client(int irq, struct pt_regs *regs)
|
void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
clear_softint(1 << irq);
|
clear_softint(1 << irq);
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include <linux/clocksource.h>
|
#include <linux/clocksource.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/ftrace.h>
|
||||||
|
|
||||||
#include <asm/oplib.h>
|
#include <asm/oplib.h>
|
||||||
#include <asm/timer.h>
|
#include <asm/timer.h>
|
||||||
@ -717,7 +718,7 @@ static struct clock_event_device sparc64_clockevent = {
|
|||||||
};
|
};
|
||||||
static DEFINE_PER_CPU(struct clock_event_device, sparc64_events);
|
static DEFINE_PER_CPU(struct clock_event_device, sparc64_events);
|
||||||
|
|
||||||
void timer_interrupt(int irq, struct pt_regs *regs)
|
void __irq_entry timer_interrupt(int irq, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||||
unsigned long tick_mask = tick_ops->softint_mask;
|
unsigned long tick_mask = tick_ops->softint_mask;
|
||||||
@ -728,6 +729,7 @@ void timer_interrupt(int irq, struct pt_regs *regs)
|
|||||||
|
|
||||||
irq_enter();
|
irq_enter();
|
||||||
|
|
||||||
|
local_cpu_data().irq0_irqs++;
|
||||||
kstat_incr_irqs_this_cpu(0, irq_to_desc(0));
|
kstat_incr_irqs_this_cpu(0, irq_to_desc(0));
|
||||||
|
|
||||||
if (unlikely(!evt->event_handler)) {
|
if (unlikely(!evt->event_handler)) {
|
||||||
|
@ -2203,27 +2203,6 @@ void dump_stack(void)
|
|||||||
|
|
||||||
EXPORT_SYMBOL(dump_stack);
|
EXPORT_SYMBOL(dump_stack);
|
||||||
|
|
||||||
static inline int is_kernel_stack(struct task_struct *task,
|
|
||||||
struct reg_window *rw)
|
|
||||||
{
|
|
||||||
unsigned long rw_addr = (unsigned long) rw;
|
|
||||||
unsigned long thread_base, thread_end;
|
|
||||||
|
|
||||||
if (rw_addr < PAGE_OFFSET) {
|
|
||||||
if (task != &init_task)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
thread_base = (unsigned long) task_stack_page(task);
|
|
||||||
thread_end = thread_base + sizeof(union thread_union);
|
|
||||||
if (rw_addr >= thread_base &&
|
|
||||||
rw_addr < thread_end &&
|
|
||||||
!(rw_addr & 0x7UL))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct reg_window *kernel_stack_up(struct reg_window *rw)
|
static inline struct reg_window *kernel_stack_up(struct reg_window *rw)
|
||||||
{
|
{
|
||||||
unsigned long fp = rw->ins[6];
|
unsigned long fp = rw->ins[6];
|
||||||
@ -2252,6 +2231,7 @@ void die_if_kernel(char *str, struct pt_regs *regs)
|
|||||||
show_regs(regs);
|
show_regs(regs);
|
||||||
add_taint(TAINT_DIE);
|
add_taint(TAINT_DIE);
|
||||||
if (regs->tstate & TSTATE_PRIV) {
|
if (regs->tstate & TSTATE_PRIV) {
|
||||||
|
struct thread_info *tp = current_thread_info();
|
||||||
struct reg_window *rw = (struct reg_window *)
|
struct reg_window *rw = (struct reg_window *)
|
||||||
(regs->u_regs[UREG_FP] + STACK_BIAS);
|
(regs->u_regs[UREG_FP] + STACK_BIAS);
|
||||||
|
|
||||||
@ -2259,8 +2239,8 @@ void die_if_kernel(char *str, struct pt_regs *regs)
|
|||||||
* find some badly aligned kernel stack.
|
* find some badly aligned kernel stack.
|
||||||
*/
|
*/
|
||||||
while (rw &&
|
while (rw &&
|
||||||
count++ < 30&&
|
count++ < 30 &&
|
||||||
is_kernel_stack(current, rw)) {
|
kstack_valid(tp, (unsigned long) rw)) {
|
||||||
printk("Caller[%016lx]: %pS\n", rw->ins[7],
|
printk("Caller[%016lx]: %pS\n", rw->ins[7],
|
||||||
(void *) rw->ins[7]);
|
(void *) rw->ins[7]);
|
||||||
|
|
||||||
|
@ -46,11 +46,16 @@ SECTIONS
|
|||||||
SCHED_TEXT
|
SCHED_TEXT
|
||||||
LOCK_TEXT
|
LOCK_TEXT
|
||||||
KPROBES_TEXT
|
KPROBES_TEXT
|
||||||
|
IRQENTRY_TEXT
|
||||||
*(.gnu.warning)
|
*(.gnu.warning)
|
||||||
} = 0
|
} = 0
|
||||||
_etext = .;
|
_etext = .;
|
||||||
|
|
||||||
RO_DATA(PAGE_SIZE)
|
RO_DATA(PAGE_SIZE)
|
||||||
|
|
||||||
|
/* Start of data section */
|
||||||
|
_sdata = .;
|
||||||
|
|
||||||
.data1 : {
|
.data1 : {
|
||||||
*(.data1)
|
*(.data1)
|
||||||
}
|
}
|
||||||
|
@ -7,26 +7,11 @@
|
|||||||
|
|
||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
|
|
||||||
#include <asm/ptrace.h>
|
|
||||||
#include <asm/thread_info.h>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the main variant and is called by C code. GCC's -pg option
|
* This is the main variant and is called by C code. GCC's -pg option
|
||||||
* automatically instruments every C function with a call to this.
|
* automatically instruments every C function with a call to this.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_STACK_DEBUG
|
|
||||||
|
|
||||||
#define OVSTACKSIZE 4096 /* lets hope this is enough */
|
|
||||||
|
|
||||||
.data
|
|
||||||
.align 8
|
|
||||||
panicstring:
|
|
||||||
.asciz "Stack overflow\n"
|
|
||||||
.align 8
|
|
||||||
ovstack:
|
|
||||||
.skip OVSTACKSIZE
|
|
||||||
#endif
|
|
||||||
.text
|
.text
|
||||||
.align 32
|
.align 32
|
||||||
.globl _mcount
|
.globl _mcount
|
||||||
@ -35,84 +20,48 @@ ovstack:
|
|||||||
.type mcount,#function
|
.type mcount,#function
|
||||||
_mcount:
|
_mcount:
|
||||||
mcount:
|
mcount:
|
||||||
#ifdef CONFIG_STACK_DEBUG
|
|
||||||
/*
|
|
||||||
* Check whether %sp is dangerously low.
|
|
||||||
*/
|
|
||||||
ldub [%g6 + TI_FPDEPTH], %g1
|
|
||||||
srl %g1, 1, %g3
|
|
||||||
add %g3, 1, %g3
|
|
||||||
sllx %g3, 8, %g3 ! each fpregs frame is 256b
|
|
||||||
add %g3, 192, %g3
|
|
||||||
add %g6, %g3, %g3 ! where does task_struct+frame end?
|
|
||||||
sub %g3, STACK_BIAS, %g3
|
|
||||||
cmp %sp, %g3
|
|
||||||
bg,pt %xcc, 1f
|
|
||||||
nop
|
|
||||||
lduh [%g6 + TI_CPU], %g1
|
|
||||||
sethi %hi(hardirq_stack), %g3
|
|
||||||
or %g3, %lo(hardirq_stack), %g3
|
|
||||||
sllx %g1, 3, %g1
|
|
||||||
ldx [%g3 + %g1], %g7
|
|
||||||
sub %g7, STACK_BIAS, %g7
|
|
||||||
cmp %sp, %g7
|
|
||||||
bleu,pt %xcc, 2f
|
|
||||||
sethi %hi(THREAD_SIZE), %g3
|
|
||||||
add %g7, %g3, %g7
|
|
||||||
cmp %sp, %g7
|
|
||||||
blu,pn %xcc, 1f
|
|
||||||
2: sethi %hi(softirq_stack), %g3
|
|
||||||
or %g3, %lo(softirq_stack), %g3
|
|
||||||
ldx [%g3 + %g1], %g7
|
|
||||||
sub %g7, STACK_BIAS, %g7
|
|
||||||
cmp %sp, %g7
|
|
||||||
bleu,pt %xcc, 3f
|
|
||||||
sethi %hi(THREAD_SIZE), %g3
|
|
||||||
add %g7, %g3, %g7
|
|
||||||
cmp %sp, %g7
|
|
||||||
blu,pn %xcc, 1f
|
|
||||||
nop
|
|
||||||
/* If we are already on ovstack, don't hop onto it
|
|
||||||
* again, we are already trying to output the stack overflow
|
|
||||||
* message.
|
|
||||||
*/
|
|
||||||
3: sethi %hi(ovstack), %g7 ! cant move to panic stack fast enough
|
|
||||||
or %g7, %lo(ovstack), %g7
|
|
||||||
add %g7, OVSTACKSIZE, %g3
|
|
||||||
sub %g3, STACK_BIAS + 192, %g3
|
|
||||||
sub %g7, STACK_BIAS, %g7
|
|
||||||
cmp %sp, %g7
|
|
||||||
blu,pn %xcc, 2f
|
|
||||||
cmp %sp, %g3
|
|
||||||
bleu,pn %xcc, 1f
|
|
||||||
nop
|
|
||||||
2: mov %g3, %sp
|
|
||||||
sethi %hi(panicstring), %g3
|
|
||||||
call prom_printf
|
|
||||||
or %g3, %lo(panicstring), %o0
|
|
||||||
call prom_halt
|
|
||||||
nop
|
|
||||||
1:
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_FUNCTION_TRACER
|
#ifdef CONFIG_FUNCTION_TRACER
|
||||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||||
mov %o7, %o0
|
/* Do nothing, the retl/nop below is all we need. */
|
||||||
.globl mcount_call
|
|
||||||
mcount_call:
|
|
||||||
call ftrace_stub
|
|
||||||
mov %o0, %o7
|
|
||||||
#else
|
#else
|
||||||
sethi %hi(ftrace_trace_function), %g1
|
sethi %hi(function_trace_stop), %g1
|
||||||
|
lduw [%g1 + %lo(function_trace_stop)], %g2
|
||||||
|
brnz,pn %g2, 2f
|
||||||
|
sethi %hi(ftrace_trace_function), %g1
|
||||||
sethi %hi(ftrace_stub), %g2
|
sethi %hi(ftrace_stub), %g2
|
||||||
ldx [%g1 + %lo(ftrace_trace_function)], %g1
|
ldx [%g1 + %lo(ftrace_trace_function)], %g1
|
||||||
or %g2, %lo(ftrace_stub), %g2
|
or %g2, %lo(ftrace_stub), %g2
|
||||||
cmp %g1, %g2
|
cmp %g1, %g2
|
||||||
be,pn %icc, 1f
|
be,pn %icc, 1f
|
||||||
mov %i7, %o1
|
mov %i7, %g3
|
||||||
jmpl %g1, %g0
|
save %sp, -128, %sp
|
||||||
mov %o7, %o0
|
mov %g3, %o1
|
||||||
|
jmpl %g1, %o7
|
||||||
|
mov %i7, %o0
|
||||||
|
ret
|
||||||
|
restore
|
||||||
/* not reached */
|
/* not reached */
|
||||||
1:
|
1:
|
||||||
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||||
|
sethi %hi(ftrace_graph_return), %g1
|
||||||
|
ldx [%g1 + %lo(ftrace_graph_return)], %g3
|
||||||
|
cmp %g2, %g3
|
||||||
|
bne,pn %xcc, 5f
|
||||||
|
sethi %hi(ftrace_graph_entry_stub), %g2
|
||||||
|
sethi %hi(ftrace_graph_entry), %g1
|
||||||
|
or %g2, %lo(ftrace_graph_entry_stub), %g2
|
||||||
|
ldx [%g1 + %lo(ftrace_graph_entry)], %g1
|
||||||
|
cmp %g1, %g2
|
||||||
|
be,pt %xcc, 2f
|
||||||
|
nop
|
||||||
|
5: mov %i7, %g2
|
||||||
|
mov %fp, %g3
|
||||||
|
save %sp, -128, %sp
|
||||||
|
mov %g2, %l0
|
||||||
|
ba,pt %xcc, ftrace_graph_caller
|
||||||
|
mov %g3, %l1
|
||||||
|
#endif
|
||||||
|
2:
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
retl
|
retl
|
||||||
@ -131,14 +80,50 @@ ftrace_stub:
|
|||||||
.globl ftrace_caller
|
.globl ftrace_caller
|
||||||
.type ftrace_caller,#function
|
.type ftrace_caller,#function
|
||||||
ftrace_caller:
|
ftrace_caller:
|
||||||
mov %i7, %o1
|
sethi %hi(function_trace_stop), %g1
|
||||||
mov %o7, %o0
|
mov %i7, %g2
|
||||||
|
lduw [%g1 + %lo(function_trace_stop)], %g1
|
||||||
|
brnz,pn %g1, ftrace_stub
|
||||||
|
mov %fp, %g3
|
||||||
|
save %sp, -128, %sp
|
||||||
|
mov %g2, %o1
|
||||||
|
mov %g2, %l0
|
||||||
|
mov %g3, %l1
|
||||||
.globl ftrace_call
|
.globl ftrace_call
|
||||||
ftrace_call:
|
ftrace_call:
|
||||||
call ftrace_stub
|
call ftrace_stub
|
||||||
mov %o0, %o7
|
mov %i7, %o0
|
||||||
retl
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||||
|
.globl ftrace_graph_call
|
||||||
|
ftrace_graph_call:
|
||||||
|
call ftrace_stub
|
||||||
nop
|
nop
|
||||||
|
#endif
|
||||||
|
ret
|
||||||
|
restore
|
||||||
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||||
|
.size ftrace_graph_call,.-ftrace_graph_call
|
||||||
|
#endif
|
||||||
|
.size ftrace_call,.-ftrace_call
|
||||||
.size ftrace_caller,.-ftrace_caller
|
.size ftrace_caller,.-ftrace_caller
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||||
|
ENTRY(ftrace_graph_caller)
|
||||||
|
mov %l0, %o0
|
||||||
|
mov %i7, %o1
|
||||||
|
call prepare_ftrace_return
|
||||||
|
mov %l1, %o2
|
||||||
|
ret
|
||||||
|
restore %o0, -8, %i7
|
||||||
|
END(ftrace_graph_caller)
|
||||||
|
|
||||||
|
ENTRY(return_to_handler)
|
||||||
|
save %sp, -128, %sp
|
||||||
|
call ftrace_return_to_handler
|
||||||
|
mov %fp, %o0
|
||||||
|
jmpl %o0 + 8, %g0
|
||||||
|
restore
|
||||||
|
END(return_to_handler)
|
||||||
|
#endif
|
||||||
|
@ -356,7 +356,7 @@ config SLUB_STATS
|
|||||||
config DEBUG_KMEMLEAK
|
config DEBUG_KMEMLEAK
|
||||||
bool "Kernel memory leak detector"
|
bool "Kernel memory leak detector"
|
||||||
depends on DEBUG_KERNEL && EXPERIMENTAL && !MEMORY_HOTPLUG && \
|
depends on DEBUG_KERNEL && EXPERIMENTAL && !MEMORY_HOTPLUG && \
|
||||||
(X86 || ARM || PPC || S390 || SUPERH || MICROBLAZE)
|
(X86 || ARM || PPC || S390 || SPARC64 || SUPERH || MICROBLAZE)
|
||||||
|
|
||||||
select DEBUG_FS if SYSFS
|
select DEBUG_FS if SYSFS
|
||||||
select STACKTRACE if STACKTRACE_SUPPORT
|
select STACKTRACE if STACKTRACE_SUPPORT
|
||||||
|
Reference in New Issue
Block a user