Skip to content

Commit

Permalink
Blackfin: split kernel/traps.c
Browse files Browse the repository at this point in the history
The current kernel/traps.c file has grown a bit unwieldy as more debugging
functionality has been added over time, so split it up into more logical
files.  There should be no functional changes here, just minor whitespace
tweaking.  This should make future extensions easier to manage.

Signed-off-by: Robin Getz <robin.getz@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
  • Loading branch information
Robin Getz authored and Mike Frysinger committed May 21, 2010
1 parent bb84dbf commit 2a12c46
Show file tree
Hide file tree
Showing 7 changed files with 887 additions and 836 deletions.
2 changes: 2 additions & 0 deletions arch/blackfin/include/asm/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#ifndef __ASSEMBLY__
extern unsigned long trace_buff_offset;
extern unsigned long software_trace_buff[];
extern void decode_address(char *buf, unsigned long address);
extern bool get_instruction(unsigned short *val, unsigned short *address);

/* Trace Macros for C files */

Expand Down
3 changes: 2 additions & 1 deletion arch/blackfin/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ extra-y := init_task.o vmlinux.lds
obj-y := \
entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \
sys_bfin.o traps.o irqchip.o dma-mapping.o flat.o \
fixed_code.o reboot.o bfin_gpio.o bfin_dma_5xx.o
fixed_code.o reboot.o bfin_gpio.o bfin_dma_5xx.o \
trace.o exception.o dumpstack.o

ifeq ($(CONFIG_GENERIC_CLOCKEVENTS),y)
obj-y += time-ts.o
Expand Down
181 changes: 181 additions & 0 deletions arch/blackfin/kernel/dumpstack.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/* Provide basic stack dumping functions
*
* Copyright 2004-2009 Analog Devices Inc.
*
* Licensed under the GPL-2 or later
*/

#include <linux/kernel.h>
#include <linux/thread_info.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
#include <linux/module.h>
#include <asm/trace.h>

/*
* Checks to see if the address pointed to is either a
* 16-bit CALL instruction, or a 32-bit CALL instruction
*/
static bool is_bfin_call(unsigned short *addr)
{
unsigned short opcode = 0, *ins_addr;
ins_addr = (unsigned short *)addr;

if (!get_instruction(&opcode, ins_addr))
return false;

if ((opcode >= 0x0060 && opcode <= 0x0067) ||
(opcode >= 0x0070 && opcode <= 0x0077))
return true;

ins_addr--;
if (!get_instruction(&opcode, ins_addr))
return false;

if (opcode >= 0xE300 && opcode <= 0xE3FF)
return true;

return false;

}

void show_stack(struct task_struct *task, unsigned long *stack)
{
#ifdef CONFIG_PRINTK
unsigned int *addr, *endstack, *fp = 0, *frame;
unsigned short *ins_addr;
char buf[150];
unsigned int i, j, ret_addr, frame_no = 0;

/*
* If we have been passed a specific stack, use that one otherwise
* if we have been passed a task structure, use that, otherwise
* use the stack of where the variable "stack" exists
*/

if (stack == NULL) {
if (task) {
/* We know this is a kernel stack, so this is the start/end */
stack = (unsigned long *)task->thread.ksp;
endstack = (unsigned int *)(((unsigned int)(stack) & ~(THREAD_SIZE - 1)) + THREAD_SIZE);
} else {
/* print out the existing stack info */
stack = (unsigned long *)&stack;
endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack);
}
} else
endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack);

printk(KERN_NOTICE "Stack info:\n");
decode_address(buf, (unsigned int)stack);
printk(KERN_NOTICE " SP: [0x%p] %s\n", stack, buf);

if (!access_ok(VERIFY_READ, stack, (unsigned int)endstack - (unsigned int)stack)) {
printk(KERN_NOTICE "Invalid stack pointer\n");
return;
}

/* First thing is to look for a frame pointer */
for (addr = (unsigned int *)((unsigned int)stack & ~0xF); addr < endstack; addr++) {
if (*addr & 0x1)
continue;
ins_addr = (unsigned short *)*addr;
ins_addr--;
if (is_bfin_call(ins_addr))
fp = addr - 1;

if (fp) {
/* Let's check to see if it is a frame pointer */
while (fp >= (addr - 1) && fp < endstack
&& fp && ((unsigned int) fp & 0x3) == 0)
fp = (unsigned int *)*fp;
if (fp == 0 || fp == endstack) {
fp = addr - 1;
break;
}
fp = 0;
}
}
if (fp) {
frame = fp;
printk(KERN_NOTICE " FP: (0x%p)\n", fp);
} else
frame = 0;

