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

Commit 9993b364 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb:
  kgdb: Fix kernel-doc format error in kgdb.h
  blackfin,kgdb: Do not put PC in gdb_regs into retx.
  blackfin,kgdb,probe_kernel: Cleanup probe_kernel_read/write
  maccess,probe_kernel: Allow arch specific override probe_kernel_(read|write)
parents 82062e7b b11e1eca
Loading
Loading
Loading
Loading
+1 −206
Original line number Diff line number Diff line
@@ -6,23 +6,9 @@
 * Licensed under the GPL-2 or later.
 */

#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/ptrace.h>		/* for linux pt_regs struct */
#include <linux/kgdb.h>
#include <linux/console.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/irq.h>
#include <linux/uaccess.h>
#include <asm/system.h>
#include <asm/traps.h>
#include <asm/blackfin.h>
#include <asm/dma.h>

void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
{
@@ -147,7 +133,7 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
	regs->lb1 = gdb_regs[BFIN_LB1];
	regs->usp = gdb_regs[BFIN_USP];
	regs->syscfg = gdb_regs[BFIN_SYSCFG];
	regs->retx = gdb_regs[BFIN_PC];
	regs->retx = gdb_regs[BFIN_RETX];
	regs->retn = gdb_regs[BFIN_RETN];
	regs->rete = gdb_regs[BFIN_RETE];
	regs->pc = gdb_regs[BFIN_PC];
@@ -424,182 +410,6 @@ struct kgdb_arch arch_kgdb_ops = {
	.correct_hw_break = bfin_correct_hw_break,
};

static int hex(char ch)
{
	if ((ch >= 'a') && (ch <= 'f'))
		return ch - 'a' + 10;
	if ((ch >= '0') && (ch <= '9'))
		return ch - '0';
	if ((ch >= 'A') && (ch <= 'F'))
		return ch - 'A' + 10;
	return -1;
}

static int validate_memory_access_address(unsigned long addr, int size)
{
	if (size < 0 || addr == 0)
		return -EFAULT;
	return bfin_mem_access_type(addr, size);
}

static int bfin_probe_kernel_read(char *dst, char *src, int size)
{
	unsigned long lsrc = (unsigned long)src;
	int mem_type;

	mem_type = validate_memory_access_address(lsrc, size);
	if (mem_type < 0)
		return mem_type;

	if (lsrc >= SYSMMR_BASE) {
		if (size == 2 && lsrc % 2 == 0) {
			u16 mmr = bfin_read16(src);
			memcpy(dst, &mmr, sizeof(mmr));
			return 0;
		} else if (size == 4 && lsrc % 4 == 0) {
			u32 mmr = bfin_read32(src);
			memcpy(dst, &mmr, sizeof(mmr));
			return 0;
		}
	} else {
		switch (mem_type) {
			case BFIN_MEM_ACCESS_CORE:
			case BFIN_MEM_ACCESS_CORE_ONLY:
				return probe_kernel_read(dst, src, size);
			/* XXX: should support IDMA here with SMP */
			case BFIN_MEM_ACCESS_DMA:
				if (dma_memcpy(dst, src, size))
					return 0;
				break;
			case BFIN_MEM_ACCESS_ITEST:
				if (isram_memcpy(dst, src, size))
					return 0;
				break;
		}
	}

	return -EFAULT;
}

static int bfin_probe_kernel_write(char *dst, char *src, int size)
{
	unsigned long ldst = (unsigned long)dst;
	int mem_type;

	mem_type = validate_memory_access_address(ldst, size);
	if (mem_type < 0)
		return mem_type;

	if (ldst >= SYSMMR_BASE) {
		if (size == 2 && ldst % 2 == 0) {
			u16 mmr;
			memcpy(&mmr, src, sizeof(mmr));
			bfin_write16(dst, mmr);
			return 0;
		} else if (size == 4 && ldst % 4 == 0) {
			u32 mmr;
			memcpy(&mmr, src, sizeof(mmr));
			bfin_write32(dst, mmr);
			return 0;
		}
	} else {
		switch (mem_type) {
			case BFIN_MEM_ACCESS_CORE:
			case BFIN_MEM_ACCESS_CORE_ONLY:
				return probe_kernel_write(dst, src, size);
			/* XXX: should support IDMA here with SMP */
			case BFIN_MEM_ACCESS_DMA:
				if (dma_memcpy(dst, src, size))
					return 0;
				break;
			case BFIN_MEM_ACCESS_ITEST:
				if (isram_memcpy(dst, src, size))
					return 0;
				break;
		}
	}

	return -EFAULT;
}

/*
 * Convert the memory pointed to by mem into hex, placing result in buf.
 * Return a pointer to the last char put in buf (null). May return an error.
 */
int kgdb_mem2hex(char *mem, char *buf, int count)
{
	char *tmp;
	int err;

	/*
	 * We use the upper half of buf as an intermediate buffer for the
	 * raw memory copy.  Hex conversion will work against this one.
	 */
	tmp = buf + count;

	err = bfin_probe_kernel_read(tmp, mem, count);
	if (!err) {
		while (count > 0) {
			buf = pack_hex_byte(buf, *tmp);
			tmp++;
			count--;
		}

		*buf = 0;
	}

	return err;
}

/*
 * Copy the binary array pointed to by buf into mem.  Fix $, #, and
 * 0x7d escaped with 0x7d.  Return a pointer to the character after
 * the last byte written.
 */
int kgdb_ebin2mem(char *buf, char *mem, int count)
{
	char *tmp_old, *tmp_new;
	int size;

	tmp_old = tmp_new = buf;

	for (size = 0; size < count; ++size) {
		if (*tmp_old == 0x7d)
			*tmp_new = *(++tmp_old) ^ 0x20;
		else
			*tmp_new = *tmp_old;
		tmp_new++;
		tmp_old++;
	}

	return bfin_probe_kernel_write(mem, buf, count);
}

/*
 * Convert the hex array pointed to by buf into binary to be placed in mem.
 * Return a pointer to the character AFTER the last byte written.
 * May return an error.
 */
int kgdb_hex2mem(char *buf, char *mem, int count)
{
	char *tmp_raw, *tmp_hex;

	/*
	 * We use the upper half of buf as an intermediate buffer for the
	 * raw memory that is converted from hex.
	 */
	tmp_raw = buf + count * 2;

	tmp_hex = tmp_raw - 1;
	while (tmp_hex >= buf) {
		tmp_raw--;
		*tmp_raw = hex(*tmp_hex--);
		*tmp_raw |= hex(*tmp_hex--) << 4;
	}

	return bfin_probe_kernel_write(mem, tmp_raw, count);
}

#define IN_MEM(addr, size, l1_addr, l1_size) \
({ \
	unsigned long __addr = (unsigned long)(addr); \
@@ -629,21 +439,6 @@ int kgdb_validate_break_address(unsigned long addr)
	return -EFAULT;
}

int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr)
{
	int err = bfin_probe_kernel_read(saved_instr, (char *)addr,
	                                 BREAK_INSTR_SIZE);
	if (err)
		return err;
	return bfin_probe_kernel_write((char *)addr, arch_kgdb_ops.gdb_bpt_instr,
	                               BREAK_INSTR_SIZE);
}

int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle)
{
	return bfin_probe_kernel_write((char *)addr, bundle, BREAK_INSTR_SIZE);
}

