From 697e21660662ff5c7ce72864e19e75b907e1e498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=B1=AA?= <547884940@qq.com> Date: Tue, 12 Aug 2014 18:18:23 +0800 Subject: [PATCH 01/10] [GDB stub]first version --- components/gdb/SConscript | 23 + components/gdb/gdb_stub.c | 1005 ++++++++++++++++++ components/gdb/gdb_stub.h | 131 +++ components/gdb/hal_stub.c | 105 ++ components/gdb/libcpu/arm/arch_gdb.h | 90 ++ components/gdb/libcpu/arm/arm_stub.c | 499 +++++++++ components/gdb/libcpu/cortexm/arch_gdb.h | 158 +++ components/gdb/libcpu/cortexm/cortexm_stub.c | 414 ++++++++ components/gdb/libcpu/cortexm/gdb_gcc.S | 27 + components/gdb/libcpu/cortexm/gdb_handler.c | 11 + components/gdb/readme-zh.txt | 118 ++ 11 files changed, 2581 insertions(+) create mode 100644 components/gdb/SConscript create mode 100644 components/gdb/gdb_stub.c create mode 100644 components/gdb/gdb_stub.h create mode 100644 components/gdb/hal_stub.c create mode 100644 components/gdb/libcpu/arm/arch_gdb.h create mode 100644 components/gdb/libcpu/arm/arm_stub.c create mode 100644 components/gdb/libcpu/cortexm/arch_gdb.h create mode 100644 components/gdb/libcpu/cortexm/cortexm_stub.c create mode 100644 components/gdb/libcpu/cortexm/gdb_gcc.S create mode 100644 components/gdb/libcpu/cortexm/gdb_handler.c create mode 100644 components/gdb/readme-zh.txt diff --git a/components/gdb/SConscript b/components/gdb/SConscript new file mode 100644 index 0000000000..3ee73a0685 --- /dev/null +++ b/components/gdb/SConscript @@ -0,0 +1,23 @@ +Import('rtconfig') +from building import * + +comm = 'libcpu/' + rtconfig.ARCH +if (rtconfig.CPU == 'cortex-m4') or (rtconfig.CPU == 'cortex-m3'): + comm = 'libcpu/cortexm' + +cwd = GetCurrentDir() +if rtconfig.PLATFORM == 'armcc': + src = Glob('*.c') + Glob(comm + '/*.c') + Glob(comm + '/*_rvds.S') + +if rtconfig.PLATFORM == 'gcc': + src = Glob('*.c') + Glob(comm + '/*.c') + Glob(comm + '/*_gcc.S') + +if rtconfig.PLATFORM == 'iar': + src = Glob('*.c') + Glob(comm + '/*.c') + Glob(comm + '/*_iar.S') + + +CPPPATH = [cwd, cwd + '/' + comm] + +group = DefineGroup('gdb', src, depend = ['RT_USING_GDB'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/gdb/gdb_stub.c b/components/gdb/gdb_stub.c new file mode 100644 index 0000000000..a07c165cbb --- /dev/null +++ b/components/gdb/gdb_stub.c @@ -0,0 +1,1005 @@ +/* + * GDB stub. + * + * Migarte form linux to rt-thread by Wzyy2 + * Original edition : KGDB stub + * + * File : gdb_stub.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2014-07-04 Wzyy2 first version + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * KGDB stub. + * + * Maintainer: Jason Wessel + * + * Copyright (C) 2000-2001 VERITAS Software Corporation. + * Copyright (C) 2002-2004 Timesys Corporation + * Copyright (C) 2003-2004 Amit S. Kale + * Copyright (C) 2004 Pavel Machek + * Copyright (C) 2004-2006 Tom Rini + * Copyright (C) 2004-2006 LinSysSoft Technologies Pvt. Ltd. + * Copyright (C) 2005-2008 Wind River Systems, Inc. + * Copyright (C) 2007 MontaVista Software, Inc. + * Copyright (C) 2008 Red Hat, Inc., Ingo Molnar + * + * Contributors at various stages not listed above: + * Jason Wessel ( jason.wessel@windriver.com ) + * George Anzinger + * Anurekh Saxena (anurekh.saxena@timesys.com) + * Lake Stevens Instrument Division (Glenn Engel) + * Jim Kingdon, Cygnus Support. + * + * Original KGDB stub: David Grothe , + * Tigran Aivazian + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ +#include +#include +#include +#include "gdb_stub.h" + + +struct gdb_state { + int signo; + int pass_exception; +}gs; + +/** + * gdb_connected - Is a host GDB connected to us? + */ +int gdb_connected; + + + +/* + * Holds information about breakpoints in a kernel. These breakpoints are + * added and removed by gdb. + */ +#if RT_GDB_HAVE_SWBP +static struct gdb_bkpt gdb_break[GDB_MAX_BREAKPOINTS] = { + [0 ... GDB_MAX_BREAKPOINTS-1] = { .state = BP_UNDEFINED } +}; +#endif + + +/* Storage for the registers, in GDB format. */ +static unsigned long gdb_regs[(NUMREGBYTES + + sizeof(unsigned long) - 1) / +sizeof(unsigned long)]; + +char remcom_in_buffer[BUFMAX]; +char remcom_out_buffer[BUFMAX]; + + +static const char hexchars[] = "0123456789abcdef"; + + +//to call that there has been an error +void* volatile gdb_mem_fault_handler = (void *)0; +static long probe_kernel_write(void *dst, void *src, size_t size) +{ + int i = 0; + char *dst_ptr = (char *)dst; + char *src_ptr = (char *)src; + + gdb_mem_fault_handler = &&err; + + for (i = 0; i= '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 char tohex(char c) +{ + return hexchars[c & 15]; +} + +/* + * 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 gdb_ebin2mem(char *buf, char *mem, int count) +{ + int err = 0; + char c; + + while (count-- > 0) { + c = *buf++; + if (c == 0x7d) + c = *buf++ ^ 0x20; + + err = probe_kernel_write(mem, &c, 1); + if (err) + break; + + mem++; + } + + return err; +} + +/* + * 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 gdb_hex2mem(char *buf, char *mem, int count) +{ + char *tmp_raw; + char *tmp_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 probe_kernel_write(mem, tmp_raw, count); +} +/* + * 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 gdb_mem2hex(char *mem, char *buf, int count) +{ + char *tmp = mem; + char ch; + + gdb_mem_fault_handler = &&err; + + while (count > 0) { + ch = *(tmp++); + *(buf++) = tohex((ch >> 4) & 0xf); + *(buf++) = tohex(ch & 0xf); + + count--; + } + *buf = 0; + + gdb_mem_fault_handler = (void *)0; + return 0; +err: + gdb_mem_fault_handler = (void *)0; + return -1; +} + +/* + * While we find nice hex chars, build a long_val. + * Return number of chars processed. + */ +int gdb_hex2long(char **ptr, unsigned long *long_val) +{ + int hex_val; + int num = 0; + int negate = 0; + + *long_val = 0; + + if (**ptr == '-') { + negate = 1; + (*ptr)++; + } + while (**ptr) { + hex_val = hex(**ptr); + if (hex_val < 0) + break; + + *long_val = (*long_val << 4) | hex_val; + num++; + (*ptr)++; + } + + if (negate) + *long_val = -*long_val; + + return num; +} + +/* Write memory due to an 'M' or 'X' packet. */ +static int write_mem_msg(int binary) +{ + char *ptr = &remcom_in_buffer[1]; + unsigned long addr; + unsigned long length; + int err; + + if (gdb_hex2long(&ptr, &addr) > 0 && *(ptr++) == ',' && + gdb_hex2long(&ptr, &length) > 0 && *(ptr++) == ':') { +#ifdef GDB_DATA_ACCESS + //accesses to areas not backed can cause error + if (gdb_permit_data_access(addr, length)) + return -1; +#endif + if (binary) + err = gdb_ebin2mem(ptr, (char *)addr, length); + else + err = gdb_hex2mem(ptr, (char *)addr, length); + if (err) + return err; +#ifdef RT_GDB_ICACHE + if (CACHE_FLUSH_IS_SAFE) + gdb_flush_icache_range(addr, addr + length); +#endif + return 0; + } + + return -1; +} + +/* + * Send the packet in buffer. + * Check for gdb connection if asked for. + */ +static void put_packet(char *buffer) +{ + unsigned char checksum; + int count; + char ch; + + /* + * $#. + */ + while (1) { + gdb_io_ops.write_char('$'); + checksum = 0; + count = 0; + + while ((ch = buffer[count])) { + gdb_io_ops.write_char(ch); + checksum += ch; + count++; + } + + gdb_io_ops.write_char('#'); + gdb_io_ops.write_char(tohex((checksum >> 4) & 0xf)); + gdb_io_ops.write_char(tohex(checksum & 0xf)); + + + /* Now see what we get in reply. */ + ch = gdb_io_ops.read_char(); + + /* If we get an ACK, we are done. */ + if (ch == '+') + return; + + /* + * If we get the start of another packet, this means + * that GDB is attempting to reconnect. We will NAK + * the packet being sent, and stop trying to send this + * packet. + */ + if (ch == '$') { + gdb_io_ops.write_char('-'); + if (gdb_io_ops.flush) + gdb_io_ops.flush(); + return; + } + } +} + +/* scan for the sequence $# */ +static void get_packet(char *buffer) +{ + unsigned char checksum; + unsigned char xmitcsum; + int count; + char ch; + + do { + /* + * Spin and wait around for the start character, ignore all + * other characters: + */ + while ((ch = (gdb_io_ops.read_char())) != '$') + /* nothing */; + gdb_connected = 1; + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* + * now, read until a # or end of buffer is found: + */ + while (count < (BUFMAX - 1)) { + ch = gdb_io_ops.read_char(); + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(gdb_io_ops.read_char()) << 4; + xmitcsum += hex(gdb_io_ops.read_char()); + + if (checksum != xmitcsum) + /* failed checksum */ + gdb_io_ops.write_char('-'); + else + /* successful transfer */ + gdb_io_ops.write_char('+'); + if (gdb_io_ops.flush) + gdb_io_ops.flush(); + } + } while (checksum != xmitcsum); +} + +static void error_packet(char *pkt, int error) +{ + error = -error; + pkt[0] = 'E'; + pkt[1] = tohex((error / 10)); + pkt[2] = tohex((error % 10)); + pkt[3] = '\0'; +} + +#if RT_GDB_HAVE_SWBP +static int gdb_arch_set_breakpoint(unsigned long addr, char *saved_instr) +{ + int err; + + err = probe_kernel_write((void *)saved_instr, (void *)addr, BREAK_INSTR_SIZE); + if (err) + return err; + + return probe_kernel_write((void *)addr, (void *)arch_gdb_ops.gdb_bpt_instr, + BREAK_INSTR_SIZE); +} + +static int gdb_arch_remove_breakpoint(unsigned long addr, char *bundle) +{ + return probe_kernel_write((void *)addr, + (void *)bundle, BREAK_INSTR_SIZE); +} +static int gdb_validate_break_address(unsigned long addr) +{ + char tmp_variable[BREAK_INSTR_SIZE]; + int err; + /* Validate setting the breakpoint and then removing it. In the + * remove fails, the kernel needs to emit a bad message because we + * are deep trouble not being able to put things back the way we + * found them. + */ + err = gdb_arch_set_breakpoint(addr, tmp_variable); + if (err) + return err; + err = gdb_arch_remove_breakpoint(addr, tmp_variable); + if (err) + rt_kprintf("GDB: Critical breakpoint error,memory destroyed at: %08x \n", addr); + return err; +} + +/* + * Some architectures need cache flushes when we set/clear a + * breakpoint: + */ +static void gdb_flush_swbreak_addr(unsigned long addr) +{ + if (!CACHE_FLUSH_IS_SAFE) + return; + + /* Force flush instruction cache if it was outside the mm */ + gdb_flush_icache_range(addr, addr + BREAK_INSTR_SIZE); +} + +/* + * SW breakpoint management: + */ +static int gdb_activate_sw_breakpoints(void) +{ + unsigned long addr; + int error = 0; + int i; + + for (i = 0; i < GDB_MAX_BREAKPOINTS; i++) { + if (gdb_break[i].state != BP_SET) + continue; + + addr = gdb_break[i].bpt_addr; + error = gdb_arch_set_breakpoint(addr, + (char *)(gdb_break[i].saved_instr)); + if (error) + return error; + + gdb_flush_swbreak_addr(addr); + gdb_break[i].state = BP_ACTIVE; + } + return 0; +} + +int gdb_set_sw_break(unsigned long addr) +{ + int err = gdb_validate_break_address(addr); + int breakno = -1; + int i; + + if (err) + return err; + + for (i = 0; i < GDB_MAX_BREAKPOINTS; i++) { + if ((gdb_break[i].state == BP_SET) && + (gdb_break[i].bpt_addr == addr)) + return -1; + } + for (i = 0; i < GDB_MAX_BREAKPOINTS; i++) { + if (gdb_break[i].state == BP_REMOVED) { + breakno = i; + break; + } + } + + if (breakno == -1) { + for (i = 0; i < GDB_MAX_BREAKPOINTS; i++) { + if (gdb_break[i].state == BP_UNDEFINED) { + breakno = i; + break; + } + } + } + + if (breakno == -1) + return -1; + + gdb_break[breakno].state = BP_SET; + gdb_break[breakno].type = BP_BREAKPOINT; + gdb_break[breakno].bpt_addr = addr; + + return 0; +} + +static int gdb_deactivate_sw_breakpoints(void) +{ + unsigned long addr; + int error = 0; + int i; + + for (i = 0; i < GDB_MAX_BREAKPOINTS; i++) { + if (gdb_break[i].state != BP_ACTIVE) + continue; + addr = gdb_break[i].bpt_addr; + error = gdb_arch_remove_breakpoint(addr, + (char *)(gdb_break[i].saved_instr)); + if (error) + return error; + + gdb_flush_swbreak_addr(addr); + gdb_break[i].state = BP_SET; + } + return 0; +} + +int gdb_remove_sw_break(unsigned long addr) +{ + int i; + + for (i = 0; i < GDB_MAX_BREAKPOINTS; i++) { + if ((gdb_break[i].state == BP_SET) && + (gdb_break[i].bpt_addr == addr)) { + gdb_break[i].state = BP_REMOVED; + return 0; + } + } + return -1; +} + +int gdb_isremovedbreak(unsigned long addr) +{ + int i; + + for (i = 0; i < GDB_MAX_BREAKPOINTS; i++) { + if ((gdb_break[i].state == BP_REMOVED) && + (gdb_break[i].bpt_addr == addr)) + return 1; + } + return 0; +} +#endif + +static int remove_all_break() +{ +#if RT_GDB_HAVE_SWBP + unsigned long addr; + int error=0; + int i; + + /* Clear memory breakpoints. */ + for (i = 0; i < GDB_MAX_BREAKPOINTS; i++) { + if (gdb_break[i].state != BP_ACTIVE) + goto setundefined; + addr = gdb_break[i].bpt_addr; + error = gdb_arch_remove_breakpoint(addr, + (char *)gdb_break[i].saved_instr); + if (error) + rt_kprintf("GDB: breakpoint remove failed: %lx\n", + addr); +setundefined: + gdb_break[i].state = BP_UNDEFINED; + } +#endif + +#if RT_GDB_HAVE_HWBP + /* Clear hardware breakpoints. */ + arch_gdb_ops.remove_all_hw_break(); +#endif + + return 0; +} + + +static char gdbmsgbuf[BUFMAX + 1]; +static void gdb_msg_write(const char *s, int len) +{ + char *bufptr; + int wcount; + int i; + + /* 'O'utput */ + gdbmsgbuf[0] = 'O'; + + /* Fill and send buffers... */ + while (len > 0) { + bufptr = gdbmsgbuf + 1; + + /* Calculate how many this time */ + if ((len << 1) > (BUFMAX - 2)) + wcount = (BUFMAX - 2) >> 1; + else + wcount = len; + + /* Pack in hex chars */ + for (i = 0; i < wcount; i++) { + *(bufptr++) = tohex((s[i] >> 4) & 0xf); + *(bufptr++) = tohex(s[i] & 0xf); + } + *bufptr = '\0'; + + /* Move up */ + s += wcount; + len -= wcount; + + /* Write packet */ + put_packet(gdbmsgbuf); + } +} + +/* + * Return true if there is a valid gdb I/O module. Also if no + * debugger is attached a message can be printed to the console about + * waiting for the debugger to attach. + * + * The print_wait argument is only to be true when called from inside + * the core gdb_handle_exception, because it will wait for the + * debugger to attach. + */ +static int gdb_io_ready(int print_wait) +{ + if (!gdb_dev) + return 0; + if (gdb_connected) + return 1; + if (print_wait) + rt_kprintf("GDB: Waiting for remote debugger\n"); + return 1; +} + +/* Handle the '?' status packets */ +static void gdb_cmd_status(struct gdb_state *gs) +{ + /* + * We know that this packet is only sent + * during initial connect. So to be safe, + * we clear out our breakpoints now in case + * GDB is reconnecting. + */ + remove_all_break(); + + remcom_out_buffer[0] = 'S'; + remcom_out_buffer[1] = tohex((gs->signo >> 4) &0xf); + remcom_out_buffer[2] = tohex(gs->signo & 0xf); + remcom_out_buffer[3] = 0; +} + +/* Handle the 'm' memory read bytes */ +static void gdb_cmd_memread(struct gdb_state *gs) +{ + char *ptr = &remcom_in_buffer[1]; + unsigned long length; + unsigned long addr; + int err; + + if (gdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' && + gdb_hex2long(&ptr, &length) > 0) { +#ifdef GDB_DATA_ACCESS + //accesses to areas not backed can cause error + if (gdb_permit_data_access(addr, length)) + return ; +#endif + err = gdb_mem2hex((char *)addr, remcom_out_buffer, length); + if (err) + error_packet(remcom_out_buffer, err); + } else { + error_packet(remcom_out_buffer, -1); + } +} + +/* Handle the 'M' memory write bytes */ +static void gdb_cmd_memwrite(struct gdb_state *gs) +{ + int err = write_mem_msg(0); + + if (err) + error_packet(remcom_out_buffer, err); + else + strcpy(remcom_out_buffer, "OK"); +} + +/* Handle the 'X' memory binary write bytes */ +static void gdb_cmd_binwrite(struct gdb_state *gs) +{ + int err = write_mem_msg(1); + + if (err) + error_packet(remcom_out_buffer, err); + else + strcpy(remcom_out_buffer, "OK"); +} + +/* Handle the 'q' query packets */ +static void gdb_cmd_query(struct gdb_state *gs) +{ + /* nothing,because we have no thread support */ +} + + +/* Handle the 'g' or 'p' get registers request */ +static void gdb_cmd_getregs(struct gdb_state *gs) +{ + char len = sizeof(long); + + gdb_get_register((unsigned long *)gdb_regs); + + /*get one registers*/ + if (remcom_in_buffer[0] == 'p'){ + char *p = &remcom_in_buffer[1]; + unsigned long regno = 0; + + if (gdb_hex2long(&p, ®no)){ + gdb_mem2hex(((char *)gdb_regs) + regno * len, remcom_out_buffer, len); + return; + } else { + strcpy(remcom_out_buffer, "INVALID"); + return; + } + } + + gdb_mem2hex((char *)gdb_regs, remcom_out_buffer, NUMREGBYTES); +} + +/* Handle the 'G' or 'P' set registers request */ +static void gdb_cmd_setregs(struct gdb_state *gs) +{ + char len = sizeof(long); + + /*set one registers*/ + if (remcom_in_buffer[0] == 'P'){ + char *p = &remcom_in_buffer[1]; + unsigned long regno = 0; + + if (gdb_hex2long(&p, ®no) && *p++ == '='){ + gdb_get_register((unsigned long *)gdb_regs); + gdb_hex2mem(p, ((char *)gdb_regs) + regno * len, len); + gdb_put_register(gdb_regs); + strcpy(remcom_out_buffer, "OK"); + } + + return; + } + + gdb_hex2mem(&remcom_in_buffer[1], (char *)gdb_regs, NUMREGBYTES); + + gdb_put_register(gdb_regs); + strcpy(remcom_out_buffer, "OK"); +} + +/* Handle the 'D' or 'k', detach or kill packets */ +static void gdb_cmd_detachkill(struct gdb_state *gs) +{ + int error; + + /* The detach case */ + if (remcom_in_buffer[0] == 'D') { + error = remove_all_break(); + if (error < 0) { + error_packet(remcom_out_buffer, error); + } else { + strcpy(remcom_out_buffer, "OK"); + gdb_connected = 0; + } + put_packet(remcom_out_buffer); + } else { + /* + * Assume the kill case, with no exit code checking, + * trying to force detach the debugger: + */ + remove_all_break(); + gdb_connected = 0; + } +} + +/* Handle the 'z' or 'Z' breakpoint remove or set packets */ +static void gdb_cmd_break(struct gdb_state *gs) +{ + /* + * Since GDB-5.3, it's been drafted that '0' is a software + * breakpoint, '1' is a hardware breakpoint, so let's do that. + */ + char *bpt_type = &remcom_in_buffer[1]; + char *ptr = &remcom_in_buffer[2]; + unsigned long addr; + unsigned long length; + int error = 0; + + if (arch_gdb_ops.set_hw_breakpoint && *bpt_type >= '1') { + /* Unsupported */ + if (*bpt_type > '4') + return; + } + /* + * Test if this is a hardware breakpoint, and + * if we support it: + */ + if (*bpt_type == '1' && !(arch_gdb_ops.flags)) { + /* Unsupported. */ + return; + } + if (*(ptr++) != ',') { + error_packet(remcom_out_buffer, -1); + return; + } + if (!gdb_hex2long(&ptr, &addr)) { + error_packet(remcom_out_buffer, -1); + return; + } + if (*(ptr++) != ',' || + !gdb_hex2long(&ptr, &length)) { + error_packet(remcom_out_buffer, -1); + return; + } +#if RT_GDB_HAVE_SWBP + if (remcom_in_buffer[0] == 'Z' && *bpt_type == '0') + error = gdb_set_sw_break(addr); + else if (remcom_in_buffer[0] == 'z' && *bpt_type == '0') + error = gdb_remove_sw_break(addr); +#else + if (remcom_in_buffer[0] == 'Z' && *bpt_type == '0') + error = arch_gdb_ops.set_hw_breakpoint(addr, + (int)length, BP_HARDWARE_BREAKPOINT); + else if (remcom_in_buffer[0] == 'z' && *bpt_type == '0') + error = arch_gdb_ops.remove_hw_breakpoint(addr, + (int) length, BP_HARDWARE_BREAKPOINT); +#endif + else if (remcom_in_buffer[0] == 'Z') + error = arch_gdb_ops.set_hw_breakpoint(addr, + (int)length, *bpt_type - '0'); + else if (remcom_in_buffer[0] == 'z') + error = arch_gdb_ops.remove_hw_breakpoint(addr, + (int) length, *bpt_type - '0'); + + if (error == 0) + strcpy(remcom_out_buffer, "OK"); + else + error_packet(remcom_out_buffer, error); +} + +/* Handle the 'C' signal / exception passing packets */ +static int gdb_cmd_exception_pass(struct gdb_state *gs) +{ + /* C09 == pass exception + * C15 == detach gdb, pass exception + */ + if (remcom_in_buffer[1] == '0' && remcom_in_buffer[2] == '9') { + + gs->pass_exception = 1; + remcom_in_buffer[0] = 'c'; + + } else if (remcom_in_buffer[1] == '1' && remcom_in_buffer[2] == '5') { + + gs->pass_exception = 1; + remcom_in_buffer[0] = 'D'; + remove_all_break(); + gdb_connected = 0; + return 1; + + } else { + error_packet(remcom_out_buffer, -1); + return 0; + } + + /* Indicate fall through */ + return -1; +} + + +/*more about packet in https://www.sourceware.org/gdb/current/onlinedocs/gdb/Packets.html#Packets*/ +static int process_packet(char *pkt) +{ + int status = 0; + int tmp; + + status = gdb_arch_handle_exception(remcom_in_buffer, + remcom_out_buffer); + + remcom_out_buffer[0] = 0; + switch (pkt[0]) { + case '?':/* gdbserial status */ + gdb_cmd_status(&gs); + break; + case 'q':/* query command */ + gdb_cmd_query(&gs); + break; + case 'p': /* return the value of a single CPU register */ + case 'g': /* return the value of the CPU registers */ + gdb_cmd_getregs(&gs); + break; + case 'P': /* set the value of a single CPU registers - return OK */ + case 'G': /* set the value of the CPU registers - return OK */ + gdb_cmd_setregs(&gs); + break; + case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + gdb_cmd_memread(&gs); + break; + case 'X':/* XAA..AA,LLLL: Write LLLL escaped binary bytes at address AA.AA*/ + gdb_cmd_binwrite(&gs); + break; + case 'M':/* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + gdb_cmd_memwrite(&gs); + break; + case 'D': /* Debugger detach */ + case 'k': /* Debugger detach via kill */ + gdb_cmd_detachkill(&gs); + break; + case 'C':/* Exception passing */ + tmp = gdb_cmd_exception_pass(&gs); + if (tmp > 0) + process_packet(remcom_in_buffer); + if (tmp == 0) + break; + case 'z':/* Break point remove */ + case 'Z':/* Break point set */ + gdb_cmd_break(&gs); + break; + case 'H':/* task related */ + break; + case 'T':/* Query thread status */ + break; + case 'b': /* bBB... Set baud rate to BB... */ + break; + case 's': /* sAA..AA step form address AA..AA (optional) */ + case 'c': /* cAA..AA Continue at address AA..AA (optional) */ +#if RT_GDB_HAVE_SWBP + gdb_activate_sw_breakpoints(); +#endif + break; + } + + if (!status) + return -1; + +exit: + put_packet(remcom_out_buffer); + return 0; +} + + +/* + * This function does all command procesing for interfacing to gdb. + */ +int gdb_process_exception() +{ + int status; + + do { + get_packet(remcom_in_buffer); + status = process_packet(remcom_in_buffer); + } while (status == 0); + + if (status < 0) + return 0; + else + return 1; +} + + +int gdb_handle_exception(int signo, void *regs) +{ + int error; + + gs.signo = signo; + + if (!gdb_io_ready(1)) { + error = 1; + return error; /* No I/O connection, so resume the system */ + } + +#if RT_GDB_HAVE_SWBP + gdb_deactivate_sw_breakpoints(); +#endif + gdb_set_register(regs); + + /* Clear the out buffer. */ + memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); + + if (gdb_connected) { + char *ptr; + + gdb_io_ops.write_char('\n'); + /* Reply to host that an exception has occurred */ + ptr = remcom_out_buffer; + *ptr++ = 'T'; + *ptr++ = tohex((gs.signo >> 4) &0xf); + *ptr++ = tohex(gs.signo & 0xf); + /*ptr += strlen(strcpy(ptr, "thread:"));*/ + /**ptr++ = ';';*/ + put_packet(remcom_out_buffer); + } + gs.pass_exception = 0; + + + while (gdb_process_exception()); + + error = gs.pass_exception; + + return error; +} + +void gdb_console_write(const char *s, unsigned count) +{ + /* If we're debugging, or GDB has not connected, don't try + * and print. */ + if (!gdb_connected) + return; + + gdb_msg_write(s, count); +} + diff --git a/components/gdb/gdb_stub.h b/components/gdb/gdb_stub.h new file mode 100644 index 0000000000..cb9688ee3a --- /dev/null +++ b/components/gdb/gdb_stub.h @@ -0,0 +1,131 @@ +/* + * This provides the functions that GDB needs to share between + * different portions. + * + * GDB stub. + * + * Migarte form linux to rt-thread by Wzyy2 + * Original edition : KGDB stub + * + * File : gdb_stub.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2014-07-04 Wzyy2 first version + */ +#ifndef __GDB_STUB_H__ +#define __GDB_STUB_H__ + +#include +#include + + +#ifndef RT_GDB_MAX_BREAKPOINTS + #define GDB_MAX_BREAKPOINTS 20 +#else + #define GDB_MAX_BREAKPOINTS RT_GDB_MAX_BREAKPOINTS +#endif + + +// Signal definitions +#define SIGHUP 1 /* hangup */ +#define SIGINT 2 /* interrupt */ //irq or fiq +#define SIGQUIT 3 /* quit */ +#define SIGILL 4 /* illegal instruction (not reset when caught) */ +#define SIGTRAP 5 /* trace trap (not reset when caught) */ +#define SIGIOT 6 /* IOT instruction */ +#define SIGABRT 6 /* used by abort, replace SIGIOT in the future */ +#define SIGEMT 7 /* EMT instruction */ +#define SIGFPE 8 /* floating point exception */ +#define SIGKILL 9 /* kill (cannot be caught or ignored) */ +#define SIGBUS 10 /* bus error */ //abort or reserved +#define SIGSEGV 11 /* segmentation violation */ +#define SIGSYS 12 /* bad argument to system call */ +#define SIGPIPE 13 /* write on a pipe with no one to read it */ +#define SIGALRM 14 /* alarm clock */ +#define SIGTERM 15 /* software termination signal from kill */ + +enum gdb_bptype { + BP_BREAKPOINT = 0, + BP_HARDWARE_BREAKPOINT, + BP_WRITE_WATCHPOINT, + BP_READ_WATCHPOINT, + BP_ACCESS_WATCHPOINT, + BP_POKE_BREAKPOINT, +}; + +enum gdb_bpstate { + BP_UNDEFINED = 0, + BP_REMOVED, + BP_SET, + BP_ACTIVE +}; + +struct gdb_bkpt { + unsigned long bpt_addr; + unsigned char saved_instr[BREAK_INSTR_SIZE]; + enum gdb_bptype type; + enum gdb_bpstate state; +}; + +/** + * struct gdb_arch - Describe architecture specific values. + * @gdb_bpt_instr: The instruction to trigger a breakpoint. + * @flags: Flags for the breakpoint, currently just %GDB_HW_BREAKPOINT. + * @set_hw_breakpoint: Allow an architecture to specify how to set a hardware + * breakpoint. + * @remove_hw_breakpoint: Allow an architecture to specify how to remove a + * hardware breakpoint. + * @remove_all_hw_break: Allow an architecture to specify how to remove all + * hardware breakpoints. + */ +struct gdb_arch { + unsigned char gdb_bpt_instr[BREAK_INSTR_SIZE]; + unsigned long flags; + + int (*set_hw_breakpoint)(unsigned long, int, enum gdb_bptype); + int (*remove_hw_breakpoint)(unsigned long, int, enum gdb_bptype); + void (*remove_all_hw_break)(void); +}; +/** + * struct gdb_io - Describe the interface for an I/O driver to talk with KGDB. + * @read_char: Pointer to a function that will return one char. + * @write_char: Pointer to a function that will write one char. + * @flush: Pointer to a function that will flush any pending writes. + * @init: Pointer to a function that will initialize the device. + */ +struct gdb_io { + int (*read_char) (void); + void (*write_char) (char); + void (*flush) (void); + int (*init) (void); +}; + +extern int gdb_connected; +extern void* volatile gdb_mem_fault_handler; + +int gdb_hex2long(char **ptr, unsigned long *long_val); +int gdb_mem2hex(char *mem, char *buf, int count); +int gdb_hex2mem(char *buf, char *mem, int count); +int gdb_ebin2mem(char *buf, char *mem, int count); +int gdb_set_sw_break(unsigned long addr); +int gdb_remove_sw_break(unsigned long addr); +int gdb_isremovedbreak(unsigned long addr); +void gdb_console_write(const char *s, unsigned count); +int gdb_handle_exception(int signo, void *regs); + +/* hal */ +extern struct gdb_io gdb_io_ops; +extern rt_device_t gdb_dev; +void gdb_start(); +void gdb_set_device(const char* device_name); + + + +#endif /* __GDB_STUB_H__ */ diff --git a/components/gdb/hal_stub.c b/components/gdb/hal_stub.c new file mode 100644 index 0000000000..077c4088f7 --- /dev/null +++ b/components/gdb/hal_stub.c @@ -0,0 +1,105 @@ +/* + * I/O and interface portion of GDB stub + * + * File : hal_stub.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2014-07-04 Wzyy2 first version + */ +#include +#include +#include "gdb_stub.h" + +#ifdef RT_USING_SERIAL +#include +#endif + +rt_device_t gdb_dev = RT_NULL; +static struct rt_serial_device *gdb_serial; +char gdb_io_set; + +void gdb_uart_putc(char c); +int gdb_uart_getc(); + + +/*if you want to use something instead of the serial,change it */ +struct gdb_io gdb_io_ops = { + gdb_uart_getc, + gdb_uart_putc +}; + + +/** + * @ingroup gdb_stub + * + * This function will get GDB stubs started, with a proper environment + */ +void gdb_start() +{ + if (gdb_dev == RT_NULL) + rt_kprintf("GDB: no gdb_dev found,please set it first\n"); + else + gdb_breakpoint(); +} + + +/** + * @ingroup gdb_stub + * + * This function sets the input device of gdb_stub. + * + * @param device_name the name of new input device. + */ +void gdb_set_device(const char* device_name) +{ + rt_device_t dev = RT_NULL; + dev = rt_device_find(device_name); + if(dev == RT_NULL){ + rt_kprintf("GDB: can not find device: %s\n", device_name); + return; + } + + /* open this device and set the new device */ + if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR) == RT_EOK) + { + gdb_dev = dev; + gdb_serial = (struct rt_serial_device *)gdb_dev; + } +} + +void gdb_uart_putc(char c) +{ +#ifdef RT_GDB_DEBUG + rt_kprintf("%c",c); +#endif + rt_device_write(gdb_dev, 0, &c, 1); +} + +/* polling */ +int gdb_uart_getc() +{ + int ch; + +#ifdef RT_USING_SERIAL + ch = -1; + do { + ch = gdb_serial->ops->getc(gdb_serial); + } while (ch == -1); +#else + rt_device_read(gdb_dev, 0, &ch, 1); +#endif + +#ifdef RT_GDB_DEBUG + rt_kprintf("%c",ch); +#endif + + return ch; +} + diff --git a/components/gdb/libcpu/arm/arch_gdb.h b/components/gdb/libcpu/arm/arch_gdb.h new file mode 100644 index 0000000000..b9462499f2 --- /dev/null +++ b/components/gdb/libcpu/arm/arch_gdb.h @@ -0,0 +1,90 @@ +/* + * ARM GDB support + * arch-specific portion of GDB stub + * + * File : arch_gdb.h(arm) + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2014-07-04 wzyy2 first version + */ +#ifndef __ARM_GDB_H__ +#define __ARM_GDB_H__ + +#include + + +#ifndef RT_GDB_HAVE_HWBP + #define RT_GDB_HAVE_HWBP 0 +#endif +#ifndef RT_GDB_HAVE_SWBP + #define RT_GDB_HAVE_SWBP 1 +#endif + + +#if RT_GDB_HAVE_HWBP + #error GDB:No hardware_breakpoint support +#endif + + +/* + * By doing this as an undefined instruction trap, we force a mode + * switch from SVC to UND mode, allowing us to save full kernel state. + * We also define a GDB_COMPILED_BREAK which can be used to compile + * in breakpoints. + */ +#define BREAK_INSTR_SIZE 4 +#define GDB_BREAKINST 0xe7ffdefe +#define GDB_COMPILED_BREAK 0xe7ffdeff +#define CACHE_FLUSH_IS_SAFE 1 + +#define ARM_GP_REGS 16 +#define ARM_FP_REGS 8 +#define ARM_EXTRA_REGS 2 +#define GDB_MAX_REGS (ARM_GP_REGS + (ARM_FP_REGS * 3) + ARM_EXTRA_REGS) +#define NUMREGBYTES (GDB_MAX_REGS << 2) + + +//#define BUFMAX ((NUMREGBYTES << 1) + 10) +#define BUFMAX 400 + +enum regnames { + GDB_R0, /*0*/ + GDB_R1, /*1*/ + GDB_R2, /*2*/ + GDB_R3, /*3*/ + GDB_R4, /*4*/ + GDB_R5, /*5*/ + GDB_R6, /*6*/ + GDB_R7, /*7*/ + GDB_R8, /*8*/ + GDB_R9, /*9*/ + GDB_R10, /*10*/ + GDB_FP, /*11*/ + GDB_IP, /*12*/ + GDB_SPT, /*13*/ + GDB_LR, /*14*/ + GDB_PC, /*15*/ + GDB_CPSR = GDB_MAX_REGS-1 +}; + +/* arch */ +extern struct gdb_arch arch_gdb_ops; +void gdb_breakpoint(); +void gdb_get_register(unsigned long *gdb_regs); +void gdb_put_register(unsigned long *gdb_regs); +void gdb_set_register(void *hw_regs); +int gdb_arch_handle_exception(char *remcom_in_buffer, + char *remcom_out_buffer); +void gdb_flush_icache_range(unsigned long start, unsigned long end); +int gdb_undef_hook(void *regs); + +int gdb_handle_exception(int signo, void *regs); + +#endif /* __ARM_GDB_H__ */ diff --git a/components/gdb/libcpu/arm/arm_stub.c b/components/gdb/libcpu/arm/arm_stub.c new file mode 100644 index 0000000000..a312d39f4a --- /dev/null +++ b/components/gdb/libcpu/arm/arm_stub.c @@ -0,0 +1,499 @@ +/* + * ARM GDB support + * arch-specific portion of GDB stub + * + * File : arm_stub.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2014-07-04 Wzyy2 first version + */ +#include +#include +#include +#include + +#define PS_N 0x80000000 +#define PS_Z 0x40000000 +#define PS_C 0x20000000 +#define PS_V 0x10000000 + +#define IS_THUMB_ADDR(addr) ((addr) & 1) +#define MAKE_THUMB_ADDR(addr) ((addr) | 1) +#define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1) + +static int compiled_break = 0; +static unsigned long step_addr = 0; +static int ins_will_execute(unsigned long ins); +static unsigned long target_ins(unsigned long *pc, unsigned long ins); + + +/*struct gdb_arch - Describe architecture specific values.*/ +struct gdb_arch arch_gdb_ops = { + .gdb_bpt_instr = {0xfe, 0xde, 0xff, 0xe7} //Little-Endian +}; + +struct rt_gdb_register +{ + rt_uint32_t r0; + rt_uint32_t r1; + rt_uint32_t r2; + rt_uint32_t r3; + rt_uint32_t r4; + rt_uint32_t r5; + rt_uint32_t r6; + rt_uint32_t r7; + rt_uint32_t r8; + rt_uint32_t r9; + rt_uint32_t r10; + rt_uint32_t fp; + rt_uint32_t ip; + rt_uint32_t sp; + rt_uint32_t lr; + rt_uint32_t pc; + rt_uint32_t cpsr; + rt_uint32_t ORIG_r0; +}*regs; + +/** + * gdb_breakpoint - generate a compiled_breadk + * It is used to sync up with a debugger and stop progarm + */ +void gdb_breakpoint() +{ + asm(".word 0xe7ffdeff"); +} + +void gdb_set_register(void *hw_regs) +{ + regs = (struct rt_gdb_register *)hw_regs; +} +void gdb_get_register(unsigned long *gdb_regs) +{ + int regno; + /* Initialize all to zero. */ + for (regno = 0; regno < GDB_MAX_REGS; regno++) + gdb_regs[regno] = 0; + + gdb_regs[GDB_R0] = regs->r0; + gdb_regs[GDB_R1] = regs->r1; + gdb_regs[GDB_R2] = regs->r2; + gdb_regs[GDB_R3] = regs->r3; + gdb_regs[GDB_R4] = regs->r4; + gdb_regs[GDB_R5] = regs->r5; + gdb_regs[GDB_R6] = regs->r6; + gdb_regs[GDB_R7] = regs->r7; + gdb_regs[GDB_R8] = regs->r8; + gdb_regs[GDB_R9] = regs->r9; + gdb_regs[GDB_R10] = regs->r10; + gdb_regs[GDB_FP] = regs->fp; + gdb_regs[GDB_IP] = regs->ip; + gdb_regs[GDB_SPT] = regs->sp; + gdb_regs[GDB_LR] = regs->lr; + gdb_regs[GDB_PC] = regs->pc; + gdb_regs[GDB_CPSR] = regs->cpsr; + +}; + + +void gdb_put_register(unsigned long *gdb_regs) +{ + regs->r0 = gdb_regs[GDB_R0]; + regs->r1 = gdb_regs[GDB_R1]; + regs->r2 = gdb_regs[GDB_R2]; + regs->r3 = gdb_regs[GDB_R3]; + regs->r4 = gdb_regs[GDB_R4]; + regs->r5 = gdb_regs[GDB_R5]; + regs->r6 = gdb_regs[GDB_R6]; + regs->r7 = gdb_regs[GDB_R7]; + regs->r8 = gdb_regs[GDB_R8]; + regs->r9 = gdb_regs[GDB_R9]; + regs->r10 = gdb_regs[GDB_R10]; + regs->fp = gdb_regs[GDB_FP]; + regs->ip = gdb_regs[GDB_IP]; + regs->sp = gdb_regs[GDB_SPT]; + regs->lr = gdb_regs[GDB_LR]; + regs->pc = gdb_regs[GDB_PC]; + regs->cpsr = gdb_regs[GDB_CPSR]; +} + + +/* It will be called during process_packet */ +int gdb_arch_handle_exception(char *remcom_in_buffer, + char *remcom_out_buffer) +{ + unsigned long addr,curins; + char *ptr; + + /*clear single step*/ + if (step_addr) { + gdb_remove_sw_break(step_addr); + step_addr = 0; + } + + switch (remcom_in_buffer[0]) { + case 'D': + case 'k': + case 'c': + /* + * If this was a compiled breakpoint, we need to move + * to the next instruction or we will breakpoint + * over and over again + */ + ptr = &remcom_in_buffer[1]; + if (gdb_hex2long(&ptr, &addr)) + regs->pc = addr; + else if (compiled_break == 1) + regs->pc += 4; + compiled_break = 0; + return 0; + + case 's': + ptr = &remcom_in_buffer[1]; + if (gdb_hex2long(&ptr, &addr)) + regs->pc = addr; + + curins = *(unsigned long*)(regs->pc); + if (ins_will_execute(curins)) + //Decode instruction to decide what the next pc will be + step_addr = target_ins((unsigned long *)regs->pc, curins); + else + step_addr = regs->pc + 4; + +#ifdef RT_GDB_DEBUG + rt_kprintf("\n next will be %x \n",step_addr); +#endif + gdb_set_sw_break(step_addr); + + if (compiled_break == 1) + regs->pc += 4; + compiled_break = 0; + return 0; + } + + return -1; + +} + +/* flush icache to let the sw breakpoint working */ +void gdb_flush_icache_range(unsigned long start, unsigned long end) +{ +#ifdef RT_GDB_ICACHE + extern void mmu_invalidate_icache(); + mmu_invalidate_icache(); //for arm,wo can only invalidate it +#endif +} + +/* register a hook in undef*/ +int gdb_undef_hook(void *regs) +{ + struct rt_gdb_register *tmp_reg = (struct rt_gdb_register *)regs; + unsigned long *tmp_pc = (unsigned long *)tmp_reg->pc; + + /* it is a compiled break */ + if (*tmp_pc == GDB_COMPILED_BREAK) { + compiled_break = 1; + gdb_handle_exception(SIGTRAP, regs); + return 1; + + } + /* it is a sw break */ + else if (*tmp_pc == GDB_BREAKINST) { + gdb_handle_exception(SIGTRAP, regs); + return 1; + } + /*or we just go */ + return 0; + +} + +static unsigned long gdb_arch_regs[GDB_MAX_REGS]; +static int ins_will_execute(unsigned long ins) +{ + unsigned long psr = regs->cpsr; // condition codes + int res = 0; + switch ((ins & 0xF0000000) >> 28) { + case 0x0: // EQ + res = (psr & PS_Z) != 0; + break; + case 0x1: // NE + res = (psr & PS_Z) == 0; + break; + case 0x2: // CS + res = (psr & PS_C) != 0; + break; + case 0x3: // CC + res = (psr & PS_C) == 0; + break; + case 0x4: // MI + res = (psr & PS_N) != 0; + break; + case 0x5: // PL + res = (psr & PS_N) == 0; + break; + case 0x6: // VS + res = (psr & PS_V) != 0; + break; + case 0x7: // VC + res = (psr & PS_V) == 0; + break; + case 0x8: // HI + res = ((psr & PS_C) != 0) && ((psr & PS_Z) == 0); + break; + case 0x9: // LS + res = ((psr & PS_C) == 0) || ((psr & PS_Z) != 0); + break; + case 0xA: // GE + res = ((psr & (PS_N|PS_V)) == (PS_N|PS_V)) || + ((psr & (PS_N|PS_V)) == 0); + break; + case 0xB: // LT + res = ((psr & (PS_N|PS_V)) == PS_N) || + ((psr & (PS_N|PS_V)) == PS_V); + break; + case 0xC: // GT + res = ((psr & (PS_N|PS_V)) == (PS_N|PS_V)) || + ((psr & (PS_N|PS_V)) == 0); + res = ((psr & PS_Z) == 0) && res; + break; + case 0xD: // LE + res = ((psr & (PS_N|PS_V)) == PS_N) || + ((psr & (PS_N|PS_V)) == PS_V); + res = ((psr & PS_Z) == PS_Z) || res; + break; + case 0xE: // AL + res = 1; + break; + case 0xF: // NV + if (((ins & 0x0E000000) >> 24) == 0xA) + res = 1; + else + res = 0; + break; + } + return res; +} + +static unsigned long RmShifted(int shift) +{ + unsigned long Rm = gdb_arch_regs[shift & 0x00F]; + int shift_count; + if ((shift & 0x010) == 0) { + shift_count = (shift & 0xF80) >> 7; + } else { + shift_count = gdb_arch_regs[(shift & 0xF00) >> 8]; + } + switch ((shift & 0x060) >> 5) { + case 0x0: // Logical left + Rm <<= shift_count; + break; + case 0x1: // Logical right + Rm >>= shift_count; + break; + case 0x2: // Arithmetic right + Rm = (unsigned long)((long)Rm >> shift_count); + break; + case 0x3: // Rotate right + if (shift_count == 0) { + // Special case, RORx + Rm >>= 1; + if (gdb_arch_regs[GDB_CPSR] & PS_C) Rm |= 0x80000000; + } else { + Rm = (Rm >> shift_count) | (Rm << (32-shift_count)); + } + break; + } + return Rm; +} + +// Decide the next instruction to be executed for a given instruction +static unsigned long target_ins(unsigned long *pc, unsigned long ins) +{ + unsigned long new_pc, offset, op2; + unsigned long Rn; + int i, reg_count, c; + + gdb_get_register(gdb_arch_regs); + + switch ((ins & 0x0C000000) >> 26) { + case 0x0: + // BX or BLX + if ((ins & 0x0FFFFFD0) == 0x012FFF10) { + new_pc = (unsigned long)gdb_arch_regs[ins & 0x0000000F]; + return new_pc; + } + // Data processing + new_pc = (unsigned long)(pc+1); + if ((ins & 0x0000F000) == 0x0000F000) { + // Destination register is PC + if ((ins & 0x0FBF0000) != 0x010F0000) { + Rn = (unsigned long)gdb_arch_regs[(ins & 0x000F0000) >> 16]; + if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch! + if ((ins & 0x02000000) == 0) { + op2 = RmShifted(ins & 0x00000FFF); + } else { + op2 = ins & 0x000000FF; + i = (ins & 0x00000F00) >> 8; // Rotate count + op2 = (op2 >> (i*2)) | (op2 << (32-(i*2))); + } + switch ((ins & 0x01E00000) >> 21) { + case 0x0: // AND + new_pc = Rn & op2; + break; + case 0x1: // EOR + new_pc = Rn ^ op2; + break; + case 0x2: // SUB + new_pc = Rn - op2; + break; + case 0x3: // RSB + new_pc = op2 - Rn; + break; + case 0x4: // ADD + new_pc = Rn + op2; + break; + case 0x5: // ADC + c = (gdb_arch_regs[GDB_CPSR] & PS_C) != 0; + new_pc = Rn + op2 + c; + break; + case 0x6: // SBC + c = (gdb_arch_regs[GDB_CPSR] & PS_C) != 0; + new_pc = Rn - op2 + c - 1; + break; + case 0x7: // RSC + c = (gdb_arch_regs[GDB_CPSR] & PS_C) != 0; + new_pc = op2 - Rn +c - 1; + break; + case 0x8: // TST + case 0x9: // TEQ + case 0xA: // CMP + case 0xB: // CMN + break; // PC doesn't change + case 0xC: // ORR + new_pc = Rn | op2; + break; + case 0xD: // MOV + new_pc = op2; + break; + case 0xE: // BIC + new_pc = Rn & ~op2; + break; + case 0xF: // MVN + new_pc = ~op2; + break; + } + } + } + return new_pc; + case 0x1: + if ((ins & 0x02000010) == 0x02000010) { + // Undefined! + return (unsigned long)(pc+1); + } else { + if ((ins & 0x00100000) == 0) { + // STR + return (unsigned long)(pc+1); + } else { + // LDR + if ((ins & 0x0000F000) != 0x0000F000) { + // Rd not PC + return (unsigned long)(pc+1); + } else { + Rn = (unsigned long)gdb_arch_regs[(ins & 0x000F0000) >> 16]; + if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch! + if (ins & 0x01000000) { + // Add/subtract offset before + if ((ins & 0x02000000) == 0) { + // Immediate offset + if (ins & 0x00800000) { + // Add offset + Rn += (ins & 0x00000FFF); + } else { + // Subtract offset + Rn -= (ins & 0x00000FFF); + } + } else { + // Offset is in a register + if (ins & 0x00800000) { + // Add offset + Rn += RmShifted(ins & 0x00000FFF); + } else { + // Subtract offset + Rn -= RmShifted(ins & 0x00000FFF); + } + } + } + return *(unsigned long *)Rn; + } + } + } + return (unsigned long)(pc+1); + case 0x2: // Branch, LDM/STM + if ((ins & 0x02000000) == 0) { + // LDM/STM + if ((ins & 0x00100000) == 0) { + // STM + return (unsigned long)(pc+1); + } else { + // LDM + if ((ins & 0x00008000) == 0) { + // PC not in list + return (unsigned long)(pc+1); + } else { + Rn = (unsigned long)gdb_arch_regs[(ins & 0x000F0000) >> 16]; + if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch! + offset = ins & 0x0000FFFF; + reg_count = 0; + for (i = 0; i < 15; i++) { + if (offset & (1< + +#ifndef RT_GDB_HAVE_HWBP + #define RT_GDB_HAVE_HWBP 1 +#endif +#ifndef RT_GDB_HAVE_SWBP + #define RT_GDB_HAVE_SWBP 0 +#endif + +#ifndef GDB_CORTEXM_PRIORITY_MAX + #define GDB_CORTEXM_PRIORITY_MAX (1 << 6) +#endif + +#define GDB_DATA_ACCESS + +#define BREAK_INSTR_SIZE 4 +#define ARM_GP_REGS 16 +#define ARM_FP_REGS 8 +#define ARM_EXTRA_REGS 2 +#define GDB_MAX_REGS (ARM_GP_REGS + (ARM_FP_REGS * 3) + ARM_EXTRA_REGS) +#define NUMREGBYTES (GDB_MAX_REGS << 2) + +#define HBP_NUM 6 //Max hardware breakpoint +#define HWP_NUM 4 //Max hardware watchpoint + +//#define BUFMAX ((NUMREGBYTES << 1) + 10) +#define BUFMAX 400 + +#define GDB_DEBUG_REG_BASE 0xE000EDF0 +#define GDB_DEBUG_REG_DHSR 0x00 +#define GDB_DEBUG_REG_DCRSR 0x04 +#define GDB_DEBUG_REG_DCRDR 0x08 +#define GDB_DEBUG_REG_DEMCR 0x0c + +#define GDB_DEBUG_REG_DEMCR_MON_EN (1UL << 16) +#define GDB_DEBUG_REG_DEMCR_MON_PEND (1UL << 17) +#define GDB_DEBUG_REG_DEMCR_MON_STEP (1UL << 18) +#define GDB_DEBUG_REG_DEMCR_TRCENA (1UL << 24) + +#define GDB_NVIC_REG_BASE 0xE000E000 +#define GDB_NVIC_REG_SHCSR 0xD24 +#define GDB_NVIC_REG_DFSR 0xD30 + +#define GDB_NVIC_REG_SHCSR_MEMFAULTENA (1 << 16) + +#define GDB_FPB_REG_BASE 0xE0002000 +#define GDB_FPB_REG_CTRL 0x0 +#define GDB_FPB_REG_REMAP 0x4 +#define GDB_FPB_REG_COMP 0x8 + +#define GDB_FPB_REG_CTRL_KEY (1UL << 1) +#define GDB_FPB_REG_CTRL_ENABLE 1 +#define GDB_FPB_REG_COMP_ENABLE 1 +#define GDB_FPB_REG_COMP_ADDR (((1UL << 29) -1) << 2) +#define GDB_FPB_REG_COMP_REPLACE (((1UL << 32) -1) << 30) + +#define GDB_DWT_REG_BASE 0xE0001000 +#define GDB_DWT_REG_CTRL 0x0 +#define GDB_DWT_REG_COMP 0x20 +#define GDB_DWT_REG_MASK 0x24 +#define GDB_DWT_REG_FUNCTION 0x28 + +#define GDB_DWT_REG_FUNCTION_FUC (((1UL << 4) -1) << 0) + + + + +enum regnames { + GDB_R0, /*0*/ + GDB_R1, /*1*/ + GDB_R2, /*2*/ + GDB_R3, /*3*/ + GDB_R4, /*4*/ + GDB_R5, /*5*/ + GDB_R6, /*6*/ + GDB_R7, /*7*/ + GDB_R8, /*8*/ + GDB_R9, /*9*/ + GDB_R10, /*10*/ + GDB_FP, /*11*/ + GDB_IP, /*12*/ + GDB_SPT, /*13*/ + GDB_LR, /*14*/ + GDB_PC, /*15*/ + GDB_F0, /*16*/ + GDB_F1, /*17*/ + GDB_F2, /*18*/ + GDB_F3, /*19*/ + GDB_F4, /*20*/ + GDB_F5, /*21*/ + GDB_F6, /*22*/ + GDB_F7, /*23*/ + GDB_FPS, /*24*/ + GDB_CPSR = GDB_MAX_REGS-1 +}; + +typedef struct +{ + unsigned long type; // State type + unsigned long vector; // Exception vector number + unsigned long basepri; // BASEPRI + + unsigned long r4; // Remaining CPU registers + unsigned long r5; // Remaining CPU registers + unsigned long r6; // Remaining CPU registers + unsigned long r7; // Remaining CPU registers + unsigned long r8; // Remaining CPU registers + unsigned long r9; // Remaining CPU registers + unsigned long r10; // Remaining CPU registers + unsigned long r11; // Remaining CPU registers + unsigned long sp; // Remaining CPU registers + + unsigned long xlr; // Exception return LR + // The following are saved and restored automatically by the CPU + // for exceptions or interrupts. + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r12; + unsigned long lr; + unsigned long pc; + unsigned long psr; +} Gdb_SavedRegisters; + +/* arch */ +extern struct gdb_arch arch_gdb_ops; +void gdb_breakpoint(); +void gdb_get_register(unsigned long *gdb_regs); +void gdb_put_register(unsigned long *gdb_regs); +void gdb_set_register(void *hw_regs); +int gdb_arch_handle_exception(char *remcom_in_buffer, + char *remcom_out_buffer); + +int gdb_permit_data_access(unsigned long addr, unsigned long count); +void gdb_arch_exit(); +void gdb_arch_late(); + +#endif /* __CORTEXM_GDB_H__ */ diff --git a/components/gdb/libcpu/cortexm/cortexm_stub.c b/components/gdb/libcpu/cortexm/cortexm_stub.c new file mode 100644 index 0000000000..bcbdc39dd1 --- /dev/null +++ b/components/gdb/libcpu/cortexm/cortexm_stub.c @@ -0,0 +1,414 @@ +/* + * CORTEXM GDB support + * arch-specific portion of GDB stub + * + * File : cortexm_stub.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2014-07-04 Wzyy2 first version + */ +#include +#include +#include + +static Gdb_SavedRegisters *regs; +unsigned long single_step_basepri = 0; + +void gdb_remove_all_hw_break(); +void gdb_enable_hw_debug(); +void gdb_disable_hw_debug(); +int gdb_set_hw_break(unsigned long, int, enum gdb_bptype); +int gdb_remove_hw_break(unsigned long, int, enum gdb_bptype); + +/*struct gdb_arch - Describe architecture specific values.*/ +struct gdb_arch arch_gdb_ops = { + /* Breakpoint instruction: */ + .gdb_bpt_instr = {0xfe, 0xde, 0xff, 0xe7}, //Little-Endian + .flags = RT_GDB_HAVE_HWBP, + .set_hw_breakpoint = gdb_set_hw_break, + .remove_hw_breakpoint = gdb_remove_hw_break, + .remove_all_hw_break = gdb_remove_all_hw_break +}; + +static struct hw_breakpoint { + int enabled; + unsigned long addr; +} breakinfo[HBP_NUM]; + +static struct hw_watchpoint { + int enabled; + unsigned long addr; + int len; + enum gdb_bptype type; +} watchinfo[HWP_NUM]; + +//The following table defines the memory areas that GDB is allow to touch +static const struct { + unsigned long start; + unsigned long end; +} data_access[] = +{ + { 0x20000000, 0x40000000-1}, // On-chip ram + { 0x60000000, 0xa0000000-1}, // External ram + { 0x00000000, 0x20000000-1}, // On-chip flash + { 0x60000000, 0xa0000000-1}, // External flash + { 0xE0000000, 0x00000000-1}, // cortex-M peripheral + { 0x40000000, 0x60000000-1}, // mcu peripheral +}; + + +int gdb_permit_data_access(unsigned long addr, unsigned long count) +{ + unsigned char i; + + for (i = 0; i < sizeof(data_access)/sizeof(data_access[0]); i++) { + if ((addr >= data_access[i].start) && (addr + count) <= data_access[i].end) { + return 0; + } + } + + return -1; +} + +/*we need to block all pending interrupts by swtting basepri + * before doing the steo + */ +void gdb_single_step() +{ + volatile unsigned long *base; + + //mask all interrupts + single_step_basepri = regs->basepri; + regs->basepri = GDB_CORTEXM_PRIORITY_MAX; + + //When MON_EN = 1, this steps the core + base = (unsigned long*)(GDB_DEBUG_REG_BASE + GDB_DEBUG_REG_DEMCR); + *base |= GDB_DEBUG_REG_DEMCR_MON_STEP; + + /* Clear any bits set in DFSR*/ + base = (unsigned long*)(GDB_NVIC_REG_BASE + GDB_NVIC_REG_DFSR); + *base = 0xffffffff; + +} + +void gdb_clear_single_step() +{ + volatile unsigned long *base; + + regs->basepri = single_step_basepri; + + /*clear single step*/ + base = (unsigned long*)(GDB_DEBUG_REG_BASE + GDB_DEBUG_REG_DEMCR); + *base &= ~GDB_DEBUG_REG_DEMCR_MON_STEP; + + // Clear any bits set in DFSR + base = (unsigned long*)(GDB_NVIC_REG_BASE + GDB_NVIC_REG_DFSR); + *base = 0xffffffff; + +} + +/** + * gdb_breakpoint - generate a breadk + * It is used to sync up with a debugger and stop progarm + */ +void gdb_breakpoint() +{ + volatile unsigned long *base; + + // Enable the FPB-FLASH PATCH BREAKPOINT + base = (unsigned long*)(GDB_FPB_REG_BASE + GDB_FPB_REG_CTRL); + *base |= GDB_FPB_REG_CTRL_KEY | GDB_FPB_REG_CTRL_ENABLE ; + + base = (unsigned long*)(GDB_DEBUG_REG_BASE + GDB_DEBUG_REG_DEMCR); + /* + * Enable the debug monitor. When enabled, the System handler priority + * register controls its priority level. + * If disabled, then all debug events go + * to Hard fault + */ + *base |= GDB_DEBUG_REG_DEMCR_MON_EN; + + // Enable DWT + *base |= GDB_DEBUG_REG_DEMCR_TRCENA ; + + //Fall into debug monitor + *base |= GDB_DEBUG_REG_DEMCR_MON_PEND; + +} + +void gdb_set_register(void *hw_regs) +{ + regs = hw_regs; +} + +void gdb_get_register(unsigned long *gdb_regs) +{ + int regno; + /* Initialize all to zero. */ + for (regno = 0; regno < GDB_MAX_REGS; regno++) + gdb_regs[regno] = 0; + + gdb_regs[GDB_R0] = regs->r0; + gdb_regs[GDB_R1] = regs->r1; + gdb_regs[GDB_R2] = regs->r2; + gdb_regs[GDB_R3] = regs->r3; + gdb_regs[GDB_R4] = regs->r4; + gdb_regs[GDB_R5] = regs->r5; + gdb_regs[GDB_R6] = regs->r6; + gdb_regs[GDB_R7] = regs->r7; + gdb_regs[GDB_R8] = regs->r8; + gdb_regs[GDB_R9] = regs->r9; + gdb_regs[GDB_R10] = regs->r10; + gdb_regs[GDB_FP] = regs->r11; + gdb_regs[GDB_IP] = regs->r12; + gdb_regs[GDB_SPT] = regs->sp; + gdb_regs[GDB_LR] = regs->lr; + gdb_regs[GDB_PC] = regs->pc; + gdb_regs[GDB_CPSR] = regs->psr; + +}; + + +void gdb_put_register(unsigned long *gdb_regs) +{ + regs->r0 = gdb_regs[GDB_R0]; + regs->r1 = gdb_regs[GDB_R1]; + regs->r2 = gdb_regs[GDB_R2]; + regs->r3 = gdb_regs[GDB_R3]; + + regs->r4 = gdb_regs[GDB_R4]; + regs->r5 = gdb_regs[GDB_R5]; + regs->r6 = gdb_regs[GDB_R6]; + regs->r7 = gdb_regs[GDB_R7]; + regs->r8 = gdb_regs[GDB_R8]; + regs->r9 = gdb_regs[GDB_R9]; + regs->r10 = gdb_regs[GDB_R10]; + regs->r11 = gdb_regs[GDB_FP]; + regs->r12 = gdb_regs[GDB_IP]; + regs->sp = gdb_regs[GDB_SPT]; + regs->lr = gdb_regs[GDB_LR]; + regs->pc = gdb_regs[GDB_PC]; + regs->psr = gdb_regs[GDB_CPSR]; + +} + + +/* It will be called during process_packet */ +int gdb_arch_handle_exception(char *remcom_in_buffer, + char *remcom_out_buffer) +{ + unsigned long addr; + char *ptr; + static int step = 0; + + if (step){ + gdb_clear_single_step(); + step = 0; + } + + switch (remcom_in_buffer[0]) { + case 'D': + case 'k': + case 'c': + /* + * If this was a compiled breakpoint, we need to move + * to the next instruction or we will breakpoint + * over and over again + */ + ptr = &remcom_in_buffer[1]; + if (gdb_hex2long(&ptr, &addr)) + regs->pc = addr; + + return 0; + case 's': + ptr = &remcom_in_buffer[1]; + if (gdb_hex2long(&ptr, &addr)) + regs->pc = addr; + + gdb_single_step(); + step = 1; + + return 0; + } + + return -1; + +} + +int gdb_set_hw_break(unsigned long addr, int len, enum gdb_bptype bptype) +{ + int i; + + if (bptype == BP_HARDWARE_BREAKPOINT) { + for (i = 0; i < HBP_NUM; i++) + if (!breakinfo[i].enabled) + break; + if (i == HBP_NUM) + return -1; + breakinfo[i].addr = addr; + breakinfo[i].enabled = 1; + } + else if (bptype == BP_WRITE_WATCHPOINT) { + for (i = 0; i < HWP_NUM; i++) + if (!watchinfo[i].enabled) + break; + if (i == HWP_NUM) + return -1; + watchinfo[i].addr = addr; + watchinfo[i].len = len; + watchinfo[i].type = BP_WRITE_WATCHPOINT; + watchinfo[i].enabled = 1; + } + else if (bptype == BP_READ_WATCHPOINT) { + for (i = 0; i < HWP_NUM; i++) + if (!watchinfo[i].enabled) + break; + if (i == HWP_NUM) + return -1; + watchinfo[i].addr = addr; + watchinfo[i].len = len; + watchinfo[i].type = BP_READ_WATCHPOINT; + watchinfo[i].enabled = 1; + } + else if (bptype == BP_ACCESS_WATCHPOINT) { + for (i = 0; i < HWP_NUM; i++) + if (!watchinfo[i].enabled) + break; + if (i == HWP_NUM) + return -1; + watchinfo[i].addr = addr; + watchinfo[i].len = len; + watchinfo[i].type = BP_ACCESS_WATCHPOINT; + watchinfo[i].enabled = 1; + } + + return 0; +} + +int gdb_remove_hw_break(unsigned long addr, int len, enum gdb_bptype bptype) +{ + int i; + + if (bptype == BP_HARDWARE_BREAKPOINT) { + for (i = 0; i < HBP_NUM; i++) + if (breakinfo[i].addr == addr && breakinfo[i].enabled) + break; + if (i == HBP_NUM) + return -1; + breakinfo[i].enabled = 0; + + } + else if (bptype == BP_WRITE_WATCHPOINT) { + for (i = 0; i < HWP_NUM; i++) + if (watchinfo[i].addr == addr && watchinfo[i].enabled && watchinfo[i].type == bptype) + break; + if (i == HWP_NUM) + return -1; + watchinfo[i].enabled = 0; + + } + else if (bptype == BP_READ_WATCHPOINT) { + for (i = 0; i < HWP_NUM; i++) + if (watchinfo[i].addr == addr && watchinfo[i].enabled && watchinfo[i].type == bptype) + break; + if (i == HWP_NUM) + return -1; + watchinfo[i].enabled = 0; + + } + else if (bptype == BP_ACCESS_WATCHPOINT) { + for (i = 0; i < HWP_NUM; i++) + if (watchinfo[i].addr == addr && watchinfo[i].enabled && watchinfo[i].type == bptype) + break; + if (i == HWP_NUM) + return -1; + watchinfo[i].enabled = 0; + + } + + return 0; +} + +void gdb_remove_all_hw_break() +{ + int i; + volatile unsigned long *base; + + // Disable hardware break + for (i = 0; i < HBP_NUM; i++) { + if (!breakinfo[i].enabled) + break; + base = (unsigned long*)(GDB_FPB_REG_BASE + GDB_FPB_REG_COMP + i * 4); + *base &= ~GDB_FPB_REG_COMP_ENABLE ; + } + + // Disable watchpoint + for (i = 0; i < HWP_NUM; i++) { + if (!watchinfo[i].enabled) + break; + base = (unsigned long*)(GDB_DWT_REG_BASE + GDB_DWT_REG_FUNCTION + i * 12); + *base &= ~GDB_DWT_REG_FUNCTION_FUC ; + } + +} + +void gdb_arch_late() +{ + gdb_remove_all_hw_break(); +} + +void gdb_arch_exit() +{ + volatile unsigned long *base; + char num = 1; + int i; + + // Install the hardware break + for (i = 0; i < HBP_NUM; i++) { + if (breakinfo[i].enabled) { + base = (unsigned long*)(GDB_FPB_REG_BASE + GDB_FPB_REG_COMP + i * 4); + + *base = GDB_FPB_REG_COMP_ADDR & ((unsigned long)(breakinfo[i].addr)); + + if (breakinfo[i].addr & 2) + *base |= (1UL << 31); //set BKPT on upper halfword + else + *base |= (1UL << 30); //set BKPT on lower halfword, + + *base |= GDB_FPB_REG_COMP_ENABLE ; + } + } + + // Install the watchpoint + for (i = 0; i < HWP_NUM; i++) { + if (watchinfo[i].enabled) { + base = (unsigned long*)(GDB_DWT_REG_BASE + GDB_DWT_REG_COMP + i * 12); + *base = watchinfo[i].addr; + + base = (unsigned long*)(GDB_DWT_REG_BASE + GDB_DWT_REG_MASK + i * 12); + while (watchinfo[i].len >> num) { + num++; + } + *base = num - 1; //DWT matching is performed as:(ADDR & (~0 << MASK)) == COMP + + base = (unsigned long*)(GDB_DWT_REG_BASE + GDB_DWT_REG_FUNCTION + i * 12); + + if (watchinfo[i].type == BP_WRITE_WATCHPOINT) + *base = (*base & ~GDB_DWT_REG_FUNCTION_FUC) + 0x05; + else if (watchinfo[i].type == BP_READ_WATCHPOINT) + *base = (*base & ~GDB_DWT_REG_FUNCTION_FUC) + 0x06; + else if (watchinfo[i].type == BP_ACCESS_WATCHPOINT) + *base = (*base & ~GDB_DWT_REG_FUNCTION_FUC) + 0x07; + + } + } + +} + diff --git a/components/gdb/libcpu/cortexm/gdb_gcc.S b/components/gdb/libcpu/cortexm/gdb_gcc.S new file mode 100644 index 0000000000..e6c5ab95e8 --- /dev/null +++ b/components/gdb/libcpu/cortexm/gdb_gcc.S @@ -0,0 +1,27 @@ +.cpu cortex-m4 +.syntax unified +.thumb +.text + +.global DebugMon_Handler +.type DebugMon_Handler, %function +DebugMon_Handler: + mrs r0,psp ;// Get process stack + sub r1,r0,#(4*13) ;// Make space for saved state + msr psp,r1 ;// Ensure PSP is up to date + + mov r12,r0 ;// R12 = stack + mov r1,#1 ;// R1 = exception state type + mrs r2,ipsr ;// R2 = vector number + mrs r3,basepri ;// R3 = basepri + stmfd r0!,{r1-r12,lr} ;// Push type, vector, basepri, r4-11 + + mov r4,r0 ;// R4 = saved state pointer + bl rt_hw_debugmon_exception + + mov r0,r4 ;// R4 = saved state pointer + ldmfd r0!,{r1-r12,lr} ;// Pop type, vec, basepri, registers and LR + msr psp,r0 ;// Restore PSP + msr basepri,r3 ;// Restore basepri + + bx lr ;// Return diff --git a/components/gdb/libcpu/cortexm/gdb_handler.c b/components/gdb/libcpu/cortexm/gdb_handler.c new file mode 100644 index 0000000000..05904224c2 --- /dev/null +++ b/components/gdb/libcpu/cortexm/gdb_handler.c @@ -0,0 +1,11 @@ +#include +#include + +void rt_hw_debugmon_exception(void *regs) +{ +#ifdef RT_USING_GDB + gdb_arch_late(); + gdb_handle_exception(SIGTRAP, regs); + gdb_arch_exit(); +#endif +} diff --git a/components/gdb/readme-zh.txt b/components/gdb/readme-zh.txt new file mode 100644 index 0000000000..06cdc01c76 --- /dev/null +++ b/components/gdb/readme-zh.txt @@ -0,0 +1,118 @@ +说明: + +一 当前版本进度 + +1).分类 +考虑到arm各种版本的调试寄存器地址和种类都有很大不同 +所以分为两个版本,均只在GCC下编译 + + 1.基础ARM(软件断点(使用undef指令的办法),需要ram运行,模拟单步) + 2.cortex M系列(不支持M0,基于寄存器操作,支持硬件断点,数据观察点,硬件单步) + +理论上cortexA系列和cortexM的调式单元是一样的,有需要的话也可以在基础arm版本里单独为cortexA做出可选的数据断点,硬件单步 + +二 安装说明 + +1) 下载 + 下载最新RT-THREAD GDB STUB代码,并解压 + +2) 加入RT-Thread + 先将得到的components文件夹覆盖RTT根目录 + 然后若要使用BBB板测试GDB,就用BSP/beaglebone和libpcu/am335x覆盖RTT下的同名文件夹 + + 若要使用STM32F407测试GDB,就用BSP/stm32F4xx覆盖RTT下的同名文件夹,同时更改编译器为gcc + +3) 宏 + 打开RT_USING_GDB + +三 宏配置说明 + +1) RT_GDB_HAVE_HWBP + 1硬件断点 + +2) RT_GDB_HAVE_SWBP + 1软件断点 + +3) RT_GDB_MAX_BREAKPOINTS + 最大软件断点数量 + 不加默认20 + +4) RT_GDB_ICACHE + 是否使用ICACHE + 若使用了ICACHE则要开启此宏,保证断点覆盖后及时刷新 + +5) RT_GDB_DEBUG + 测试开发用 + 会打印GDB收发信息到默认串口上,以供获取数据 + +四 使用说明 + +1) 设置serial设备 + 首先需要调用 + void gdb_set_device(const char* device_name); (gdb_stub.h) + 设置相应的GDB通信端口 + PS: + 首先serial的驱动不能是中断 + 其次收发函数最好是poll的,要不就是9600,不然可能会出现问题 + 若出现问题,请打开 RT_GDB_DEBUG ,观察收发是否正常。 + +2) 进入GDB stub + 调用 + void gdb_start(); (gdb_stub.h) + 触发异常,即可进入等待状态 等待GDB连接 + 也可以将该函数加入按键中断中,可以实现外部打断程序的效果(条件有限,未测试) + +3) pc连接 + 确认GCC 打开-g选项后编译 + 然后arm-none-eabi-gdb xxxx.elf or axf + 进如GDB界面后 + set serial baud 115200(or 9600) + target remote /dev/ttyUSB0(linux) or COM1 (windows) + 即可实现GDB对接 + +PS: + BBB板默认uart4作为GDB通信口 + STM32F407默认uart6作GDB通信 + +五 移植说明 + +若要移植到不同架构上 +软件实现请参考gdb/libcpu/arm下的文件 +硬件实现请参考gdb/libcpu/cortexm下的文件 +需要rsp协议的话 请参考https://www.sourceware.org/gdb/current/onlinedocs/gdb/Remote-Protocol.html + +若要移植到已有架构的芯片上 +1) arm9,11以及cortexA + 修改udef和dabt的函数,在/libcpu/arm/am335x/trap.c里,加入ifdef GDB的内容 + 将libcpu/arm/am335x/start_gcc.s的相关异常向量汇编复制到自己的undef和dabt异常向量里 + 分配足够的栈空间给undef + +2) cortexM3以及M4 + 删除已有的debugmon_handler + 优先级分组有变化的话,重定义宏GDB_CORTEXM_PRIORITY_MAX,就是basepri的设置值,满足屏蔽中断的同时不屏蔽debugmon + 使用有需要的话,重定义cortexm_stub.c的data_acess数组,也就是允许GDB访问的地址空间 + 增大_system_stack_size,也就是MSP栈的大小 + + +六 易错或者bug(出错了看这里) + +编译器选项是否打开-g,是否使用GCC编译 +硬件断点使用超过(max-1)个后,单步可能会出现不正常 +检查串口通信是否正常,可以打开RT_GDB_DEBUG +堆栈大小是否设置合适(因为gdb要在handler模式下运行,所需要的栈大小比较大,大概0x200) +cm系列切记如果优先级分组不同于默认设置,就要重定义宏GDB_CORTEXM_PRIORITY_MAX,使抢占优先级等于1,不然单步可能会出现问题(被中断抢占) +cm系列在中断里设置断点会出现错误(目测程序还是正常工作,就是压栈的寄存器还是进入中断前的,所以返回的寄存器信息有误) +cm系列可能会因为访问不可访问的地址造成出错,有需求自己手动修改cortexm_stub.c的data_acess数组(没找到好的办法,falut后寄存器全乱了) + + +## + 嫌速度慢的话就把串口速度9600改成115200 + 不过如此就要把注册的驱动里的getc改成阻塞的,不然会收不到 + 类似 + while(!(UART_LSR_REG(uart->base) & 0x01)); + ch = UART_RHR_REG(uart->base) & 0xff; + 原先是 + if (UART_LSR_REG(uart->base) & 0x01) + { + ch = UART_RHR_REG(uart->base) & 0xff; + } From ae3b6583ce6d2f5b6b02642805f6158f7e6b550b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=B1=AA?= <547884940@qq.com> Date: Tue, 12 Aug 2014 18:22:04 +0800 Subject: [PATCH 02/10] [bsp]add gdb support for stm32f4xx --- bsp/stm32f40x/applications/application.c | 10 ++++ bsp/stm32f40x/drivers/board.h | 1 + bsp/stm32f40x/drivers/stm32f4xx_it.c | 7 +-- bsp/stm32f40x/drivers/usart.c | 60 ++++++++++++++++++++++++ bsp/stm32f40x/rtconfig.h | 3 ++ bsp/stm32f40x/stm32_rom.ld | 2 +- 6 files changed, 79 insertions(+), 4 deletions(-) diff --git a/bsp/stm32f40x/applications/application.c b/bsp/stm32f40x/applications/application.c index 2a01107f6b..c5e5bcf296 100644 --- a/bsp/stm32f40x/applications/application.c +++ b/bsp/stm32f40x/applications/application.c @@ -23,8 +23,18 @@ #include "stm32_eth.h" #endif +#ifdef RT_USING_GDB +#include +#endif + void rt_init_thread_entry(void* parameter) { + /* GDB STUB */ +#ifdef RT_USING_GDB + gdb_set_device("uart6"); + gdb_start(); +#endif + /* LwIP Initialization */ #ifdef RT_USING_LWIP { diff --git a/bsp/stm32f40x/drivers/board.h b/bsp/stm32f40x/drivers/board.h index 44fef35cb3..33b423ae1c 100644 --- a/bsp/stm32f40x/drivers/board.h +++ b/bsp/stm32f40x/drivers/board.h @@ -43,6 +43,7 @@ //#define RT_USING_UART1 #define RT_USING_UART2 //#define RT_USING_UART3 +#define RT_USING_UART6 // Console on USART: <0=> no console <1=>USART 1 <2=>USART 2 <3=> USART 3 // Default: 1 diff --git a/bsp/stm32f40x/drivers/stm32f4xx_it.c b/bsp/stm32f40x/drivers/stm32f4xx_it.c index 69a6068746..b7a82e3302 100644 --- a/bsp/stm32f40x/drivers/stm32f4xx_it.c +++ b/bsp/stm32f40x/drivers/stm32f4xx_it.c @@ -117,9 +117,10 @@ void SVC_Handler(void) * @param None * @retval None */ -void DebugMon_Handler(void) -{ -} +//void DebugMon_Handler(void) +//{ + //definitio in gdb/libcpu/cortexm +//} /** * @brief This function handles PendSVC exception. diff --git a/bsp/stm32f40x/drivers/usart.c b/bsp/stm32f40x/drivers/usart.c index 6864a3fc92..8b87dbbb10 100644 --- a/bsp/stm32f40x/drivers/usart.c +++ b/bsp/stm32f40x/drivers/usart.c @@ -69,6 +69,17 @@ struct stm32_serial_device uart3 = struct rt_device uart3_device; #endif +#ifdef RT_USING_UART6 +struct stm32_serial_int_rx uart6_int_rx; +struct stm32_serial_device uart6 = +{ + USART6, + &uart6_int_rx, + RT_NULL +}; +struct rt_device uart6_device; +#endif + //#define USART1_DR_Base 0x40013804 //#define USART2_DR_Base 0x40004404 //#define USART3_DR_Base 0x40004804 @@ -103,6 +114,14 @@ struct rt_device uart3_device; #define UART3_TX_DMA DMA1_Stream1 #define UART3_RX_DMA DMA1_Stream3 +#define UART6_GPIO_TX GPIO_Pin_6 +#define UART6_TX_PIN_SOURCE GPIO_PinSource6 +#define UART6_GPIO_RX GPIO_Pin_7 +#define UART6_RX_PIN_SOURCE GPIO_PinSource7 +#define UART6_GPIO GPIOC +#define UART6_GPIO_RCC RCC_AHB1Periph_GPIOC +#define RCC_APBPeriph_UART6 RCC_APB2Periph_USART6 + static void RCC_Configuration(void) { #ifdef RT_USING_UART1 @@ -128,6 +147,13 @@ static void RCC_Configuration(void) /* DMA clock enable */ RCC_APB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); #endif + +#ifdef RT_USING_UART6 + /* Enable USART6 GPIO clocks */ + RCC_AHB1PeriphClockCmd(UART6_GPIO_RCC, ENABLE); + /* Enable USART6 clock */ + RCC_APB2PeriphClockCmd(RCC_APBPeriph_UART6, ENABLE); +#endif } static void GPIO_Configuration(void) @@ -168,6 +194,16 @@ static void GPIO_Configuration(void) GPIO_PinAFConfig(UART3_GPIO, UART3_TX_PIN_SOURCE, GPIO_AF_USART3); GPIO_PinAFConfig(UART3_GPIO, UART3_RX_PIN_SOURCE, GPIO_AF_USART3); #endif + +#ifdef RT_USING_UART6 + /* Configure USART6 Rx/tx PIN */ + GPIO_InitStructure.GPIO_Pin = UART6_GPIO_TX | UART6_GPIO_RX; + GPIO_Init(UART6_GPIO, &GPIO_InitStructure); + + /* Connect alternate function */ + GPIO_PinAFConfig(UART6_GPIO, UART6_TX_PIN_SOURCE, GPIO_AF_USART6); + GPIO_PinAFConfig(UART6_GPIO, UART6_RX_PIN_SOURCE, GPIO_AF_USART6); +#endif } static void NVIC_Configuration(void) @@ -204,6 +240,15 @@ static void NVIC_Configuration(void) NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); #endif + +#ifdef RT_USING_UART6 + /* Enable the USART6 Interrupt */ + NVIC_InitStructure.NVIC_IRQChannel = USART6_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); +#endif } static void DMA_Configuration(void) @@ -346,4 +391,19 @@ void rt_hw_usart_init() /* enable interrupt */ USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); #endif + +#ifdef RT_USING_UART6 + USART_InitStructure.USART_BaudRate = 9600; + USART_InitStructure.USART_WordLength = USART_WordLength_8b; + USART_InitStructure.USART_StopBits = USART_StopBits_1; + USART_InitStructure.USART_Parity = USART_Parity_No; + USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; + USART_Init(USART6, &USART_InitStructure); + + /* register uart6 */ + rt_hw_serial_register(&uart6_device, "uart6", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STREAM, + &uart6); +#endif } diff --git a/bsp/stm32f40x/rtconfig.h b/bsp/stm32f40x/rtconfig.h index e961fb2e8f..64cc047ad8 100644 --- a/bsp/stm32f40x/rtconfig.h +++ b/bsp/stm32f40x/rtconfig.h @@ -2,6 +2,9 @@ #ifndef __RTTHREAD_CFG_H__ #define __RTTHREAD_CFG_H__ +/* RT_GDB_STUB */ +//#define RT_USING_GDB + /* RT_NAME_MAX*/ #define RT_NAME_MAX 8 diff --git a/bsp/stm32f40x/stm32_rom.ld b/bsp/stm32f40x/stm32_rom.ld index bd2ef9fe44..aa9c9b2af2 100644 --- a/bsp/stm32f40x/stm32_rom.ld +++ b/bsp/stm32f40x/stm32_rom.ld @@ -10,7 +10,7 @@ MEMORY DATA (rw) : ORIGIN = 0x20000000, LENGTH = 128k /* 128K sram */ } ENTRY(Reset_Handler) -_system_stack_size = 0x100; +_system_stack_size = 0x200; SECTIONS { From fd6ef4b2350eafd9ffc48f835d479ebc52330024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=B1=AA?= <547884940@qq.com> Date: Tue, 12 Aug 2014 18:26:22 +0800 Subject: [PATCH 03/10] [libcpu]am335x edit vector vector_undef and vector_dabt --- libcpu/arm/am335x/start_gcc.S | 24 ++++++++++++++++++++++-- libcpu/arm/am335x/trap.c | 18 ++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/libcpu/arm/am335x/start_gcc.S b/libcpu/arm/am335x/start_gcc.S index 6d9ec8be25..f80aca6223 100644 --- a/libcpu/arm/am335x/start_gcc.S +++ b/libcpu/arm/am335x/start_gcc.S @@ -33,7 +33,7 @@ .equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled .equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled -.equ UND_Stack_Size, 0x00000000 +.equ UND_Stack_Size, 0x00000200 .equ SVC_Stack_Size, 0x00000100 .equ ABT_Stack_Size, 0x00000000 .equ FIQ_Stack_Size, 0x00000000 @@ -135,7 +135,15 @@ vector_undef: sub sp, sp, #72 stmia sp, {r0 - r12} @/* Calling r0-r12 */ add r8, sp, #60 - stmdb r8, {sp, lr} @/* Calling SP, LR */ + + mrs r1, cpsr + mrs r2, spsr + orr r2,r2, #I_Bit|F_Bit + msr cpsr_c, r2 + mov r0, r0 + stmdb r8, {sp, lr} @/* Calling SP, LR */ + msr cpsr_c, r1 @/* return to Undefined Instruction mode */ + str lr, [r8, #0] @/* Save calling PC */ mrs r6, spsr str r6, [r8, #4] @/* Save CPSR */ @@ -144,6 +152,12 @@ vector_undef: bl rt_hw_trap_udef + ldmia sp, {r0 - r12} @/* Calling r0 - r2 */ + mov r0, r0 + ldr lr, [sp, #60] @/* Get PC */ + add sp, sp, #72 + movs pc, lr @/* return & move spsr_svc into cpsr */ + .align 5 .globl vector_swi vector_swi: @@ -169,6 +183,12 @@ vector_dabt: bl rt_hw_trap_dabt + ldmia sp, {r0 - r12} @/* Calling r0 - r2 */ + mov r0, r0 + ldr lr, [sp, #60] @/* Get PC */ + add sp, sp, #72 + movs pc, lr @/* return & move spsr_svc into cpsr */ + .align 5 .globl vector_resv vector_resv: diff --git a/libcpu/arm/am335x/trap.c b/libcpu/arm/am335x/trap.c index 925ec56434..89dc14255a 100644 --- a/libcpu/arm/am335x/trap.c +++ b/libcpu/arm/am335x/trap.c @@ -18,6 +18,10 @@ #include "am33xx.h" #include "interrupt.h" +#ifdef RT_USING_GDB +#include "gdb_stub.h" +#endif + /** * @addtogroup AM33XX */ @@ -55,6 +59,13 @@ void rt_hw_show_register (struct rt_hw_register *regs) */ void rt_hw_trap_udef(struct rt_hw_register *regs) { + +#ifdef RT_USING_GDB + regs->pc -= 4; //lr in undef is pc + 4 + if (gdb_undef_hook(regs)) + return; +#endif + rt_hw_show_register(regs); rt_kprintf("undefined instruction\n"); @@ -114,6 +125,13 @@ void rt_hw_trap_pabt(struct rt_hw_register *regs) */ void rt_hw_trap_dabt(struct rt_hw_register *regs) { + +#ifdef RT_USING_GDB + if (gdb_mem_fault_handler) { + regs->pc = (unsigned long)gdb_mem_fault_handler; + return; + } +#endif rt_hw_show_register(regs); rt_kprintf("data abort\n"); From a966dd3c3802198cf84adbd8aef08d9206e256ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=B1=AA?= <547884940@qq.com> Date: Tue, 12 Aug 2014 18:27:22 +0800 Subject: [PATCH 04/10] [bsp]add gdb support for BBB --- bsp/beaglebone/applications/application.c | 8 +++++ bsp/beaglebone/drivers/serial.c | 42 +++++++++++++++++++++-- bsp/beaglebone/rtconfig.h | 6 ++++ bsp/beaglebone/rtconfig.py | 2 +- 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/bsp/beaglebone/applications/application.c b/bsp/beaglebone/applications/application.c index 99c2991df7..f34821e748 100644 --- a/bsp/beaglebone/applications/application.c +++ b/bsp/beaglebone/applications/application.c @@ -16,6 +16,10 @@ #include #include +#ifdef RT_USING_GDB +#include +#endif + int rt_application_init() { /* do component initialization */ @@ -23,6 +27,10 @@ int rt_application_init() #ifdef RT_USING_NEWLIB libc_system_init(RT_CONSOLE_DEVICE_NAME); #endif +#ifdef RT_USING_GDB + gdb_set_device("uart4"); + gdb_start(); +#endif return 0; } diff --git a/bsp/beaglebone/drivers/serial.c b/bsp/beaglebone/drivers/serial.c index 8dcd389123..1cc0e69a85 100644 --- a/bsp/beaglebone/drivers/serial.c +++ b/bsp/beaglebone/drivers/serial.c @@ -338,6 +338,42 @@ static void config_pinmux(void) #endif } +static int am33xx_putc_poll(struct rt_serial_device *serial, char c) +{ + struct am33xx_uart* uart; + + RT_ASSERT(serial != RT_NULL); + uart = (struct am33xx_uart *)serial->parent.user_data; + + while (!(UART_LSR_REG(uart->base) & 0x20)); + UART_THR_REG(uart->base) = c; + + return 1; +} + +static int am33xx_getc_poll(struct rt_serial_device *serial) +{ + int ch; + struct am33xx_uart* uart; + + RT_ASSERT(serial != RT_NULL); + uart = (struct am33xx_uart *)serial->parent.user_data; + + ch = -1; + while(!(UART_LSR_REG(uart->base) & 0x01)); + ch = UART_RHR_REG(uart->base) & 0xff; + + return ch; +} + +static const struct rt_uart_ops am33xx_gdb_ops = +{ + am33xx_configure, + am33xx_control, + am33xx_putc_poll, + am33xx_getc_poll, +}; + int rt_hw_serial_init(void) { struct serial_configure config; @@ -447,17 +483,17 @@ int rt_hw_serial_init(void) config.invert = NRZ_NORMAL; config.bufsz = RT_SERIAL_RB_BUFSZ; - serial4.ops = &am33xx_uart_ops; + serial4.ops = &am33xx_gdb_ops; serial4.config = config; /* enable RX interrupt */ - UART_IER_REG(uart4.base) = 0x01; + UART_IER_REG(uart4.base) = 0x00; /* install ISR */ rt_hw_interrupt_install(uart4.irq, am33xx_uart_isr, &serial4, "uart4"); rt_hw_interrupt_control(uart4.irq, 0, 0); rt_hw_interrupt_mask(uart4.irq); /* register UART4 device */ rt_hw_serial_register(&serial4, "uart4", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STREAM, &uart4); #endif diff --git a/bsp/beaglebone/rtconfig.h b/bsp/beaglebone/rtconfig.h index 15326d74cf..018b2862f1 100644 --- a/bsp/beaglebone/rtconfig.h +++ b/bsp/beaglebone/rtconfig.h @@ -2,6 +2,12 @@ #ifndef __RTTHREAD_CFG_H__ #define __RTTHREAD_CFG_H__ +//
+//#define RT_USING_GDB +//#define RT_GDB_DEBUG +#define RT_GDB_ICACHE +//
+ // // diff --git a/bsp/beaglebone/rtconfig.py b/bsp/beaglebone/rtconfig.py index 3c7f228d86..a5561f54d3 100644 --- a/bsp/beaglebone/rtconfig.py +++ b/bsp/beaglebone/rtconfig.py @@ -23,7 +23,7 @@ elif CROSS_TOOL == 'iar': if os.getenv('RTT_EXEC_PATH'): EXEC_PATH = os.getenv('RTT_EXEC_PATH') -BUILD = 'release' +BUILD = 'debug' if PLATFORM == 'gcc': # toolchains From ae8e46de1ff7386c5add04e8ee3830fc71042306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=B1=AA?= <547884940@qq.com> Date: Tue, 12 Aug 2014 18:27:50 +0800 Subject: [PATCH 05/10] Revert "[bsp]add gdb support for BBB" This reverts commit a966dd3c3802198cf84adbd8aef08d9206e256ce. --- bsp/beaglebone/applications/application.c | 8 ----- bsp/beaglebone/drivers/serial.c | 42 ++--------------------- bsp/beaglebone/rtconfig.h | 6 ---- bsp/beaglebone/rtconfig.py | 2 +- 4 files changed, 4 insertions(+), 54 deletions(-) diff --git a/bsp/beaglebone/applications/application.c b/bsp/beaglebone/applications/application.c index f34821e748..99c2991df7 100644 --- a/bsp/beaglebone/applications/application.c +++ b/bsp/beaglebone/applications/application.c @@ -16,10 +16,6 @@ #include #include -#ifdef RT_USING_GDB -#include -#endif - int rt_application_init() { /* do component initialization */ @@ -27,10 +23,6 @@ int rt_application_init() #ifdef RT_USING_NEWLIB libc_system_init(RT_CONSOLE_DEVICE_NAME); #endif -#ifdef RT_USING_GDB - gdb_set_device("uart4"); - gdb_start(); -#endif return 0; } diff --git a/bsp/beaglebone/drivers/serial.c b/bsp/beaglebone/drivers/serial.c index 1cc0e69a85..8dcd389123 100644 --- a/bsp/beaglebone/drivers/serial.c +++ b/bsp/beaglebone/drivers/serial.c @@ -338,42 +338,6 @@ static void config_pinmux(void) #endif } -static int am33xx_putc_poll(struct rt_serial_device *serial, char c) -{ - struct am33xx_uart* uart; - - RT_ASSERT(serial != RT_NULL); - uart = (struct am33xx_uart *)serial->parent.user_data; - - while (!(UART_LSR_REG(uart->base) & 0x20)); - UART_THR_REG(uart->base) = c; - - return 1; -} - -static int am33xx_getc_poll(struct rt_serial_device *serial) -{ - int ch; - struct am33xx_uart* uart; - - RT_ASSERT(serial != RT_NULL); - uart = (struct am33xx_uart *)serial->parent.user_data; - - ch = -1; - while(!(UART_LSR_REG(uart->base) & 0x01)); - ch = UART_RHR_REG(uart->base) & 0xff; - - return ch; -} - -static const struct rt_uart_ops am33xx_gdb_ops = -{ - am33xx_configure, - am33xx_control, - am33xx_putc_poll, - am33xx_getc_poll, -}; - int rt_hw_serial_init(void) { struct serial_configure config; @@ -483,17 +447,17 @@ int rt_hw_serial_init(void) config.invert = NRZ_NORMAL; config.bufsz = RT_SERIAL_RB_BUFSZ; - serial4.ops = &am33xx_gdb_ops; + serial4.ops = &am33xx_uart_ops; serial4.config = config; /* enable RX interrupt */ - UART_IER_REG(uart4.base) = 0x00; + UART_IER_REG(uart4.base) = 0x01; /* install ISR */ rt_hw_interrupt_install(uart4.irq, am33xx_uart_isr, &serial4, "uart4"); rt_hw_interrupt_control(uart4.irq, 0, 0); rt_hw_interrupt_mask(uart4.irq); /* register UART4 device */ rt_hw_serial_register(&serial4, "uart4", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STREAM, + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, &uart4); #endif diff --git a/bsp/beaglebone/rtconfig.h b/bsp/beaglebone/rtconfig.h index 018b2862f1..15326d74cf 100644 --- a/bsp/beaglebone/rtconfig.h +++ b/bsp/beaglebone/rtconfig.h @@ -2,12 +2,6 @@ #ifndef __RTTHREAD_CFG_H__ #define __RTTHREAD_CFG_H__ -//
-//#define RT_USING_GDB -//#define RT_GDB_DEBUG -#define RT_GDB_ICACHE -//
- // // diff --git a/bsp/beaglebone/rtconfig.py b/bsp/beaglebone/rtconfig.py index a5561f54d3..3c7f228d86 100644 --- a/bsp/beaglebone/rtconfig.py +++ b/bsp/beaglebone/rtconfig.py @@ -23,7 +23,7 @@ elif CROSS_TOOL == 'iar': if os.getenv('RTT_EXEC_PATH'): EXEC_PATH = os.getenv('RTT_EXEC_PATH') -BUILD = 'debug' +BUILD = 'release' if PLATFORM == 'gcc': # toolchains From 4cf77e255fc12d5ddda5f049f674c34ad9a18249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=B1=AA?= <547884940@qq.com> Date: Tue, 12 Aug 2014 18:39:53 +0800 Subject: [PATCH 06/10] [bsp]add gdb support for BBB --- bsp/beaglebone/applications/application.c | 8 ++++++++ bsp/beaglebone/drivers/serial.c | 11 ++++++++--- bsp/beaglebone/rtconfig.h | 6 ++++++ bsp/beaglebone/rtconfig.py | 2 +- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/bsp/beaglebone/applications/application.c b/bsp/beaglebone/applications/application.c index 99c2991df7..f34821e748 100644 --- a/bsp/beaglebone/applications/application.c +++ b/bsp/beaglebone/applications/application.c @@ -16,6 +16,10 @@ #include #include +#ifdef RT_USING_GDB +#include +#endif + int rt_application_init() { /* do component initialization */ @@ -23,6 +27,10 @@ int rt_application_init() #ifdef RT_USING_NEWLIB libc_system_init(RT_CONSOLE_DEVICE_NAME); #endif +#ifdef RT_USING_GDB + gdb_set_device("uart4"); + gdb_start(); +#endif return 0; } diff --git a/bsp/beaglebone/drivers/serial.c b/bsp/beaglebone/drivers/serial.c index 8dcd389123..ee657a0d8f 100644 --- a/bsp/beaglebone/drivers/serial.c +++ b/bsp/beaglebone/drivers/serial.c @@ -80,6 +80,11 @@ static rt_err_t am33xx_configure(struct rt_serial_device *serial, struct serial_ UART_DLL_REG(base) = 26; UART_DLH_REG(base) = 0; } + else if (cfg->baud_rate == BAUD_RATE_9600) + { + UART_DLL_REG(base) = 0x38; + UART_DLH_REG(base) = 1; + } else { NOT_IMPLEMENTED(); @@ -439,7 +444,7 @@ int rt_hw_serial_init(void) #endif #ifdef RT_USING_UART4 - config.baud_rate = BAUD_RATE_115200; + config.baud_rate = BAUD_RATE_9600; config.bit_order = BIT_ORDER_LSB; config.data_bits = DATA_BITS_8; config.parity = PARITY_NONE; @@ -450,14 +455,14 @@ int rt_hw_serial_init(void) serial4.ops = &am33xx_uart_ops; serial4.config = config; /* enable RX interrupt */ - UART_IER_REG(uart4.base) = 0x01; + UART_IER_REG(uart4.base) = 0x00; /* install ISR */ rt_hw_interrupt_install(uart4.irq, am33xx_uart_isr, &serial4, "uart4"); rt_hw_interrupt_control(uart4.irq, 0, 0); rt_hw_interrupt_mask(uart4.irq); /* register UART4 device */ rt_hw_serial_register(&serial4, "uart4", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STREAM, &uart4); #endif diff --git a/bsp/beaglebone/rtconfig.h b/bsp/beaglebone/rtconfig.h index 15326d74cf..018b2862f1 100644 --- a/bsp/beaglebone/rtconfig.h +++ b/bsp/beaglebone/rtconfig.h @@ -2,6 +2,12 @@ #ifndef __RTTHREAD_CFG_H__ #define __RTTHREAD_CFG_H__ +//
+//#define RT_USING_GDB +//#define RT_GDB_DEBUG +#define RT_GDB_ICACHE +//
+ // // diff --git a/bsp/beaglebone/rtconfig.py b/bsp/beaglebone/rtconfig.py index 3c7f228d86..a5561f54d3 100644 --- a/bsp/beaglebone/rtconfig.py +++ b/bsp/beaglebone/rtconfig.py @@ -23,7 +23,7 @@ elif CROSS_TOOL == 'iar': if os.getenv('RTT_EXEC_PATH'): EXEC_PATH = os.getenv('RTT_EXEC_PATH') -BUILD = 'release' +BUILD = 'debug' if PLATFORM == 'gcc': # toolchains From 1f05b87e5a7b84e170ee287998ecb0b1f814445d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=B1=AA?= <547884940@qq.com> Date: Tue, 12 Aug 2014 20:30:55 +0800 Subject: [PATCH 07/10] [bsp]stm32f4xx typo --- bsp/stm32f40x/drivers/stm32f4xx_it.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bsp/stm32f40x/drivers/stm32f4xx_it.c b/bsp/stm32f40x/drivers/stm32f4xx_it.c index b7a82e3302..6c4ea2226a 100644 --- a/bsp/stm32f40x/drivers/stm32f4xx_it.c +++ b/bsp/stm32f40x/drivers/stm32f4xx_it.c @@ -119,7 +119,7 @@ void SVC_Handler(void) */ //void DebugMon_Handler(void) //{ - //definitio in gdb/libcpu/cortexm + // defined in gdb/libcpu/cortexm/gdb_gcc.S //} /** @@ -129,7 +129,7 @@ void SVC_Handler(void) */ //void PendSV_Handler(void) //{ -// // definition in libcpu/arm/cortex-m4/context_*.S +// // defined in libcpu/arm/cortex-m4/context_*.S //} /** @@ -139,7 +139,7 @@ void SVC_Handler(void) */ //void SysTick_Handler(void) //{ -// // definition in boarc.c +// // defined in boarc.c //} /******************************************************************************/ From 2a1e7d56fcca3132ebed9496a46b0794f9bd107c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=B1=AA?= <547884940@qq.com> Date: Sat, 20 Sep 2014 01:44:56 +0800 Subject: [PATCH 08/10] [bsp]Comment stm32f407 uart6 --- bsp/stm32f40x/drivers/board.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bsp/stm32f40x/drivers/board.h b/bsp/stm32f40x/drivers/board.h index 33b423ae1c..b3a1cb4a08 100644 --- a/bsp/stm32f40x/drivers/board.h +++ b/bsp/stm32f40x/drivers/board.h @@ -43,7 +43,7 @@ //#define RT_USING_UART1 #define RT_USING_UART2 //#define RT_USING_UART3 -#define RT_USING_UART6 +//#define RT_USING_UART6 // Console on USART: <0=> no console <1=>USART 1 <2=>USART 2 <3=> USART 3 // Default: 1 From dd7fff2b31f3c4af0e6599beb7c662579d6f6740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=B1=AA?= <547884940@qq.com> Date: Sat, 20 Sep 2014 20:53:17 +0800 Subject: [PATCH 09/10] [gdb]Change open flag --- components/gdb/hal_stub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/gdb/hal_stub.c b/components/gdb/hal_stub.c index 077c4088f7..8cf4a31a51 100644 --- a/components/gdb/hal_stub.c +++ b/components/gdb/hal_stub.c @@ -67,7 +67,7 @@ void gdb_set_device(const char* device_name) } /* open this device and set the new device */ - if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR) == RT_EOK) + if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM) == RT_EOK) { gdb_dev = dev; gdb_serial = (struct rt_serial_device *)gdb_dev; From daac5388afe5a18d51e9839719de8423b62b00c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=B1=AA?= <547884940@qq.com> Date: Sat, 20 Sep 2014 20:56:02 +0800 Subject: [PATCH 10/10] [bsp]change BBB uart flag --- bsp/beaglebone/drivers/serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bsp/beaglebone/drivers/serial.c b/bsp/beaglebone/drivers/serial.c index ee657a0d8f..1ecd96ced6 100644 --- a/bsp/beaglebone/drivers/serial.c +++ b/bsp/beaglebone/drivers/serial.c @@ -462,7 +462,7 @@ int rt_hw_serial_init(void) rt_hw_interrupt_mask(uart4.irq); /* register UART4 device */ rt_hw_serial_register(&serial4, "uart4", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STREAM, + RT_DEVICE_FLAG_RDWR, &uart4); #endif