mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 16:29:59 +00:00
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb
* '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)
This commit is contained in:
commit
9993b364d2
6 changed files with 114 additions and 214 deletions
|
@ -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;
|
||||
|
|
|
@ -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
arch/blackfin/mm/maccess.c
Normal file
97
arch/blackfin/mm/maccess.c
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
11
mm/maccess.c
11
mm/maccess.c
|
@ -14,7 +14,11 @@
|
|||
* Safely read from address @src to the buffer at @dst. If a kernel fault
|
||||
* happens, handle that and return -EFAULT.
|
||||
*/
|
||||
long probe_kernel_read(void *dst, void *src, size_t size)
|
||||
|
||||
long __weak probe_kernel_read(void *dst, void *src, size_t size)
|
||||
__attribute__((alias("__probe_kernel_read")));
|
||||
|
||||
long __probe_kernel_read(void *dst, void *src, size_t size)
|
||||
{
|
||||
long ret;
|
||||
mm_segment_t old_fs = get_fs();
|
||||
|
@ -39,7 +43,10 @@ EXPORT_SYMBOL_GPL(probe_kernel_read);
|
|||
* Safely write to address @dst from the buffer at @src. If a kernel fault
|
||||
* happens, handle that and return -EFAULT.
|
||||
*/
|
||||
long notrace __weak probe_kernel_write(void *dst, void *src, size_t size)
|
||||
long __weak probe_kernel_write(void *dst, void *src, size_t size)
|
||||
__attribute__((alias("__probe_kernel_write")));
|
||||
|
||||
long __probe_kernel_write(void *dst, void *src, size_t size)
|
||||
{
|
||||
long ret;
|
||||
mm_segment_t old_fs = get_fs();
|
||||
|
|
Loading…
Reference in a new issue