int kgdb_arch_init(void)
{
	kgdb_single_step = 0;
+1 −1
Original line number Diff line number Diff line
@@ -2,4 +2,4 @@
# arch/blackfin/mm/Makefile
#

obj-y := sram-alloc.o isram-driver.o init.o
obj-y := sram-alloc.o isram-driver.o init.o maccess.o
+97 −0
Original line number Diff line number Diff line
/*
 * safe read and write memory routines callable while atomic
 *
 * Copyright 2005-2008 Analog Devices Inc.
 *
 * Licensed under the GPL-2 or later.
 */

#include <linux/uaccess.h>
#include <asm/dma.h>

static int validate_memory_access_address(unsigned long addr, int size)
{
	if (size < 0 || addr == 0)
		return -EFAULT;
	return bfin_mem_access_type(addr, size);
}

long probe_kernel_read(void *dst, void *src, size_t size)
{
	unsigned long lsrc = (unsigned long)src;
	int mem_type;

	mem_type = validate_memory_access_address(lsrc, size);
	if (mem_type < 0)
		return mem_type;

	if (lsrc >= SYSMMR_BASE) {
		if (size == 2 && lsrc % 2 == 0) {
			u16 mmr = bfin_read16(src);
			memcpy(dst, &mmr, sizeof(mmr));
			return 0;
		} else if (size == 4 && lsrc % 4 == 0) {
			u32 mmr = bfin_read32(src);
			memcpy(dst, &mmr, sizeof(mmr));
			return 0;
		}
	} else {
		switch (mem_type) {
		case BFIN_MEM_ACCESS_CORE:
		case BFIN_MEM_ACCESS_CORE_ONLY:
			return __probe_kernel_read(dst, src, size);
			/* XXX: should support IDMA here with SMP */
		case BFIN_MEM_ACCESS_DMA:
			if (dma_memcpy(dst, src, size))
				return 0;
			break;
		case BFIN_MEM_ACCESS_ITEST:
			if (isram_memcpy(dst, src, size))
				return 0;
			break;
		}
	}

	return -EFAULT;
}

long probe_kernel_write(void *dst, void *src, size_t size)
{
	unsigned long ldst = (unsigned long)dst;
	int mem_type;

	mem_type = validate_memory_access_address(ldst, size);
	if (mem_type < 0)
		return mem_type;

	if (ldst >= SYSMMR_BASE) {
		if (size == 2 && ldst % 2 == 0) {
			u16 mmr;
			memcpy(&mmr, src, sizeof(mmr));
			bfin_write16(dst, mmr);
			return 0;
		} else if (size == 4 && ldst % 4 == 0) {
			u32 mmr;
			memcpy(&mmr, src, sizeof(mmr));
			bfin_write32(dst, mmr);
			return 0;
		}
	} else {
		switch (mem_type) {
		case BFIN_MEM_ACCESS_CORE:
		case BFIN_MEM_ACCESS_CORE_ONLY:
			return __probe_kernel_write(dst, src, size);
			/* XXX: should support IDMA here with SMP */
		case BFIN_MEM_ACCESS_DMA:
			if (dma_memcpy(dst, src, size))
				return 0;
			break;
		case BFIN_MEM_ACCESS_ITEST:
			if (isram_memcpy(dst, src, size))
				return 0;
			break;
		}
	}

	return -EFAULT;
}
+3 −4
Original line number Diff line number Diff line
@@ -29,8 +29,7 @@ struct pt_regs;
 *
 *	On some architectures it is required to skip a breakpoint
 *	exception when it occurs after a breakpoint has been removed.
 *	This can be implemented in the architecture specific portion of
 *	for kgdb.
 *	This can be implemented in the architecture specific portion of kgdb.
 */
extern int kgdb_skipexception(int exception, struct pt_regs *regs);

@@ -65,7 +64,7 @@ struct uart_port;
/**
 *	kgdb_breakpoint - compiled in breakpoint
 *
 *	This will be impelmented a static inline per architecture.  This
 *	This will be implemented as a static inline per architecture.  This
 *	function is called by the kgdb core to execute an architecture
 *	specific trap to cause kgdb to enter the exception processing.
 *
@@ -190,7 +189,7 @@ kgdb_arch_handle_exception(int vector, int signo, int err_code,
 *	@flags: Current IRQ state
 *
 *	On SMP systems, we need to get the attention of the other CPUs
 *	and get them be in a known state.  This should do what is needed
 *	and get them into a known state.  This should do what is needed
 *	to get the other CPUs to call kgdb_wait(). Note that on some arches,
 *	the NMI approach is not used for rounding up all the CPUs. For example,
 *	in case of MIPS, smp_call_function() is used to roundup CPUs. In
+3 −1
Original line number Diff line number Diff line
@@ -94,6 +94,7 @@ static inline unsigned long __copy_from_user_nocache(void *to,
 * happens, handle that and return -EFAULT.
 */
extern long probe_kernel_read(void *dst, void *src, size_t size);
extern long __probe_kernel_read(void *dst, void *src, size_t size);

/*
 * probe_kernel_write(): safely attempt to write to a location
@@ -104,6 +105,7 @@ extern long probe_kernel_read(void *dst, void *src, size_t size);
 * Safely write to address @dst from the buffer at @src.  If a kernel fault
 * happens, handle that and return -EFAULT.
 */
extern long probe_kernel_write(void *dst, void *src, size_t size);
extern long notrace probe_kernel_write(void *dst, void *src, size_t size);
extern long notrace __probe_kernel_write(void *dst, void *src, size_t size);

#endif		/* __LINUX_UACCESS_H__ */
Loading