/*
* Now that we think we know where things are, we
* walk the stack again, this time printing things out
* incase there is no frame pointer, we still look for
* valid return addresses
*/

/* First time print out data, next time, print out symbols */
for (j = 0; j <= 1; j++) {
if (j)
printk(KERN_NOTICE "Return addresses in stack:\n");
else
printk(KERN_NOTICE " Memory from 0x%08lx to %p", ((long unsigned int)stack & ~0xF), endstack);

fp = frame;
frame_no = 0;

for (addr = (unsigned int *)((unsigned int)stack & ~0xF), i = 0;
addr < endstack; addr++, i++) {

ret_addr = 0;
if (!j && i % 8 == 0)
printk(KERN_NOTICE "%p:", addr);

/* if it is an odd address, or zero, just skip it */
if (*addr & 0x1 || !*addr)
goto print;

ins_addr = (unsigned short *)*addr;

/* Go back one instruction, and see if it is a CALL */
ins_addr--;
ret_addr = is_bfin_call(ins_addr);
print:
if (!j && stack == (unsigned long *)addr)
printk("[%08x]", *addr);
else if (ret_addr)
if (j) {
decode_address(buf, (unsigned int)*addr);
if (frame == addr) {
printk(KERN_NOTICE " frame %2i : %s\n", frame_no, buf);
continue;
}
printk(KERN_NOTICE " address : %s\n", buf);
} else
printk("<%08x>", *addr);
else if (fp == addr) {
if (j)
frame = addr+1;
else
printk("(%08x)", *addr);

fp = (unsigned int *)*addr;
frame_no++;

} else if (!j)
printk(" %08x ", *addr);
}
if (!j)
printk("\n");
}
#endif
}
EXPORT_SYMBOL(show_stack);

void dump_stack(void)
{
unsigned long stack;
#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
int tflags;
#endif
trace_buffer_save(tflags);
dump_bfin_trace_buffer();
show_stack(current, &stack);
trace_buffer_restore(tflags);
}
EXPORT_SYMBOL(dump_stack);
45 changes: 45 additions & 0 deletions arch/blackfin/kernel/exception.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* Basic functions for adding/removing custom exception handlers
*
* Copyright 2004-2009 Analog Devices Inc.
*
* Licensed under the GPL-2 or later
*/

#include <linux/module.h>
#include <asm/irq_handler.h>

int bfin_request_exception(unsigned int exception, void (*handler)(void))
{
void (*curr_handler)(void);

if (exception > 0x3F)
return -EINVAL;

curr_handler = ex_table[exception];

if (curr_handler != ex_replaceable)
return -EBUSY;

ex_table[exception] = handler;

return 0;
}
EXPORT_SYMBOL(bfin_request_exception);

int bfin_free_exception(unsigned int exception, void (*handler)(void))
{
void (*curr_handler)(void);

if (exception > 0x3F)
return -EINVAL;

curr_handler = ex_table[exception];

if (curr_handler != handler)
return -EBUSY;

ex_table[exception] = ex_replaceable;

return 0;
}
EXPORT_SYMBOL(bfin_free_exception);
23 changes: 23 additions & 0 deletions arch/blackfin/kernel/sys_bfin.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,26 @@ unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr,
}
EXPORT_SYMBOL(get_fb_unmapped_area);
#endif

/* Needed for legacy userspace atomic emulation */
static DEFINE_SPINLOCK(bfin_spinlock_lock);

#ifdef CONFIG_SYS_BFIN_SPINLOCK_L1
__attribute__((l1_text))
#endif
asmlinkage int sys_bfin_spinlock(int *p)
{
int ret, tmp = 0;

spin_lock(&bfin_spinlock_lock); /* This would also hold kernel preemption. */
ret = get_user(tmp, p);
if (likely(ret == 0)) {
if (unlikely(tmp))
ret = 1;
else
put_user(1, p);
}
spin_unlock(&bfin_spinlock_lock);

return ret;
}
Loading

0 comments on commit 2a12c46

Please sign in to comment.