diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c index f1036b6b92936fbfb5eba7a74f2026613c3c3d49..34c7c3ed2c9c5e7eafc7453c5a7a7bfacea5329a 100644 --- a/arch/blackfin/kernel/kgdb.c +++ b/arch/blackfin/kernel/kgdb.c @@ -6,23 +6,9 @@ * Licensed under the GPL-2 or later. */ -#include -#include -#include -#include -#include -#include #include /* for linux pt_regs struct */ #include -#include -#include -#include -#include #include -#include -#include -#include -#include 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; diff --git a/arch/blackfin/mm/Makefile b/arch/blackfin/mm/Makefile index d489f894f4b1d7451fc7cdedb8cf1ce9049b371b..4c011b1f661fc0c542cdd44b385168705111836f 100644 --- a/arch/blackfin/mm/Makefile +++ b/arch/blackfin/mm/Makefile @@ -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 diff --git a/arch/blackfin/mm/maccess.c b/arch/blackfin/mm/maccess.c new file mode 100644 index 0000000000000000000000000000000000000000..b71cebc1f8a3850d843c1c470fc9016ef0ef3b10 --- /dev/null +++ b/arch/blackfin/mm/maccess.c @@ -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 +#include + +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; +} diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h index 6adcc297e35408f45990ce5263f006827a08b062..19ec41a183f58f0e82c2a5a9fa840c2a11b2b6fb 100644 --- a/include/linux/kgdb.h +++ b/include/linux/kgdb.h @@ -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 diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h index 6b58367d145e8735eaebbf16bfec0733406389fb..d512d98dfb7dbae07b1669132e40af457da3e879 100644 --- a/include/linux/uaccess.h +++ b/include/linux/uaccess.h @@ -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__ */ diff --git a/mm/maccess.c b/mm/maccess.c index 9073695ff25f3db8da8df878e6ade3952542229a..4e348dbaecd75a297e59101aa9cb5b9ffc872968 100644 --- a/mm/maccess.c +++ b/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();