From 0e64ede5388eaba52b006201defc6b4b3376aad0 Mon Sep 17 00:00:00 2001 From: Marcin Rajwa Date: Tue, 5 Feb 2019 14:31:50 +0100 Subject: [PATCH 01/11] GDB: Added support for insert breakpoint. Signed-off-by: Marcin Rajwa --- src/gdb/gdb.c | 101 ++++++++++++++++++++++++++++++-------- src/include/sof/gdb/gdb.h | 2 +- 2 files changed, 81 insertions(+), 22 deletions(-) diff --git a/src/gdb/gdb.c b/src/gdb/gdb.c index 9c19378a16d0..2efcbcb31e4e 100644 --- a/src/gdb/gdb.c +++ b/src/gdb/gdb.c @@ -48,6 +48,7 @@ static void put_packet(unsigned char *buffer); static void parse_request(void); static unsigned char *get_packet(void); static void gdb_log_exception(char *message); +static void write_sr(int sr); /* main buffers */ static unsigned char remcom_in_buffer[GDB_BUFMAX]; @@ -144,32 +145,74 @@ void gdb_handle_exception(void) void parse_request(void) { unsigned char *request; + unsigned int i; int addr; - - while (1) { - request = get_packet(); - /* Log any exception caused by debug exception */ - gdb_debug_info(request); - - /* Pick incoming request handler */ - unsigned char command = *request++; - - switch (command) { - /* Continue normal program execution and leave debug handler */ - case 'c': - if (hex_to_int(&request, &addr)) - sregs[DEBUG_PC] = addr; - - /* return from exception */ - return; + int length; + +while (1) { + request = get_packet(); + /* Log any exception caused by debug exception */ + gdb_debug_info(request); + /* Pick incoming request handler */ + unsigned char command = *request++; + + switch (command) { + /* Continue normal program execution and leave debug handler */ + case 'c': + if (hex_to_int(&request, &addr)) + sregs[DEBUG_PC] = addr; + + /* return from exception */ + return; + /* insert breakpoint */ + case 'Z': + switch (*request++) { + /* HW breakpoint */ + case '1': + if (*request++ == ',' && hex_to_int(&request, &addr) && + *request++ == ',' && hex_to_int(&request, &length) + && *request == 0) { + for (i = 0; i < XCHAL_NUM_IBREAK; ++i) { + if (!(sregs[IBREAKENABLE] & (1 << i)) || + sregs[IBREAKA + i] == addr) { + sregs[IBREAKA + i] = addr; + sregs[IBREAKENABLE] |= (1 << i); + write_sr(IBREAKA+i); + write_sr(IBREAKENABLE); + break; + } + } + + if (i == XCHAL_NUM_IBREAK) { + strcpy((char *) remcom_out_buffer, + "E02"); + } else { + strcpy((char *)remcom_out_buffer, "OK"); + sregs[INTENABLE] &= + DISABLE_LOWER_INTERRUPTS_MASK; + write_sr(INTENABLE); + } + } else { + strcpy((char *)remcom_out_buffer, "E01"); + } + break; + /* SW breakpoints */ default: - gdb_log_exception("Unknown GDB command."); + /* send empty response to indicate thet SW breakpoints + * are not supported + */ + strcpy((char *)remcom_out_buffer, ""); break; - } - /* reply to the request */ - put_packet(remcom_out_buffer); + break; + default: + gdb_log_exception("Unknown GDB command."); + break; + } + /* reply to the request */ + put_packet(remcom_out_buffer); +} } /* @@ -232,3 +275,19 @@ static void gdb_log_exception(char *message) put_exception_char(*message++); } + +static void write_sr(int sr) +{ +#ifdef __XTENSA__ + asm volatile ("movi a3, 1f + 1\n" + "s8i %1, a3, 0\n" + "dhwb a3, 0\n" + "ihi a3, 0\n" + "isync\n" + "1:\n" + "wsr %0, lbeg\n" + : + : "r"(sregs[sr]), "r"(sr) + : "a3", "memory"); +#endif +} diff --git a/src/include/sof/gdb/gdb.h b/src/include/sof/gdb/gdb.h index 599cfa02335c..02e055049cd4 100644 --- a/src/include/sof/gdb/gdb.h +++ b/src/include/sof/gdb/gdb.h @@ -3,7 +3,7 @@ #define GDB_BUFMAX 256 #define GDB_NUMBER_OF_REGISTERS 64 - +#define DISABLE_LOWER_INTERRUPTS_MASK ~0x1F void gdb_handle_exception(void); void gdb_debug_info(unsigned char *str); void gdb_init_debug_exception(void); From 948ad84b968e44c89edea3a7e40756af24a67981 Mon Sep 17 00:00:00 2001 From: Marcin Rajwa Date: Tue, 5 Feb 2019 14:46:29 +0100 Subject: [PATCH 02/11] GDB: Added the possibility to remove breakpoints. Signed-off-by: Marcin Rajwa --- src/gdb/gdb.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/gdb/gdb.c b/src/gdb/gdb.c index 2efcbcb31e4e..0419c4581d0b 100644 --- a/src/gdb/gdb.c +++ b/src/gdb/gdb.c @@ -205,6 +205,39 @@ while (1) { break; } break; + case 'z': /* remove HW breakpoint */ + switch (*request++) { + /* remove HW breakpoint */ + case '1': + if (*request++ == ',' && hex_to_int(&request, &addr) && + *request++ == ',' && hex_to_int(&request, &length)) { + for (i = 0; i < XCHAL_NUM_IBREAK; ++i) { + if (sregs[IBREAKENABLE] & (1 << i) && + sregs[IBREAKA + i] == addr) { + sregs[IBREAKENABLE] + &= ~(1 << i); + write_sr(IBREAKENABLE); + break; + } + } + if (i == XCHAL_NUM_IBREAK) + strcpy((char *)remcom_out_buffer, + "E02"); + else + strcpy((char *)remcom_out_buffer, "OK"); + } else { + strcpy((char *)remcom_out_buffer, "E01"); + } + break; + /* SW breakpoints */ + default: + /* send empty response to indicate thet SW breakpoints + * are not supported + */ + strcpy((char *)remcom_out_buffer, ""); + break; + } + break; default: gdb_log_exception("Unknown GDB command."); break; From 5e9b3b8aad180b9418e2ac34a15c1a7b55e8f34f Mon Sep 17 00:00:00 2001 From: Marcin Rajwa Date: Tue, 5 Feb 2019 14:53:03 +0100 Subject: [PATCH 03/11] GDB: Added support for single step. Signed-off-by: Marcin Rajwa --- src/gdb/gdb.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/gdb/gdb.c b/src/gdb/gdb.c index 0419c4581d0b..d7a42f549ec8 100644 --- a/src/gdb/gdb.c +++ b/src/gdb/gdb.c @@ -205,7 +205,8 @@ while (1) { break; } break; - case 'z': /* remove HW breakpoint */ + /* remove HW breakpoint */ + case 'z': switch (*request++) { /* remove HW breakpoint */ case '1': @@ -238,6 +239,19 @@ while (1) { break; } break; + /* Single step in the code */ + case 's': + if (hex_to_int(&request, &addr)) + sregs[DEBUG_PC] = addr; + /* leave debug just for one instruction */ + sregs[ICOUNT] = 0xfffffffe; + sregs[ICOUNTLEVEL] = XCHAL_DEBUGLEVEL; + /* disable low level interrupts */ + sregs[INTENABLE] &= ~DISABLE_LOWER_INTERRUPTS_MASK; + write_sr(ICOUNTLEVEL); + write_sr(ICOUNT); + write_sr(INTENABLE); + return; default: gdb_log_exception("Unknown GDB command."); break; From bc90831c7c23c37c3a3a3bdcb66cf27347ba8427 Mon Sep 17 00:00:00 2001 From: Marcin Rajwa Date: Tue, 5 Feb 2019 15:32:31 +0100 Subject: [PATCH 04/11] GDB: Added support for register read. Signed-off-by: Marcin Rajwa --- src/gdb/gdb.c | 85 ++++++++++++++++++++++++++++++++++++++- src/include/sof/gdb/gdb.h | 1 + 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/src/gdb/gdb.c b/src/gdb/gdb.c index d7a42f549ec8..323c25e61e5c 100644 --- a/src/gdb/gdb.c +++ b/src/gdb/gdb.c @@ -49,7 +49,9 @@ static void parse_request(void); static unsigned char *get_packet(void); static void gdb_log_exception(char *message); static void write_sr(int sr); - +static unsigned char *mem_to_hex(const void *mem_, + unsigned char *buf, int count); +static void read_sr(int sr); /* main buffers */ static unsigned char remcom_in_buffer[GDB_BUFMAX]; static unsigned char remcom_out_buffer[GDB_BUFMAX]; @@ -148,6 +150,8 @@ void parse_request(void) unsigned int i; int addr; int length; + unsigned int windowbase = (4 * sregs[WINDOWBASE]); + while (1) { request = get_packet(); @@ -239,7 +243,7 @@ while (1) { break; } break; - /* Single step in the code */ + /* single step in the code */ case 's': if (hex_to_int(&request, &addr)) sregs[DEBUG_PC] = addr; @@ -252,6 +256,32 @@ while (1) { write_sr(ICOUNT); write_sr(INTENABLE); return; + /* read register */ + case 'p': + if (hex_to_int(&request, &addr)) { + /* read address register in the current window */ + if (addr < 0x10) { + mem_to_hex(aregs + addr, remcom_out_buffer, 4); + } else if (addr == 0x20) { /* read PC */ + mem_to_hex(sregs + DEBUG_PC, + remcom_out_buffer, 4); + } else if (addr >= 0x100 && + addr < (0x100 + XCHAL_NUM_AREGS)) { + mem_to_hex(aregs + ((addr - windowbase) & + REGISTER_MASK), remcom_out_buffer, 4); + } else if (addr >= 0x200 && addr < 0x300) { + /* read special registers */ + addr &= REGISTER_MASK; + read_sr(addr); + mem_to_hex(sregs + addr, remcom_out_buffer, 4); + } else if (addr >= 0x300 && addr < 0x400) { + strcpy((char *)remcom_out_buffer, + "out of scope"); + } else { /* unexpected register number */ + strcpy((char *)remcom_out_buffer, "E00"); + } + } + break; default: gdb_log_exception("Unknown GDB command."); break; @@ -338,3 +368,54 @@ static void write_sr(int sr) : "a3", "memory"); #endif } + +/* Convert the memory pointed to by mem into hex, placing result in buf. + * Return a pointer to the last char put in buf (null), in case of mem fault, + * return 0. + */ +static unsigned char *mem_to_hex(const void *mem_, unsigned char *buf, + int count) +{ + const unsigned char *mem = mem_; + unsigned char ch; + + if ((mem == NULL) || (buf == NULL)) + return NULL; + while (count-- > 0) { +#ifdef __XTENSA__ + unsigned long v; + unsigned long addr = (unsigned long) mem; + + asm volatile ("_l32i %0, %1, 0\n" + : "=r"(v) + : "r"(addr & ~3) + : "memory"); + ch = v >> (addr & 3) * 8; +#endif + mem++; + *buf++ = hex_chars[ch >> 4]; + *buf++ = hex_chars[ch & 0xf]; + } + + *buf = 0; + return buf; +} + +static void read_sr(int sr) +{ +#ifdef __XTENSA__ + uint32_t val; + + asm volatile ("movi a3, 1f + 1\n" + "s8i %1, a3, 0\n" + "dhwb a3, 0\n" + "ihi a3, 0\n" + "isync\n" + "1:\n" + "rsr %0, lbeg\n" + : "=r"(val) + : "r"(sr) + : "a3", "memory"); + sregs[sr] = val; +#endif +} diff --git a/src/include/sof/gdb/gdb.h b/src/include/sof/gdb/gdb.h index 02e055049cd4..ac5ab8912087 100644 --- a/src/include/sof/gdb/gdb.h +++ b/src/include/sof/gdb/gdb.h @@ -4,6 +4,7 @@ #define GDB_BUFMAX 256 #define GDB_NUMBER_OF_REGISTERS 64 #define DISABLE_LOWER_INTERRUPTS_MASK ~0x1F +#define REGISTER_MASK 0xFF void gdb_handle_exception(void); void gdb_debug_info(unsigned char *str); void gdb_init_debug_exception(void); From 1c8879e2cc5aa2adf1626281adc3f4a61a4aecbb Mon Sep 17 00:00:00 2001 From: Marcin Rajwa Date: Tue, 5 Feb 2019 15:49:52 +0100 Subject: [PATCH 05/11] GDB: Added support for register write. Signed-off-by: Marcin Rajwa --- src/gdb/gdb.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/gdb/gdb.c b/src/gdb/gdb.c index 323c25e61e5c..19caa24d74ec 100644 --- a/src/gdb/gdb.c +++ b/src/gdb/gdb.c @@ -52,6 +52,9 @@ static void write_sr(int sr); static unsigned char *mem_to_hex(const void *mem_, unsigned char *buf, int count); static void read_sr(int sr); +static unsigned char *hex_to_mem(const unsigned char *buf, void *mem_, + int count); + /* main buffers */ static unsigned char remcom_in_buffer[GDB_BUFMAX]; static unsigned char remcom_out_buffer[GDB_BUFMAX]; @@ -282,6 +285,30 @@ while (1) { } } break; + /* write register */ + case 'P': + if (hex_to_int(&request, &addr) && *(request++) == '=') { + int ok = 1; + + if (addr < 0x10) { + hex_to_mem(request, aregs + addr, 4); + } else if (addr == 0x20) { + hex_to_mem(request, sregs + DEBUG_PC, 4); + } else if (addr >= 0x100 && addr < + 0x100 + XCHAL_NUM_AREGS) { + hex_to_mem(request, aregs + + ((addr - windowbase) & REGISTER_MASK), 4); + } else if (addr >= 0x200 && addr < 0x300) { + addr &= REGISTER_MASK; + hex_to_mem(request, sregs + addr, 4); + } else { + ok = 0; + strcpy((char *)remcom_out_buffer, "E00"); + } + if (ok) + strcpy((char *)remcom_out_buffer, "OK"); + } + break; default: gdb_log_exception("Unknown GDB command."); break; @@ -419,3 +446,41 @@ static void read_sr(int sr) sregs[sr] = val; #endif } + +/* 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 + */ +static unsigned char *hex_to_mem(const unsigned char *buf, void *mem_, + int count) +{ + unsigned char *mem = mem_; + int i; + unsigned char ch; + + if ((mem == NULL) || (buf == NULL)) + return NULL; + for (i = 0; i < count; i++) { + ch = get_hex(*buf++) << 4; + ch |= get_hex(*buf++); +#ifdef __XTENSA__ + unsigned long tmp; + unsigned long addr = (unsigned long)mem; + + asm volatile ("_l32i %0, %1, 0\n" + "and %0, %0, %2\n" + "or %0, %0, %3\n" + "_s32i %0, %1, 0\n" + "dhwb %1, 0\n" + "ihi %1, 0\n" + : "=&r"(tmp) + : "r"(addr & ~3), "r"(0xffffffff ^ (0xff << + (addr & 3) * 8)), + "r"(ch << (addr & 3) * 8) + : "memory"); +#endif + mem++; + } + + dcache_writeback_region((void *)mem, count); + return mem; +} From 30203256bb67b7a539a60c2beac18ea585d78c2a Mon Sep 17 00:00:00 2001 From: Marcin Rajwa Date: Tue, 5 Feb 2019 15:59:27 +0100 Subject: [PATCH 06/11] GDB: Added support for memory read. Signed-off-by: Marcin Rajwa --- src/gdb/gdb.c | 13 +++++++++++++ src/include/sof/gdb/gdb.h | 3 +++ 2 files changed, 16 insertions(+) diff --git a/src/gdb/gdb.c b/src/gdb/gdb.c index 19caa24d74ec..a26bd2b48255 100644 --- a/src/gdb/gdb.c +++ b/src/gdb/gdb.c @@ -309,6 +309,19 @@ while (1) { strcpy((char *)remcom_out_buffer, "OK"); } break; + /* read memory */ + case 'm': + i = hex_to_int(&request, &addr); + if (i == VALID_MEM_ADDRESS_LEN && + ((addr & FIRST_BYTE_MASK) >> 28) == VALID_MEM_START_BYTE && + *request++ == ',' && hex_to_int(&request, &length)) { + if (mem_to_hex((void *)addr, remcom_out_buffer, length)) + break; + strcpy((char *)remcom_out_buffer, "E03"); + } else { + strcpy((char *)remcom_out_buffer, "E01"); + } + break; default: gdb_log_exception("Unknown GDB command."); break; diff --git a/src/include/sof/gdb/gdb.h b/src/include/sof/gdb/gdb.h index ac5ab8912087..03ee76e03187 100644 --- a/src/include/sof/gdb/gdb.h +++ b/src/include/sof/gdb/gdb.h @@ -5,6 +5,9 @@ #define GDB_NUMBER_OF_REGISTERS 64 #define DISABLE_LOWER_INTERRUPTS_MASK ~0x1F #define REGISTER_MASK 0xFF +#define FIRST_BYTE_MASK 0xF0000000 +#define VALID_MEM_START_BYTE 0xB +#define VALID_MEM_ADDRESS_LEN 0x8 void gdb_handle_exception(void); void gdb_debug_info(unsigned char *str); void gdb_init_debug_exception(void); From 8b06b3553b5eeb9b3c5d4c96b578ae0cf8d469a6 Mon Sep 17 00:00:00 2001 From: Marcin Rajwa Date: Tue, 5 Feb 2019 16:17:24 +0100 Subject: [PATCH 07/11] GDB: Added support for memory write (binary mode). Signed-off-by: Marcin Rajwa --- src/gdb/gdb.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/gdb/gdb.c b/src/gdb/gdb.c index a26bd2b48255..8680d856fff0 100644 --- a/src/gdb/gdb.c +++ b/src/gdb/gdb.c @@ -322,6 +322,18 @@ while (1) { strcpy((char *)remcom_out_buffer, "E01"); } break; + /* write memory (binary) */ + case 'X': + if (hex_to_int(&request, &addr) && *request++ == ',' && + hex_to_int(&request, &length) && *request++ == ':') { + if (hex_to_mem(request, (void *)addr, length)) + strcpy((char *)remcom_out_buffer, "OK"); + else + strcpy((char *)remcom_out_buffer, "E03"); + } else { + strcpy((char *)remcom_out_buffer, "E02"); + } + break; default: gdb_log_exception("Unknown GDB command."); break; From 460e139f8e86cd2ddb0155545ce9d7e86bce832f Mon Sep 17 00:00:00 2001 From: Marcin Rajwa Date: Tue, 5 Feb 2019 16:20:06 +0100 Subject: [PATCH 08/11] GDB: Added support for memory write. Signed-off-by: Marcin Rajwa --- src/gdb/gdb.c | 5 +++-- src/include/sof/gdb/gdb.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gdb/gdb.c b/src/gdb/gdb.c index 8680d856fff0..210872db814e 100644 --- a/src/gdb/gdb.c +++ b/src/gdb/gdb.c @@ -322,8 +322,9 @@ while (1) { strcpy((char *)remcom_out_buffer, "E01"); } break; - /* write memory (binary) */ - case 'X': + /* write memory */ + case 'X': /* binary mode */ + case 'M': if (hex_to_int(&request, &addr) && *request++ == ',' && hex_to_int(&request, &length) && *request++ == ':') { if (hex_to_mem(request, (void *)addr, length)) diff --git a/src/include/sof/gdb/gdb.h b/src/include/sof/gdb/gdb.h index 03ee76e03187..ad49cca4c0fe 100644 --- a/src/include/sof/gdb/gdb.h +++ b/src/include/sof/gdb/gdb.h @@ -8,6 +8,7 @@ #define FIRST_BYTE_MASK 0xF0000000 #define VALID_MEM_START_BYTE 0xB #define VALID_MEM_ADDRESS_LEN 0x8 + void gdb_handle_exception(void); void gdb_debug_info(unsigned char *str); void gdb_init_debug_exception(void); From 2cae346f3684607be4864eb6d2507b357d09dea7 Mon Sep 17 00:00:00 2001 From: Marcin Rajwa Date: Tue, 12 Feb 2019 20:04:26 +0100 Subject: [PATCH 09/11] GDB: fix "step" followed by "continue" issue Signed-off-by: Marcin Rajwa --- src/arch/xtensa/gdb/debugexception.S | 4 ++++ src/gdb/gdb.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/arch/xtensa/gdb/debugexception.S b/src/arch/xtensa/gdb/debugexception.S index 4f6ac6039350..3883ec7f7d04 100644 --- a/src/arch/xtensa/gdb/debugexception.S +++ b/src/arch/xtensa/gdb/debugexception.S @@ -154,6 +154,10 @@ DebugExceptionEntry: wsr a2, PS rsync + /* reset icountlevel - essential when coming back from single step */ + movi a2, 0x00 + wsr a2, ICOUNTLEVEL + movi a4, gdb_handle_exception callx4 a4 diff --git a/src/gdb/gdb.c b/src/gdb/gdb.c index 210872db814e..44c2ffbc257d 100644 --- a/src/gdb/gdb.c +++ b/src/gdb/gdb.c @@ -279,7 +279,7 @@ while (1) { mem_to_hex(sregs + addr, remcom_out_buffer, 4); } else if (addr >= 0x300 && addr < 0x400) { strcpy((char *)remcom_out_buffer, - "out of scope"); + "deadbabe"); } else { /* unexpected register number */ strcpy((char *)remcom_out_buffer, "E00"); } @@ -469,7 +469,7 @@ static void read_sr(int sr) : "=r"(val) : "r"(sr) : "a3", "memory"); - sregs[sr] = val; + //sregs[sr] = val; #endif } From 0d045496fd7514acf180dbb28edc866afe0ed8d8 Mon Sep 17 00:00:00 2001 From: Marcin Rajwa Date: Tue, 12 Feb 2019 21:57:27 +0100 Subject: [PATCH 10/11] GDB: move Xtensa specific stuff into arch/xtensa/gdb/* Signed-off-by: Marcin Rajwa --- src/arch/xtensa/gdb/CMakeLists.txt | 2 +- src/arch/xtensa/gdb/utilities.c | 111 ++++++++++++++++++ src/arch/xtensa/include/arch/gdb/init.h | 33 ++++++ src/arch/xtensa/include/arch/gdb/utilities.h | 38 ++++++ .../xtensa/include/arch/gdb/xtensa-defs.h | 33 ++++++ src/gdb/gdb.c | 101 +++------------- 6 files changed, 234 insertions(+), 84 deletions(-) create mode 100644 src/arch/xtensa/gdb/utilities.c create mode 100644 src/arch/xtensa/include/arch/gdb/utilities.h diff --git a/src/arch/xtensa/gdb/CMakeLists.txt b/src/arch/xtensa/gdb/CMakeLists.txt index d42db2b29a05..6713570f8bf0 100644 --- a/src/arch/xtensa/gdb/CMakeLists.txt +++ b/src/arch/xtensa/gdb/CMakeLists.txt @@ -1,3 +1,3 @@ # TODO: add gdb to final binary when it's done -add_local_sources(sof init.S debugexception.S) +add_local_sources(sof init.S debugexception.S utilities.c) diff --git a/src/arch/xtensa/gdb/utilities.c b/src/arch/xtensa/gdb/utilities.c new file mode 100644 index 000000000000..d746358498cd --- /dev/null +++ b/src/arch/xtensa/gdb/utilities.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2019, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Marcin Rajwa + * + * Xtensa related functions for GDB. + * + */ +#define DISABLE_LOWER_INTERRUPTS_MASK ~0x1F + +#include +#include + +void arch_gdb_read_sr(int sr) +{ + int val; + + asm volatile ("movi a3, 1f + 1\n" + "s8i %1, a3, 0\n" + "dhwb a3, 0\n" + "ihi a3, 0\n" + "isync\n" + "1:\n" + "rsr %0, lbeg\n" + : "=r"(val) + : "r"(sr) + : "a3", "memory"); +} + +void arch_gdb_write_sr(int sr, int *sregs) +{ + asm volatile ("movi a3, 1f + 1\n" + "s8i %1, a3, 0\n" + "dhwb a3, 0\n" + "ihi a3, 0\n" + "isync\n" + "1:\n" + "wsr %0, lbeg\n" + : + : "r"(sregs[sr]), "r"(sr) + : "a3", "memory"); +} + +unsigned char arch_gdb_load_from_memory(void *mem) +{ + unsigned long v; + unsigned long addr = (unsigned long)mem; + unsigned char ch; + + asm volatile ("_l32i %0, %1, 0\n" + : "=r"(v) + : "r"(addr & ~3) + : "memory"); + ch = v >> (addr & 3) * 8; + + return ch; +} + +void arch_gdb_memory_load_and_store(void *mem, unsigned char ch) +{ + unsigned long tmp; + unsigned long addr = (unsigned long)mem; + + asm volatile ("_l32i %0, %1, 0\n" + "and %0, %0, %2\n" + "or %0, %0, %3\n" + "_s32i %0, %1, 0\n" + "dhwb %1, 0\n" + "ihi %1, 0\n" + : "=&r"(tmp) + : "r"(addr & ~3), "r"(0xffffffff ^ (0xff << + (addr & 3) * 8)), + "r"(ch << (addr & 3) * 8) + : "memory"); +} + +void arch_gdb_single_step(int *sregs) +{ + /* leave debug just for one instruction */ + sregs[ICOUNT] = 0xfffffffe; + sregs[ICOUNTLEVEL] = XCHAL_DEBUGLEVEL; + /* disable low level interrupts */ + sregs[INTENABLE] &= ~DISABLE_LOWER_INTERRUPTS_MASK; + arch_gdb_write_sr(ICOUNTLEVEL, sregs); + arch_gdb_write_sr(ICOUNT, sregs); + arch_gdb_write_sr(INTENABLE, sregs); +} diff --git a/src/arch/xtensa/include/arch/gdb/init.h b/src/arch/xtensa/include/arch/gdb/init.h index b2bddeedfa3a..1e7729a08c3f 100644 --- a/src/arch/xtensa/include/arch/gdb/init.h +++ b/src/arch/xtensa/include/arch/gdb/init.h @@ -1 +1,34 @@ +/* + * Copyright (c) 2019, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Marcin Rajwa + * + * Header file for init.S + * + */ + extern void gdb_init_debug_exception(void); diff --git a/src/arch/xtensa/include/arch/gdb/utilities.h b/src/arch/xtensa/include/arch/gdb/utilities.h new file mode 100644 index 000000000000..6c071d73a37a --- /dev/null +++ b/src/arch/xtensa/include/arch/gdb/utilities.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Marcin Rajwa + * + * Header file for Xtensa-GDB utilities. + * + */ + +void arch_gdb_read_sr(int sr); +void arch_gdb_write_sr(int sr, int *sregs); +unsigned char arch_gdb_load_from_memory(void *mem); +void arch_gdb_memory_load_and_store(void *mem, unsigned char ch); +void arch_gdb_single_step(int *sregs); diff --git a/src/arch/xtensa/include/arch/gdb/xtensa-defs.h b/src/arch/xtensa/include/arch/gdb/xtensa-defs.h index b39360507146..8c03aea0e380 100644 --- a/src/arch/xtensa/include/arch/gdb/xtensa-defs.h +++ b/src/arch/xtensa/include/arch/gdb/xtensa-defs.h @@ -1,3 +1,36 @@ +/* + * Copyright (c) 2019, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Marcin Rajwa + * + * Header file for xtensa specific defs for GDB. + * + */ + #ifndef XTENSA_DEFS_H #define XTENSA_DEFS_H diff --git a/src/gdb/gdb.c b/src/gdb/gdb.c index 44c2ffbc257d..69b3fa38135f 100644 --- a/src/gdb/gdb.c +++ b/src/gdb/gdb.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -48,10 +49,8 @@ static void put_packet(unsigned char *buffer); static void parse_request(void); static unsigned char *get_packet(void); static void gdb_log_exception(char *message); -static void write_sr(int sr); -static unsigned char *mem_to_hex(const void *mem_, - unsigned char *buf, int count); -static void read_sr(int sr); +static unsigned char *mem_to_hex(void *mem_, + unsigned char *buf, int count); static unsigned char *hex_to_mem(const unsigned char *buf, void *mem_, int count); @@ -184,8 +183,10 @@ while (1) { sregs[IBREAKA + i] == addr) { sregs[IBREAKA + i] = addr; sregs[IBREAKENABLE] |= (1 << i); - write_sr(IBREAKA+i); - write_sr(IBREAKENABLE); + arch_gdb_write_sr((IBREAKA+i), + sregs); + arch_gdb_write_sr(IBREAKENABLE, + sregs); break; } } @@ -197,7 +198,7 @@ while (1) { strcpy((char *)remcom_out_buffer, "OK"); sregs[INTENABLE] &= DISABLE_LOWER_INTERRUPTS_MASK; - write_sr(INTENABLE); + arch_gdb_write_sr(INTENABLE, sregs); } } else { strcpy((char *)remcom_out_buffer, "E01"); @@ -224,7 +225,8 @@ while (1) { sregs[IBREAKA + i] == addr) { sregs[IBREAKENABLE] &= ~(1 << i); - write_sr(IBREAKENABLE); + arch_gdb_write_sr(IBREAKENABLE, + sregs); break; } } @@ -250,14 +252,7 @@ while (1) { case 's': if (hex_to_int(&request, &addr)) sregs[DEBUG_PC] = addr; - /* leave debug just for one instruction */ - sregs[ICOUNT] = 0xfffffffe; - sregs[ICOUNTLEVEL] = XCHAL_DEBUGLEVEL; - /* disable low level interrupts */ - sregs[INTENABLE] &= ~DISABLE_LOWER_INTERRUPTS_MASK; - write_sr(ICOUNTLEVEL); - write_sr(ICOUNT); - write_sr(INTENABLE); + arch_gdb_single_step(sregs); return; /* read register */ case 'p': @@ -273,9 +268,8 @@ while (1) { mem_to_hex(aregs + ((addr - windowbase) & REGISTER_MASK), remcom_out_buffer, 4); } else if (addr >= 0x200 && addr < 0x300) { - /* read special registers */ addr &= REGISTER_MASK; - read_sr(addr); + arch_gdb_read_sr(addr); mem_to_hex(sregs + addr, remcom_out_buffer, 4); } else if (addr >= 0x300 && addr < 0x400) { strcpy((char *)remcom_out_buffer, @@ -406,45 +400,20 @@ static void gdb_log_exception(char *message) } -static void write_sr(int sr) -{ -#ifdef __XTENSA__ - asm volatile ("movi a3, 1f + 1\n" - "s8i %1, a3, 0\n" - "dhwb a3, 0\n" - "ihi a3, 0\n" - "isync\n" - "1:\n" - "wsr %0, lbeg\n" - : - : "r"(sregs[sr]), "r"(sr) - : "a3", "memory"); -#endif -} - /* Convert the memory pointed to by mem into hex, placing result in buf. * Return a pointer to the last char put in buf (null), in case of mem fault, * return 0. */ -static unsigned char *mem_to_hex(const void *mem_, unsigned char *buf, - int count) +static unsigned char *mem_to_hex(void *mem_, unsigned char *buf, + int count) { - const unsigned char *mem = mem_; + unsigned char *mem = mem_; unsigned char ch; if ((mem == NULL) || (buf == NULL)) return NULL; while (count-- > 0) { -#ifdef __XTENSA__ - unsigned long v; - unsigned long addr = (unsigned long) mem; - - asm volatile ("_l32i %0, %1, 0\n" - : "=r"(v) - : "r"(addr & ~3) - : "memory"); - ch = v >> (addr & 3) * 8; -#endif + ch = arch_gdb_load_from_memory(mem); mem++; *buf++ = hex_chars[ch >> 4]; *buf++ = hex_chars[ch & 0xf]; @@ -454,25 +423,6 @@ static unsigned char *mem_to_hex(const void *mem_, unsigned char *buf, return buf; } -static void read_sr(int sr) -{ -#ifdef __XTENSA__ - uint32_t val; - - asm volatile ("movi a3, 1f + 1\n" - "s8i %1, a3, 0\n" - "dhwb a3, 0\n" - "ihi a3, 0\n" - "isync\n" - "1:\n" - "rsr %0, lbeg\n" - : "=r"(val) - : "r"(sr) - : "a3", "memory"); - //sregs[sr] = val; -#endif -} - /* 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 */ @@ -488,23 +438,8 @@ static unsigned char *hex_to_mem(const unsigned char *buf, void *mem_, for (i = 0; i < count; i++) { ch = get_hex(*buf++) << 4; ch |= get_hex(*buf++); -#ifdef __XTENSA__ - unsigned long tmp; - unsigned long addr = (unsigned long)mem; - - asm volatile ("_l32i %0, %1, 0\n" - "and %0, %0, %2\n" - "or %0, %0, %3\n" - "_s32i %0, %1, 0\n" - "dhwb %1, 0\n" - "ihi %1, 0\n" - : "=&r"(tmp) - : "r"(addr & ~3), "r"(0xffffffff ^ (0xff << - (addr & 3) * 8)), - "r"(ch << (addr & 3) * 8) - : "memory"); -#endif - mem++; + arch_gdb_memory_load_and_store(mem, ch); + mem++; } dcache_writeback_region((void *)mem, count); From edc3fc946534193b835acdae789b7f68c0096eff Mon Sep 17 00:00:00 2001 From: Marcin Rajwa Date: Wed, 13 Feb 2019 12:37:10 +0100 Subject: [PATCH 11/11] GDB: cleanup and comments Signed-off-by: Marcin Rajwa --- src/arch/xtensa/gdb/CMakeLists.txt | 2 - src/arch/xtensa/gdb/utilities.c | 4 +- src/gdb/gdb.c | 121 +++++++++++++++++++++-------- src/include/sof/gdb/gdb.h | 16 ++-- 4 files changed, 102 insertions(+), 41 deletions(-) diff --git a/src/arch/xtensa/gdb/CMakeLists.txt b/src/arch/xtensa/gdb/CMakeLists.txt index 6713570f8bf0..e0410c30516d 100644 --- a/src/arch/xtensa/gdb/CMakeLists.txt +++ b/src/arch/xtensa/gdb/CMakeLists.txt @@ -1,3 +1 @@ -# TODO: add gdb to final binary when it's done add_local_sources(sof init.S debugexception.S utilities.c) - diff --git a/src/arch/xtensa/gdb/utilities.c b/src/arch/xtensa/gdb/utilities.c index d746358498cd..8ab51e31877c 100644 --- a/src/arch/xtensa/gdb/utilities.c +++ b/src/arch/xtensa/gdb/utilities.c @@ -30,7 +30,7 @@ * Xtensa related functions for GDB. * */ -#define DISABLE_LOWER_INTERRUPTS_MASK ~0x1F +#define GDB_DISABLE_LOWER_INTERRUPTS_MASK ~0x1F #include #include @@ -104,7 +104,7 @@ void arch_gdb_single_step(int *sregs) sregs[ICOUNT] = 0xfffffffe; sregs[ICOUNTLEVEL] = XCHAL_DEBUGLEVEL; /* disable low level interrupts */ - sregs[INTENABLE] &= ~DISABLE_LOWER_INTERRUPTS_MASK; + sregs[INTENABLE] &= ~GDB_DISABLE_LOWER_INTERRUPTS_MASK; arch_gdb_write_sr(ICOUNTLEVEL, sregs); arch_gdb_write_sr(ICOUNT, sregs); arch_gdb_write_sr(INTENABLE, sregs); diff --git a/src/gdb/gdb.c b/src/gdb/gdb.c index 69b3fa38135f..644e5911e6ba 100644 --- a/src/gdb/gdb.c +++ b/src/gdb/gdb.c @@ -46,13 +46,13 @@ static int get_hex(unsigned char ch); static int hex_to_int(unsigned char **ptr, int *int_value); static void put_packet(unsigned char *buffer); -static void parse_request(void); static unsigned char *get_packet(void); static void gdb_log_exception(char *message); static unsigned char *mem_to_hex(void *mem_, unsigned char *buf, int count); static unsigned char *hex_to_mem(const unsigned char *buf, void *mem_, - int count); + int count); +static inline int gdb_parser(void); /* main buffers */ static unsigned char remcom_in_buffer[GDB_BUFMAX]; @@ -143,10 +143,21 @@ static int get_hex(unsigned char ch) void gdb_handle_exception(void) { gdb_log_exception("Hello from GDB!"); - parse_request(); + + while (gdb_parser()) + ;/* do nothing */ } -void parse_request(void) +/** + * \brief Parse incoming GDB packets. + * \param[in] none. + * \param[out] none. + * + * Every incoming packet has the format: $packet-data#check-sum + * packet-data varies depending on command. Full description + * of each command packet can be found in GNU GDB reference manual. + */ +static inline int gdb_parser(void) { unsigned char *request; unsigned int i; @@ -154,8 +165,6 @@ void parse_request(void) int length; unsigned int windowbase = (4 * sregs[WINDOWBASE]); - -while (1) { request = get_packet(); /* Log any exception caused by debug exception */ gdb_debug_info(request); @@ -165,16 +174,26 @@ while (1) { switch (command) { /* Continue normal program execution and leave debug handler */ case 'c': + /* incoming packet has the form $c,ADDRESS#CH, where: + * c - continue command identifier, + * ADDRESS - address on which to continue + * CH - two bytes checksum. + */ if (hex_to_int(&request, &addr)) sregs[DEBUG_PC] = addr; /* return from exception */ - return; + return 0; /* insert breakpoint */ case 'Z': switch (*request++) { /* HW breakpoint */ case '1': + /* Incoming packet has the form $ZX,ADDRESS,LEN,#CH, where: + * Z - breakpoint command identifier, X - 0/1, SW/HW breakpoint + * ADDRESS - address on which breakpoint shall be put + * LEN - address length in bytes, CH - two bytes checksum. + */ if (*request++ == ',' && hex_to_int(&request, &addr) && *request++ == ',' && hex_to_int(&request, &length) && *request == 0) { @@ -197,7 +216,7 @@ while (1) { } else { strcpy((char *)remcom_out_buffer, "OK"); sregs[INTENABLE] &= - DISABLE_LOWER_INTERRUPTS_MASK; + GDB_DISABLE_LOWER_INTERRUPTS_MASK; arch_gdb_write_sr(INTENABLE, sregs); } } else { @@ -216,7 +235,11 @@ while (1) { /* remove HW breakpoint */ case 'z': switch (*request++) { - /* remove HW breakpoint */ + /* Incoming packet has the form $zX,ADDRESS,LEN,#CH, where: + * Z - breakpoint command identifier, X - 0/1, SW/HW breakpoint + * ADDRESS - address from which breakpoint shall be removed + * LEN - address length in bytes, CH - two bytes checksum. + */ case '1': if (*request++ == ',' && hex_to_int(&request, &addr) && *request++ == ',' && hex_to_int(&request, &length)) { @@ -236,6 +259,7 @@ while (1) { else strcpy((char *)remcom_out_buffer, "OK"); } else { + /* respond with error message */ strcpy((char *)remcom_out_buffer, "E01"); } break; @@ -250,50 +274,70 @@ while (1) { break; /* single step in the code */ case 's': + /* incoming packet has the form $s#CH, where: + * s - step command identifier, + * CH - two bytes checksum. + */ if (hex_to_int(&request, &addr)) sregs[DEBUG_PC] = addr; arch_gdb_single_step(sregs); - return; + return 0; /* read register */ case 'p': + /* Incoming packet has the form $p,REGISTER#CH, where: + * p - read register command identifier, + * REGISTER - register number to read, + * CH - two bytes checksum. + */ if (hex_to_int(&request, &addr)) { /* read address register in the current window */ - if (addr < 0x10) { + if (addr < GDB_AR_REG_RANGE) { mem_to_hex(aregs + addr, remcom_out_buffer, 4); - } else if (addr == 0x20) { /* read PC */ + } else if (addr == GDB_PC_REG_ID) { + /* read PC */ mem_to_hex(sregs + DEBUG_PC, remcom_out_buffer, 4); - } else if (addr >= 0x100 && - addr < (0x100 + XCHAL_NUM_AREGS)) { + } else if (addr >= GDB_AREG_RANGE && + addr < (GDB_AREG_RANGE + XCHAL_NUM_AREGS)) { mem_to_hex(aregs + ((addr - windowbase) & - REGISTER_MASK), remcom_out_buffer, 4); - } else if (addr >= 0x200 && addr < 0x300) { - addr &= REGISTER_MASK; + GDB_REGISTER_MASK), + remcom_out_buffer, 4); + } else if (addr >= GDB_SPEC_REG_RANGE_START && + addr < GDB_SPEC_REG_RANGE_END) { + addr &= GDB_REGISTER_MASK; arch_gdb_read_sr(addr); mem_to_hex(sregs + addr, remcom_out_buffer, 4); - } else if (addr >= 0x300 && addr < 0x400) { + } else if (addr >= GDB_SPEC_REG_RANGE_END && + addr < GDB_REG_RANGE_END) { strcpy((char *)remcom_out_buffer, "deadbabe"); - } else { /* unexpected register number */ + } else { + /* unexpected register number */ strcpy((char *)remcom_out_buffer, "E00"); } } break; /* write register */ case 'P': + /* Incoming packet has the form $P,REGISTER#CH, where: + * P - write register command identifier, + * REGISTER - register number to write, + * CH - two bytes checksum. + */ if (hex_to_int(&request, &addr) && *(request++) == '=') { int ok = 1; - if (addr < 0x10) { + if (addr < GDB_AR_REG_RANGE) { hex_to_mem(request, aregs + addr, 4); - } else if (addr == 0x20) { + } else if (addr == GDB_PC_REG_ID) { hex_to_mem(request, sregs + DEBUG_PC, 4); - } else if (addr >= 0x100 && addr < - 0x100 + XCHAL_NUM_AREGS) { + } else if (addr >= GDB_AREG_RANGE && addr < + GDB_AREG_RANGE + XCHAL_NUM_AREGS) { hex_to_mem(request, aregs + - ((addr - windowbase) & REGISTER_MASK), 4); - } else if (addr >= 0x200 && addr < 0x300) { - addr &= REGISTER_MASK; + ((addr - windowbase) & GDB_REGISTER_MASK), 4); + } else if (addr >= GDB_SPEC_REG_RANGE_START && + addr < GDB_SPEC_REG_RANGE_END) { + addr &= GDB_REGISTER_MASK; hex_to_mem(request, sregs + addr, 4); } else { ok = 0; @@ -305,20 +349,33 @@ while (1) { break; /* read memory */ case 'm': + /* Incoming packet has the form $m,ADDRESS#CH, where: + * m - read address command identifier, + * ADDRESS - address to read from, + * CH - two bytes checksum. + */ i = hex_to_int(&request, &addr); - if (i == VALID_MEM_ADDRESS_LEN && - ((addr & FIRST_BYTE_MASK) >> 28) == VALID_MEM_START_BYTE && - *request++ == ',' && hex_to_int(&request, &length)) { + if (i == GDB_VALID_MEM_ADDRESS_LEN && + ((addr & GDB_VALID_MEM_START_BYTE) >> 28) == + GDB_VALID_MEM_START_BYTE && + *request++ == ',' && hex_to_int(&request, &length)) { if (mem_to_hex((void *)addr, remcom_out_buffer, length)) break; + /* wrong memory address - respond with error message */ strcpy((char *)remcom_out_buffer, "E03"); } else { + /* wrong packet format - respond with error message */ strcpy((char *)remcom_out_buffer, "E01"); } break; /* write memory */ case 'X': /* binary mode */ case 'M': + /* Incoming packet has the form $M,ADDRESS#CH, where: + * M - write address command identifier, + * ADDRESS - address to write into, + * CH - two bytes checksum. + */ if (hex_to_int(&request, &addr) && *request++ == ',' && hex_to_int(&request, &length) && *request++ == ':') { if (hex_to_mem(request, (void *)addr, length)) @@ -336,9 +393,9 @@ while (1) { } /* reply to the request */ put_packet(remcom_out_buffer); -} -} + return 1; +} /* * While we find nice hex chars, build an int. * Return number of chars processed. @@ -427,7 +484,7 @@ static unsigned char *mem_to_hex(void *mem_, unsigned char *buf, * return a pointer to the character after the last byte written */ static unsigned char *hex_to_mem(const unsigned char *buf, void *mem_, - int count) + int count) { unsigned char *mem = mem_; int i; diff --git a/src/include/sof/gdb/gdb.h b/src/include/sof/gdb/gdb.h index ad49cca4c0fe..7c23c564050e 100644 --- a/src/include/sof/gdb/gdb.h +++ b/src/include/sof/gdb/gdb.h @@ -3,11 +3,17 @@ #define GDB_BUFMAX 256 #define GDB_NUMBER_OF_REGISTERS 64 -#define DISABLE_LOWER_INTERRUPTS_MASK ~0x1F -#define REGISTER_MASK 0xFF -#define FIRST_BYTE_MASK 0xF0000000 -#define VALID_MEM_START_BYTE 0xB -#define VALID_MEM_ADDRESS_LEN 0x8 +#define GDB_DISABLE_LOWER_INTERRUPTS_MASK ~0x1F +#define GDB_REGISTER_MASK 0xFF +#define GDB_FIRST_BYTE_MASK 0xF0000000 +#define GDB_VALID_MEM_START_BYTE 0xB +#define GDB_VALID_MEM_ADDRESS_LEN 0x8 +#define GDB_AR_REG_RANGE 0x10 /**< identifies registers in current window */ +#define GDB_PC_REG_ID 0x20 /**< identifies PC register */ +#define GDB_AREG_RANGE 0x100 /**< identifies address registers range */ +#define GDB_SPEC_REG_RANGE_START 0x200 /**< identifies spec registers range */ +#define GDB_SPEC_REG_RANGE_END 0x300 /**< identifies spec registers range */ +#define GDB_REG_RANGE_END 0x400 /**< identifies spec registers range */ void gdb_handle_exception(void); void gdb_debug_info(unsigned char *str);