Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2a12c463 authored by Robin Getz's avatar Robin Getz Committed by Mike Frysinger
Browse files

Blackfin: split kernel/traps.c



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: default avatarRobin Getz <robin.getz@analog.com>
Signed-off-by: default avatarMike Frysinger <vapier@gentoo.org>
parent bb84dbf6
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -23,6 +23,8 @@
#ifndef __ASSEMBLY__
#ifndef __ASSEMBLY__
extern unsigned long trace_buff_offset;
extern unsigned long trace_buff_offset;
extern unsigned long software_trace_buff[];
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 */
/* Trace Macros for C files */


+2 −1
Original line number Original line Diff line number Diff line
@@ -7,7 +7,8 @@ extra-y := init_task.o vmlinux.lds
obj-y := \
obj-y := \
	entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \
	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 \
	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)
ifeq ($(CONFIG_GENERIC_CLOCKEVENTS),y)
    obj-y += time-ts.o
    obj-y += time-ts.o
+181 −0
Original line number Original line Diff line number Diff line
/* 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 −0
Original line number Original line Diff line number Diff line
/* 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 −0
Original line number Original line Diff line number Diff line
@@ -47,3 +47,26 @@ unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr,
}
}
EXPORT_SYMBOL(get_fb_unmapped_area);
EXPORT_SYMBOL(get_fb_unmapped_area);
#endif
#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