diff --git a/flashstub/README b/flashstub/README deleted file mode 100644 index 90d164c..0000000 --- a/flashstub/README +++ /dev/null @@ -1,19 +0,0 @@ -Flash Stubs -=========== - -For most of the targets, these are assembler routines for executing -a flash write on the supported targets. They are kept here for -reference, but are not used, as the compiled binary code is included -in the target drivers. - -For the STM32l0x, the stubs are written in C++ and emitted as arrays -of half-words for inclusion in the target driver. The use of a higher -level language allows more detailed code and for easy revisions. -These stubs communicate with the driver through a structure defined in -the src/include/stm32l0-nvm.h header. - -The dump-to-array.sh helper script uses sed to transform the output of -'objdump -d' into a half-word array of the instructions that may be -included in C code to declare the stub. FWIW, objcopy doesn't produce -the same output as objdump. It omits some of the instructions, -probably because the object file isn't linked. diff --git a/src/Makefile b/src/Makefile index f43ffff..abd8693 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,6 +1,6 @@ PROBE_HOST ?= native PLATFORM_DIR = platforms/$(PROBE_HOST) -VPATH += platforms/common $(PLATFORM_DIR) +VPATH += $(PLATFORM_DIR) platforms/common target ENABLE_DEBUG ?= ifneq ($(V), 1) @@ -13,6 +13,7 @@ OPT_FLAGS ?= -O2 CFLAGS += -Wall -Wextra -Werror -Wno-char-subscripts\ $(OPT_FLAGS) -std=gnu99 -g3 -MD \ -I. -Iinclude -Iplatforms/common -I$(PLATFORM_DIR) +LDFLAGS += $(OPT_FLAGS) ifeq ($(ENABLE_DEBUG), 1) CFLAGS += -DENABLE_DEBUG @@ -30,10 +31,12 @@ SRC = \ exception.c \ gdb_if.c \ gdb_main.c \ + gdb_hostio.c \ gdb_packet.c \ hex_utils.c \ jtag_scan.c \ jtagtap.c \ + jtagtap_generic.c \ lmi.c \ lpc_common.c \ lpc11xx.c \ @@ -51,6 +54,7 @@ SRC = \ stm32l0.c \ stm32l4.c \ swdptap.c \ + swdptap_generic.c \ target.c \ include $(PLATFORM_DIR)/Makefile.inc diff --git a/src/command.c b/src/command.c index 7ff4432..be53dad 100644 --- a/src/command.c +++ b/src/command.c @@ -26,22 +26,29 @@ #include "exception.h" #include "command.h" #include "gdb_packet.h" -#include "jtag_scan.h" #include "target.h" #include "morse.h" -#include "adiv5.h" #include "version.h" #ifdef PLATFORM_HAS_TRACESWO # include "traceswo.h" #endif +typedef bool (*cmd_handler)(target *t, int argc, const char **argv); + +struct command_s { + const char *cmd; + cmd_handler handler; + + const char *help; +}; + static bool cmd_version(void); static bool cmd_help(target *t); static bool cmd_jtag_scan(target *t, int argc, char **argv); static bool cmd_swdp_scan(void); -static bool cmd_targets(target *t); +static bool cmd_targets(void); static bool cmd_morse(void); static bool cmd_connect_srst(target *t, int argc, const char **argv); static bool cmd_hard_srst(void); @@ -83,7 +90,6 @@ bool debug_bmp; int command_process(target *t, char *cmd) { - struct target_command_s *tc; const struct command_s *c; int argc = 0; const char **argv; @@ -103,19 +109,14 @@ int command_process(target *t, char *cmd) /* Accept a partial match as GDB does. * So 'mon ver' will match 'monitor version' */ - if(!strncmp(argv[0], c->cmd, strlen(argv[0]))) + if ((argc == 0) || !strncmp(argv[0], c->cmd, strlen(argv[0]))) return !c->handler(t, argc, argv); } if (!t) return -1; - for (tc = t->commands; tc; tc = tc->next) - for(c = tc->cmds; c->cmd; c++) - if(!strncmp(argv[0], c->cmd, strlen(argv[0]))) - return !c->handler(t, argc, argv); - - return -1; + return target_command(t, argc, argv); } bool cmd_version(void) @@ -130,7 +131,6 @@ bool cmd_version(void) bool cmd_help(target *t) { - struct target_command_s *tc; const struct command_s *c; gdb_out("General commands:\n"); @@ -140,11 +140,7 @@ bool cmd_help(target *t) if (!t) return -1; - for (tc = t->commands; tc; tc = tc->next) { - gdb_outf("%s specific commands:\n", tc->specific_name); - for(c = tc->cmds; c->cmd; c++) - gdb_outf("\t%s -- %s\n", c->cmd, c->help); - } + target_command_help(t); return true; } @@ -185,13 +181,7 @@ static bool cmd_jtag_scan(target *t, int argc, char **argv) gdb_out("JTAG device scan failed!\n"); return false; } - gdb_outf("Device IR Len IDCODE Description\n"); - for(int i = 0; i < jtag_dev_count; i++) - gdb_outf("%d\t%d\t0x%08lX %s\n", i, - jtag_devs[i].ir_len, jtag_devs[i].idcode, - jtag_devs[i].descr); - gdb_out("\n"); - cmd_targets(NULL); + cmd_targets(); return true; } @@ -222,27 +212,26 @@ bool cmd_swdp_scan(void) return false; } - cmd_targets(NULL); + cmd_targets(); return true; } -bool cmd_targets(target *cur_target) +static void display_target(int i, target *t, void *context) { - struct target_s *t; - int i; + (void)context; + gdb_outf("%2d %c %s\n", i, target_attached(t)?'*':' ', target_driver_name(t)); +} - if(!target_list) { +bool cmd_targets(void) +{ + gdb_out("Available Targets:\n"); + gdb_out("No. Att Driver\n"); + if (!target_foreach(display_target, NULL)) { gdb_out("No usable targets found.\n"); return false; } - gdb_out("Available Targets:\n"); - gdb_out("No. Att Driver\n"); - for(t = target_list, i = 1; t; t = t->next, i++) - gdb_outf("%2d %c %s\n", i, t==cur_target?'*':' ', - t->driver); - return true; } diff --git a/src/crc32.c b/src/crc32.c index 16cc565..881f12d 100644 --- a/src/crc32.c +++ b/src/crc32.c @@ -89,23 +89,21 @@ static const uint32_t crc32_table[] = { 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4, }; -uint32_t crc32_calc(uint32_t crc, uint8_t data) +static uint32_t crc32_calc(uint32_t crc, uint8_t data) { return (crc << 8) ^ crc32_table[((crc >> 24) ^ data) & 255]; } -uint32_t generic_crc32(target *t, uint32_t base, int len) +uint32_t generic_crc32(target *t, uint32_t base, size_t len) { uint32_t crc = -1; - static uint8_t bytes[128]; + uint8_t bytes[128]; while (len) { - uint32_t i; - uint32_t read_len = len >= 128 ? 128 : len; - + size_t read_len = MIN(sizeof(bytes), len); target_mem_read(t, bytes, base, read_len); - for (i=0; i -uint32_t generic_crc32(target *t, uint32_t base, int len) +uint32_t generic_crc32(target *t, uint32_t base, size_t len) { - uint32_t data; + uint8_t bytes[128]; uint32_t crc; - size_t i; CRC_CR |= CRC_CR_RESET; while (len > 3) { - data = target_mem_read32(t, base); + size_t read_len = MIN(sizeof(bytes), len) & ~3; + target_mem_read(t, bytes, base, read_len); - CRC_DR = __builtin_bswap32(data); - base += 4; - len -= 4; + for (unsigned i = 0; i < read_len; i += 4) + CRC_DR = __builtin_bswap32(*(uint32_t*)(bytes+i)); + + base += read_len; + len -= read_len; } crc = CRC_DR; + target_mem_read(t, bytes, base, len); + uint8_t *data = bytes; while (len--) { - data = target_mem_read8(t, base++); - - crc ^= data << 24; - for (i = 0; i < 8; i++) { + crc ^= *data++ << 24; + for (int i = 0; i < 8; i++) { if (crc & 0x80000000) crc = (crc << 1) ^ 0x4C11DB7; else @@ -146,5 +146,5 @@ uint32_t generic_crc32(target *t, uint32_t base, int len) } return crc; } - #endif + diff --git a/src/gdb_hostio.c b/src/gdb_hostio.c new file mode 100644 index 0000000..82ff0a6 --- /dev/null +++ b/src/gdb_hostio.c @@ -0,0 +1,133 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2016 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "general.h" +#include "target.h" +#include "gdb_main.h" +#include "gdb_hostio.h" +#include "gdb_packet.h" + +int gdb_main_loop(struct target_controller *, bool in_syscall); + +int hostio_reply(struct target_controller *tc, char *pbuf, int len) +{ + (void)len; + int retcode, items, errno_; + char c, *p; + if (pbuf[1] == '-') + p = &pbuf[2]; + else + p = &pbuf[1]; + items = sscanf(p, "%x,%x,%c", &retcode, &errno_, &c); + if (pbuf[1] == '-') + retcode = -retcode; + + /* if break is requested */ + tc->interrupted = items == 3 && c == 'C'; + tc->errno_ = errno_; + + return retcode; +} + +/* Interface to host system calls */ +int hostio_open(struct target_controller *tc, + target_addr path, size_t path_len, + enum target_open_flags flags, mode_t mode) +{ + gdb_putpacket_f("Fopen,%08X/%X,%08X,%08X", path, path_len, flags, mode);;;; + return gdb_main_loop(tc, true); +} + +int hostio_close(struct target_controller *tc, int fd) +{ + gdb_putpacket_f("Fclose,%08X", fd); + return gdb_main_loop(tc, true); +} + +int hostio_read(struct target_controller *tc, + int fd, target_addr buf, unsigned int count) +{ + gdb_putpacket_f("Fread,%08X,%08X,%08X", fd, buf, count); + return gdb_main_loop(tc, true); +} + +int hostio_write(struct target_controller *tc, + int fd, target_addr buf, unsigned int count) +{ + gdb_putpacket_f("Fwrite,%08X,%08X,%08X", fd, buf, count); + return gdb_main_loop(tc, true); +} + +long hostio_lseek(struct target_controller *tc, + int fd, long offset, enum target_seek_flag flag) +{ + gdb_putpacket_f("Flseek,%08X,%08X,%08X", fd, offset, flag); + return gdb_main_loop(tc, true); +} + +int hostio_rename(struct target_controller *tc, + target_addr oldpath, size_t old_len, + target_addr newpath, size_t new_len) +{ + gdb_putpacket_f("Frename,%08X/%X,%08X/%X", + oldpath, old_len, newpath, new_len); + return gdb_main_loop(tc, true); +} + +int hostio_unlink(struct target_controller *tc, + target_addr path, size_t path_len) +{ + gdb_putpacket_f("Funlink,%08X/%X", path, path_len); + return gdb_main_loop(tc, true); +} + +int hostio_stat(struct target_controller *tc, + target_addr path, size_t path_len, target_addr buf) +{ + gdb_putpacket_f("Fstat,%08X/%X,%08X", path, path_len, buf); + return gdb_main_loop(tc, true); +} + +int hostio_fstat(struct target_controller *tc, int fd, target_addr buf) +{ + gdb_putpacket_f("Ffstat,%X,%08X", fd, buf); + return gdb_main_loop(tc, true); +} + +int hostio_gettimeofday(struct target_controller *tc, + target_addr tv, target_addr tz) +{ + gdb_putpacket_f("Fgettimeofday,%08X,%08X", tv, tz); + return gdb_main_loop(tc, true); +} + +int hostio_isatty(struct target_controller *tc, int fd) +{ + gdb_putpacket_f("Fisatty,%08X", fd); + return gdb_main_loop(tc, true); +} + +int hostio_system(struct target_controller *tc, + target_addr cmd, size_t cmd_len) +{ + gdb_putpacket_f("Fsystem,%08X/%X", cmd, cmd_len); + return gdb_main_loop(tc, true); +} + diff --git a/src/gdb_hostio.h b/src/gdb_hostio.h new file mode 100644 index 0000000..f95f707 --- /dev/null +++ b/src/gdb_hostio.h @@ -0,0 +1,53 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2016 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef __GDB_SYSCALLS_H +#define __GDB_SYSCALLS_H + +#include "target.h" + +int hostio_reply(struct target_controller *tc, char *packet, int len); + +/* Interface to host system calls */ +int hostio_open(struct target_controller *, + target_addr path, size_t path_len, + enum target_open_flags flags, mode_t mode); +int hostio_close(struct target_controller *, int fd); +int hostio_read(struct target_controller *, + int fd, target_addr buf, unsigned int count); +int hostio_write(struct target_controller *, + int fd, target_addr buf, unsigned int count); +long hostio_lseek(struct target_controller *, + int fd, long offset, enum target_seek_flag flag); +int hostio_rename(struct target_controller *, + target_addr oldpath, size_t old_len, + target_addr newpath, size_t new_len); +int hostio_unlink(struct target_controller *, + target_addr path, size_t path_len); +int hostio_stat(struct target_controller *, + target_addr path, size_t path_len, target_addr buf); +int hostio_fstat(struct target_controller *, int fd, target_addr buf); +int hostio_gettimeofday(struct target_controller *, + target_addr tv, target_addr tz); +int hostio_isatty(struct target_controller *, int fd); +int hostio_system(struct target_controller *, + target_addr cmd, size_t cmd_len); + +#endif + diff --git a/src/gdb_main.c b/src/gdb_main.c index c2f2337..40cb829 100644 --- a/src/gdb_main.c +++ b/src/gdb_main.c @@ -29,13 +29,18 @@ #include "gdb_if.h" #include "gdb_packet.h" #include "gdb_main.h" -#include "jtagtap.h" -#include "jtag_scan.h" -#include "adiv5.h" +#include "gdb_hostio.h" #include "target.h" #include "command.h" #include "crc32.h" +enum gdb_signal { + GDB_SIGINT = 2, + GDB_SIGTRAP = 5, + GDB_SIGSEGV = 11, + GDB_SIGLOST = 29, +}; + #define BUF_SIZE 1024 #define ERROR_IF_NO_TARGET() \ @@ -50,8 +55,9 @@ static void handle_q_packet(char *packet, int len); static void handle_v_packet(char *packet, int len); static void handle_z_packet(char *packet, int len); -static void gdb_target_destroy_callback(target *t) +static void gdb_target_destroy_callback(struct target_controller *tc, target *t) { + (void)tc; if (cur_target == t) cur_target = NULL; @@ -59,12 +65,35 @@ static void gdb_target_destroy_callback(target *t) last_target = NULL; } -void -gdb_main(void) +static void gdb_target_printf(struct target_controller *tc, + const char *fmt, va_list ap) +{ + (void)tc; + gdb_voutf(fmt, ap); +} + +static struct target_controller gdb_controller = { + .destroy_callback = gdb_target_destroy_callback, + .printf = gdb_target_printf, + + .open = hostio_open, + .close = hostio_close, + .read = hostio_read, + .write = hostio_write, + .lseek = hostio_lseek, + .rename = hostio_rename, + .unlink = hostio_unlink, + .stat = hostio_stat, + .fstat = hostio_fstat, + .gettimeofday = hostio_gettimeofday, + .isatty = hostio_isatty, + .system = hostio_system, +}; + +int gdb_main_loop(struct target_controller *tc, bool in_syscall) { int size; bool single_step = false; - char last_activity = 0; DEBUG("Entring GDB protocol main loop\n"); /* GDB protocol main loop */ @@ -72,7 +101,6 @@ gdb_main(void) SET_IDLE_STATE(1); size = gdb_getpacket(pbuf, BUF_SIZE); SET_IDLE_STATE(0); - continue_activity: switch(pbuf[0]) { /* Implementation of these is mandatory! */ case 'g': { /* 'g': Read general registers */ @@ -89,8 +117,7 @@ gdb_main(void) sscanf(pbuf, "m%" SCNx32 ",%" SCNx32, &addr, &len); DEBUG("m packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len); uint8_t mem[len]; - target_mem_read(cur_target, mem, addr, len); - if(target_check_error(cur_target)) + if (target_mem_read(cur_target, mem, addr, len)) gdb_putpacketz("E01"); else gdb_putpacket(hexify(pbuf, mem, len), len*2); @@ -112,8 +139,7 @@ gdb_main(void) DEBUG("M packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len); uint8_t mem[len]; unhexify(mem, pbuf + hex, len); - target_mem_write(cur_target, addr, mem, len); - if(target_check_error(cur_target)) + if (target_mem_write(cur_target, addr, mem, len)) gdb_putpacketz("E01"); else gdb_putpacketz("OK"); @@ -135,8 +161,8 @@ gdb_main(void) case '?': { /* '?': Request reason for target halt */ /* This packet isn't documented as being mandatory, * but GDB doesn't work without it. */ - uint32_t watch_addr; - int sig; + target_addr watch; + enum target_halt_reason reason; if(!cur_target) { /* Report "target exited" if no target */ @@ -144,58 +170,42 @@ gdb_main(void) break; } - last_activity = pbuf[0]; /* Wait for target halt */ - while(!(sig = target_halt_wait(cur_target))) { + while(!(reason = target_halt_poll(cur_target, &watch))) { unsigned char c = gdb_if_getchar_to(0); if((c == '\x03') || (c == '\x04')) { target_halt_request(cur_target); - last_activity = 's'; } } SET_RUN_STATE(0); - /* Negative signal indicates we're in a syscall */ - if (sig < 0) + /* Translate reason to GDB signal */ + switch (reason) { + case TARGET_HALT_ERROR: + gdb_putpacket_f("X%02X", GDB_SIGLOST); break; - - /* Target disappeared */ - if (cur_target == NULL) { - gdb_putpacket_f("X%02X", sig); + case TARGET_HALT_REQUEST: + gdb_putpacket_f("T%02X", GDB_SIGINT); break; - } - - /* Report reason for halt */ - if(target_check_hw_wp(cur_target, &watch_addr)) { - /* Watchpoint hit */ - gdb_putpacket_f("T%02Xwatch:%08X;", sig, watch_addr); - } else { - gdb_putpacket_f("T%02X", sig); + case TARGET_HALT_WATCHPOINT: + gdb_putpacket_f("T%02Xwatch:%08X;", GDB_SIGTRAP, watch); + break; + case TARGET_HALT_FAULT: + gdb_putpacket_f("T%02X", GDB_SIGSEGV); + break; + default: + gdb_putpacket_f("T%02X", GDB_SIGTRAP); } break; } - case 'F': { /* Semihosting call finished */ - int retcode, errcode, items; - char c, *p; - if (pbuf[1] == '-') - p = &pbuf[2]; - else - p = &pbuf[1]; - items = sscanf(p, "%x,%x,%c", &retcode, &errcode, &c); - if (pbuf[1] == '-') - retcode = -retcode; - - target_hostio_reply(cur_target, retcode, errcode); - - /* if break is requested */ - if (items == 3 && c == 'C') { - gdb_putpacketz("T02"); - break; + case 'F': /* Semihosting call finished */ + if (in_syscall) { + return hostio_reply(tc, pbuf, size); + } else { + DEBUG("*** F packet when not in syscall! '%s'\n", pbuf); + gdb_putpacketz(""); } - - pbuf[0] = last_activity; - goto continue_activity; - } + break; /* Optional GDB packet support */ case '!': /* Enable Extended GDB Protocol. */ @@ -230,7 +240,7 @@ gdb_main(void) target_reset(cur_target); else if(last_target) { cur_target = target_attach(last_target, - gdb_target_destroy_callback); + &gdb_controller); target_reset(cur_target); } break; @@ -241,8 +251,7 @@ gdb_main(void) ERROR_IF_NO_TARGET(); sscanf(pbuf, "X%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &bin); DEBUG("X packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len); - target_mem_write(cur_target, addr, pbuf+bin, len); - if(target_check_error(cur_target)) + if (target_mem_write(cur_target, addr, pbuf+bin, len)) gdb_putpacketz("E01"); else gdb_putpacketz("OK"); @@ -326,7 +335,7 @@ handle_q_packet(char *packet, int len) if((!cur_target) && last_target) { /* Attach to last target if detached. */ cur_target = target_attach(last_target, - gdb_target_destroy_callback); + &gdb_controller); } if (!cur_target) { gdb_putpacketz("E01"); @@ -339,7 +348,7 @@ handle_q_packet(char *packet, int len) if((!cur_target) && last_target) { /* Attach to last target if detached. */ cur_target = target_attach(last_target, - gdb_target_destroy_callback); + &gdb_controller); } if (!cur_target) { gdb_putpacketz("E01"); @@ -368,14 +377,7 @@ handle_v_packet(char *packet, int plen) if (sscanf(packet, "vAttach;%08lx", &addr) == 1) { /* Attach to remote target processor */ - target *t; - uint32_t i; - for(t = target_list, i = 1; t; t = t->next, i++) - if(i == addr) { - cur_target = target_attach(t, - gdb_target_destroy_callback); - break; - } + cur_target = target_attach_n(addr, &gdb_controller); if(cur_target) gdb_putpacketz("T05"); else @@ -388,7 +390,7 @@ handle_v_packet(char *packet, int plen) gdb_putpacketz("T05"); } else if(last_target) { cur_target = target_attach(last_target, - gdb_target_destroy_callback); + &gdb_controller); /* If we were able to attach to the target again */ if (cur_target) { @@ -449,31 +451,22 @@ handle_z_packet(char *packet, int plen) //sscanf(packet, "%*[zZ]%hhd,%08lX,%hhd", &type, &addr, &len); type = packet[1] - '0'; sscanf(packet + 2, ",%" PRIx32 ",%d", &addr, &len); - switch(type) { - case 1: /* Hardware breakpoint */ - if(set) - ret = target_set_hw_bp(cur_target, addr, len); - else - ret = target_clear_hw_bp(cur_target, addr, len); - break; - - case 2: - case 3: - case 4: - if(set) - ret = target_set_hw_wp(cur_target, type, addr, len); - else - ret = target_clear_hw_wp(cur_target, type, addr, len); - break; - - default: - gdb_putpacketz(""); - return; - } - - if(!ret) - gdb_putpacketz("OK"); + if(set) + ret = target_breakwatch_set(cur_target, type, addr, len); else + ret = target_breakwatch_clear(cur_target, type, addr, len); + + if (ret < 0) { gdb_putpacketz("E01"); + } else if (ret > 0) { + gdb_putpacketz(""); + } else { + gdb_putpacketz("OK"); + } +} + +void gdb_main(void) +{ + gdb_main_loop(&gdb_controller, false); } diff --git a/src/gdb_packet.c b/src/gdb_packet.c index 9ce63f2..f738996 100644 --- a/src/gdb_packet.c +++ b/src/gdb_packet.c @@ -153,16 +153,21 @@ void gdb_out(const char *buf) gdb_putpacket(hexdata, i); } -void gdb_outf(const char *fmt, ...) +void gdb_voutf(const char *fmt, va_list ap) { - va_list ap; char *buf; - va_start(ap, fmt); if (vasprintf(&buf, fmt, ap) < 0) return; gdb_out(buf); free(buf); - va_end(ap); } +void gdb_outf(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + gdb_voutf(fmt, ap); + va_end(ap); +} diff --git a/src/include/command.h b/src/include/command.h index 3910bbb..539af5c 100644 --- a/src/include/command.h +++ b/src/include/command.h @@ -24,14 +24,6 @@ #include "target.h" int command_process(target *t, char *cmd); -typedef bool (*cmd_handler)(target *t, int argc, const char **argv); - -struct command_s { - const char *cmd; - cmd_handler handler; - - const char *help; -}; #endif diff --git a/src/include/crc32.h b/src/include/crc32.h index bd8d5c4..4e0f729 100644 --- a/src/include/crc32.h +++ b/src/include/crc32.h @@ -21,7 +21,6 @@ #ifndef __CRC32_H #define __CRC32_H -uint32_t crc32_calc(uint32_t crc, uint8_t data); uint32_t generic_crc32(target *t, uint32_t base, int len); #endif diff --git a/src/include/gdb_packet.h b/src/include/gdb_packet.h index aa1a654..789cfa1 100644 --- a/src/include/gdb_packet.h +++ b/src/include/gdb_packet.h @@ -21,12 +21,15 @@ #ifndef __GDB_PACKET_H #define __GDB_PACKET_H +#include + int gdb_getpacket(char *packet, int size); void gdb_putpacket(const char *packet, int size); #define gdb_putpacketz(packet) gdb_putpacket((packet), strlen(packet)) void gdb_putpacket_f(const char *packet, ...); void gdb_out(const char *buf); +void gdb_voutf(const char *fmt, va_list); void gdb_outf(const char *fmt, ...); #endif diff --git a/src/include/stm32lx-nvm.h b/src/include/stm32lx-nvm.h deleted file mode 100644 index 2e9d8c5..0000000 --- a/src/include/stm32lx-nvm.h +++ /dev/null @@ -1,190 +0,0 @@ -/* @file stm32lx-nvm.h - * - * This file is part of the Black Magic Debug project. - * - * Copyright (C) 2014 Woollysoft - * Written by Marc Singer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#if !defined (STM32Lx_NVM_H_INCLUDED) -# define STM32Lx_NVM_H_INCLUDED - -/* ----- Includes */ - -#include - -/* ----- Macros */ - -/* ----- Types */ - -enum { - STM32Lx_STUB_PHYS = 0x20000000ul, - STM32Lx_STUB_INFO_PHYS = 0x20000004ul, - STM32Lx_STUB_DATA_PHYS = (0x20000000ul + 1024), - STM32Lx_STUB_DATA_MAX = 2048, - - STM32Lx_NVM_OPT_PHYS = 0x1ff80000ul, - STM32Lx_NVM_EEPROM_PHYS = 0x08080000ul, - - STM32L0_NVM_PHYS = 0x40022000ul, - STM32L0_NVM_PROG_PAGE_SIZE = 128, - STM32L0_NVM_DATA_PAGE_SIZE = 4, - STM32L0_NVM_OPT_SIZE = 12, - STM32L0_NVM_EEPROM_SIZE = 2*1024, - - STM32L1_NVM_PHYS = 0x40023c00ul, - STM32L1_NVM_PROG_PAGE_SIZE = 256, - STM32L1_NVM_DATA_PAGE_SIZE = 4, - STM32L1_NVM_OPT_SIZE = 32, - STM32L1_NVM_EEPROM_SIZE = 16*1024, - - STM32Lx_NVM_PEKEY1 = 0x89abcdeful, - STM32Lx_NVM_PEKEY2 = 0x02030405ul, - STM32Lx_NVM_PRGKEY1 = 0x8c9daebful, - STM32Lx_NVM_PRGKEY2 = 0x13141516ul, - STM32Lx_NVM_OPTKEY1 = 0xfbead9c8ul, - STM32Lx_NVM_OPTKEY2 = 0x24252627ul, - - STM32Lx_NVM_PECR_OBL_LAUNCH = (1<<18), - STM32Lx_NVM_PECR_ERRIE = (1<<17), - STM32Lx_NVM_PECR_EOPIE = (1<<16), - STM32Lx_NVM_PECR_FPRG = (1<<10), - STM32Lx_NVM_PECR_ERASE = (1<< 9), - STM32Lx_NVM_PECR_FIX = (1<< 8), /* FTDW */ - STM32Lx_NVM_PECR_DATA = (1<< 4), - STM32Lx_NVM_PECR_PROG = (1<< 3), - STM32Lx_NVM_PECR_OPTLOCK = (1<< 2), - STM32Lx_NVM_PECR_PRGLOCK = (1<< 1), - STM32Lx_NVM_PECR_PELOCK = (1<< 0), - - STM32Lx_NVM_SR_FWWERR = (1<<17), - STM32Lx_NVM_SR_NOTZEROERR = (1<<16), - STM32Lx_NVM_SR_RDERR = (1<<13), - STM32Lx_NVM_SR_OPTVER = (1<<11), - STM32Lx_NVM_SR_SIZERR = (1<<10), - STM32Lx_NVM_SR_PGAERR = (1<<9), - STM32Lx_NVM_SR_WRPERR = (1<<8), - STM32Lx_NVM_SR_READY = (1<<3), - STM32Lx_NVM_SR_HWOFF = (1<<2), - STM32Lx_NVM_SR_EOP = (1<<1), - STM32Lx_NVM_SR_BSY = (1<<0), - STM32Lx_NVM_SR_ERR_M = ( STM32Lx_NVM_SR_WRPERR - | STM32Lx_NVM_SR_PGAERR - | STM32Lx_NVM_SR_SIZERR - | STM32Lx_NVM_SR_NOTZEROERR), - - STM32L0_NVM_OPTR_BOOT1 = (1<<31), - STM32L0_NVM_OPTR_WDG_SW = (1<<20), - STM32L0_NVM_OPTR_WPRMOD = (1<<8), - STM32L0_NVM_OPTR_RDPROT_S = (0), - STM32L0_NVM_OPTR_RDPROT_M = (0xff), - STM32L0_NVM_OPTR_RDPROT_0 = (0xaa), - STM32L0_NVM_OPTR_RDPROT_2 = (0xcc), - - STM32L1_NVM_OPTR_nBFB2 = (1<<23), - STM32L1_NVM_OPTR_nRST_STDBY = (1<<22), - STM32L1_NVM_OPTR_nRST_STOP = (1<<21), - STM32L1_NVM_OPTR_WDG_SW = (1<<20), - STM32L1_NVM_OPTR_BOR_LEV_S = (16), - STM32L1_NVM_OPTR_BOR_LEV_M = (0xf), - STM32L1_NVM_OPTR_SPRMOD = (1<<8), - STM32L1_NVM_OPTR_RDPROT_S = (0), - STM32L1_NVM_OPTR_RDPROT_M = (0xff), - STM32L1_NVM_OPTR_RDPROT_0 = (0xaa), - STM32L1_NVM_OPTR_RDPROT_2 = (0xcc), - -}; - -#if defined (__cplusplus) - -namespace STM32 { - struct NVM { - volatile uint32_t acr; - volatile uint32_t pecr; - volatile uint32_t pdkeyr; - volatile uint32_t pkeyr; - volatile uint32_t prgkeyr; - volatile uint32_t optkeyr; - volatile uint32_t sr; - volatile uint32_t optr; - volatile uint32_t wrprot; - - static constexpr uint32_t PKEY1 = 0x89abcdef; - static constexpr uint32_t PKEY2 = 0x02030405; - static constexpr uint32_t PRGKEY1 = 0x8c9daebf; - static constexpr uint32_t PRGKEY2 = 0x13141516; - static constexpr uint32_t OPTKEY1 = 0xfbead9c8; - static constexpr uint32_t OPTKEY2 = 0x24252627; - static constexpr uint32_t PDKEY1 = 0x04152637; - static constexpr uint32_t PDKEY2 = 0xfafbfcfd; - }; - - static_assert(sizeof (NVM) == 9*4, "NVM size error"); -} -using stm32lx_stub_pointer_t = uint32_t*; - -#define Nvm(nvm) (*reinterpret_cast(nvm)) -#define Info (*reinterpret_cast(STM32Lx_STUB_INFO_PHYS)) - -namespace { - inline __attribute((always_inline)) bool unlock (STM32::NVM& nvm) { - // Lock guarantees unlock - nvm.pecr = STM32Lx_NVM_PECR_PELOCK; - - nvm.pkeyr = STM32::NVM::PKEY1; - nvm.pkeyr = STM32::NVM::PKEY2; - nvm.prgkeyr = STM32::NVM::PRGKEY1; - nvm.prgkeyr = STM32::NVM::PRGKEY2; - return !(nvm.pecr & STM32Lx_NVM_PECR_PRGLOCK); - } - inline __attribute((always_inline)) void lock (STM32::NVM& nvm) { - nvm.pecr = STM32Lx_NVM_PECR_PELOCK; } - -} - -#else - -typedef uint32_t stm32lx_stub_pointer_t; - -#define STM32Lx_NVM_PECR(p) ((p) + 0x04) -#define STM32Lx_NVM_PEKEYR(p) ((p) + 0x0C) -#define STM32Lx_NVM_PRGKEYR(p) ((p) + 0x10) -#define STM32Lx_NVM_OPTKEYR(p) ((p) + 0x14) -#define STM32Lx_NVM_SR(p) ((p) + 0x18) -#define STM32Lx_NVM_OPTR(p) ((p) + 0x1C) - -#endif - -enum { - OPT_STM32L1 = 1<<1, -}; - -struct stm32lx_nvm_stub_info { - stm32lx_stub_pointer_t destination; - int32_t size; - stm32lx_stub_pointer_t source; - uint32_t nvm; - uint16_t page_size; - uint16_t options; -} __attribute__((packed)); - -/* ----- Globals */ - -/* ----- Prototypes */ - - - -#endif /* STM32Lx_NVM_H_INCLUDED */ diff --git a/src/include/swdptap.h b/src/include/swdptap.h index 3263a1d..c51a28c 100644 --- a/src/include/swdptap.h +++ b/src/include/swdptap.h @@ -22,10 +22,14 @@ #define __SWDPTAP_H int swdptap_init(void); -void swdptap_reset(void); +/* Primitive functions */ +bool swdptap_bit_in(void); +void swdptap_bit_out(bool val); + +/* High level functions, provided as weak in swdptap_generic.c */ uint32_t swdptap_seq_in(int ticks); -uint8_t swdptap_seq_in_parity(uint32_t *data, int ticks); +bool swdptap_seq_in_parity(uint32_t *data, int ticks); void swdptap_seq_out(uint32_t MS, int ticks); void swdptap_seq_out_parity(uint32_t MS, int ticks); diff --git a/src/include/target.h b/src/include/target.h index e0839a2..83afb03 100644 --- a/src/include/target.h +++ b/src/include/target.h @@ -1,7 +1,7 @@ /* * This file is part of the Black Magic Debug project. * - * Copyright (C) 2011 Black Sphere Technologies Ltd. + * Copyright (C) 2016 Black Sphere Technologies Ltd. * Written by Gareth McMullin * * This program is free software: you can redistribute it and/or modify @@ -25,252 +25,140 @@ #ifndef __TARGET_H #define __TARGET_H +#include + typedef struct target_s target; +typedef uint32_t target_addr; +struct target_controller; -/* The destroy callback function will be called by target_list_free() just - * before the target is free'd. This may be because we're scanning for new - * targets, or because of a communication failure. The target data may - * be assumed to be intact, but the communication medium may not be available, - * so access methods shouldn't be called. - * - * The callback is installed by target_attach() and only removed by attaching - * with a different callback. It remains intact after target_detach(). - */ -typedef void (*target_destroy_callback)(target *t); +int adiv5_swdp_scan(void); +int jtag_scan(const uint8_t *lrlens); -/* Halt/resume functions */ -target *target_attach(target *t, target_destroy_callback destroy_cb); +bool target_foreach(void (*cb)(int i, target *t, void *context), void *context); +void target_list_free(void); -#define target_detach(target) \ - (target)->detach(target) - -#define target_check_error(target) \ - (target)->check_error(target) +/* Attach/detach functions */ +target *target_attach(target *t, struct target_controller *); +target *target_attach_n(int n, struct target_controller *); +void target_detach(target *t); +bool target_attached(target *t); +const char *target_driver_name(target *t); /* Memory access functions */ -#define target_mem_read(target, dest, src, len) \ - (target)->mem_read((target), (dest), (src), (len)) - -#define target_mem_write(target, dest, src, len) \ - (target)->mem_write((target), (dest), (src), (len)) - -/* Register access functions */ -#define target_regs_read(target, data) \ - (target)->regs_read((target), (data)) - -#define target_regs_write(target, data) \ - (target)->regs_write((target), (data)) - - -/* Halt/resume functions */ -#define target_reset(target) \ - (target)->reset(target) - -#define target_halt_request(target) \ - (target)->halt_request(target) - -#define target_halt_wait(target) \ - (target)->halt_wait(target) - -#define target_halt_resume(target, step) \ - (target)->halt_resume((target), (step)) - -/* Break-/watchpoint functions */ -#define target_set_hw_bp(target, addr, len) \ - (target)->set_hw_bp((target), (addr), (len)) - -#define target_clear_hw_bp(target, addr, len) \ - (target)->clear_hw_bp((target), (addr), (len)) - - -#define target_set_hw_wp(target, type, addr, len) \ - (target)->set_hw_wp((target), (type), (addr), (len)) - -#define target_clear_hw_wp(target, type, addr, len) \ - (target)->clear_hw_wp((target), (type), (addr), (len)) - - -#define target_check_hw_wp(target, addr) \ - ((target)->check_hw_wp?(target)->check_hw_wp((target), (addr)):0) - - +const char *target_mem_map(target *t); +int target_mem_read(target *t, void *dest, target_addr src, size_t len); +int target_mem_write(target *t, target_addr dest, const void *src, size_t len); /* Flash memory access functions */ -int target_flash_erase(target *t, uint32_t addr, size_t len); -int target_flash_write(target *t, - uint32_t dest, const void *src, size_t len); +int target_flash_erase(target *t, target_addr addr, size_t len); +int target_flash_write(target *t, target_addr dest, const void *src, size_t len); int target_flash_done(target *t); -/* Host I/O */ -#define target_hostio_reply(target, recode, errcode) \ - (target)->hostio_reply((target), (retcode), (errcode)) +/* Register access functions */ +size_t target_regs_size(target *t); +const char *target_tdesc(target *t); +void target_regs_read(target *t, void *data); +void target_regs_write(target *t, const void *data); -/* Accessor functions */ -#define target_regs_size(target) \ - ((target)->regs_size) - -#define target_tdesc(target) \ - ((target)->tdesc ? (target)->tdesc : "") - -struct target_ram { - uint32_t start; - uint32_t length; - struct target_ram *next; +/* Halt/resume functions */ +enum target_halt_reason { + TARGET_HALT_RUNNING = 0, /* Target not halted */ + TARGET_HALT_ERROR, /* Failed to read target status */ + TARGET_HALT_REQUEST, + TARGET_HALT_STEPPING, + TARGET_HALT_BREAKPOINT, + TARGET_HALT_WATCHPOINT, + TARGET_HALT_FAULT, }; -struct target_flash; -typedef int (*flash_erase_func)(struct target_flash *f, uint32_t addr, size_t len); -typedef int (*flash_write_func)(struct target_flash *f, uint32_t dest, - const void *src, size_t len); -typedef int (*flash_done_func)(struct target_flash *f); -struct target_flash { - uint32_t start; - uint32_t length; - uint32_t blocksize; - flash_erase_func erase; - flash_write_func write; - flash_done_func done; - target *t; - struct target_flash *next; - int align; - uint8_t erased; +void target_reset(target *t); +void target_halt_request(target *t); +enum target_halt_reason target_halt_poll(target *t, target_addr *watch); +void target_halt_resume(target *t, bool step); - /* For buffered flash */ - size_t buf_size; - flash_write_func write_buf; - uint32_t buf_addr; - void *buf; +/* Break-/watchpoint functions */ +enum target_breakwatch { + TARGET_BREAK_SOFT, + TARGET_BREAK_HARD, + TARGET_WATCH_WRITE, + TARGET_WATCH_READ, + TARGET_WATCH_ACCESS, +}; +int target_breakwatch_set(target *t, enum target_breakwatch, target_addr, size_t); +int target_breakwatch_clear(target *t, enum target_breakwatch, target_addr, size_t); + +/* Command interpreter */ +void target_command_help(target *t); +int target_command(target *t, int argc, const char *argv[]); + + +enum target_errno { + TARGET_EPERM = 1, + TARGET_ENOENT = 2, + TARGET_EINTR = 4, + TARGET_EBADF = 9, + TARGET_EACCES = 13, + TARGET_EFAULT = 14, + TARGET_EBUSY = 16, + TARGET_EEXIST = 17, + TARGET_ENODEV = 19, + TARGET_ENOTDIR = 20, + TARGET_EISDIR = 21, + TARGET_EINVAL = 22, + TARGET_EMFILE = 24, + TARGET_ENFILE = 23, + TARGET_EFBIG = 27, + TARGET_ENOSPC = 28, + TARGET_ESPIPE = 29, + TARGET_EROFS = 30, + TARGET_ENAMETOOLONG = 36, }; -struct target_s { - /* Notify controlling debugger if target is lost */ - target_destroy_callback destroy_callback; - - /* Attach/Detach funcitons */ - bool (*attach)(target *t); - void (*detach)(target *t); - bool (*check_error)(target *t); - - /* Memory access functions */ - void (*mem_read)(target *t, void *dest, uint32_t src, - size_t len); - void (*mem_write)(target *t, uint32_t dest, - const void *src, size_t len); - - /* Register access functions */ - int regs_size; - const char *tdesc; - void (*regs_read)(target *t, void *data); - void (*regs_write)(target *t, const void *data); - - /* Halt/resume functions */ - void (*reset)(target *t); - void (*halt_request)(target *t); - int (*halt_wait)(target *t); - void (*halt_resume)(target *t, bool step); - - /* Break-/watchpoint functions */ - int (*set_hw_bp)(target *t, uint32_t addr, uint8_t len); - int (*clear_hw_bp)(target *t, uint32_t addr, uint8_t len); - - int (*set_hw_wp)(target *t, uint8_t type, uint32_t addr, uint8_t len); - int (*clear_hw_wp)(target *t, uint8_t type, uint32_t addr, uint8_t len); - - int (*check_hw_wp)(target *t, uint32_t *addr); - - /* target-defined options */ - unsigned target_options; - uint32_t idcode; - - /* Target memory map */ - char *dyn_mem_map; - struct target_ram *ram; - struct target_flash *flash; - - /* Host I/O support */ - void (*hostio_reply)(target *t, int32_t retcode, uint32_t errcode); - - const char *driver; - struct target_command_s *commands; - - int size; - struct target_s *next; - - void *priv; - void (*priv_free)(void *); +enum target_open_flags { + TARGET_O_RDONLY = 0, + TARGET_O_WRONLY = 1, + TARGET_O_RDWR = 2, + TARGET_O_APPEND = 0x008, + TARGET_O_CREAT = 0x200, + TARGET_O_TRUNC = 0x400, }; -struct target_command_s { - const char *specific_name; - const struct command_s *cmds; - struct target_command_s *next; +enum target_seek_flag { + TARGET_SEEK_SET = 0, + TARGET_SEEK_CUR = 1, + TARGET_SEEK_END = 2, }; -extern target *target_list; +struct target_controller { + void (*destroy_callback)(struct target_controller *, target *t); + void (*printf)(struct target_controller *, const char *fmt, va_list); -target *target_new(unsigned size); -void target_list_free(void); -void target_add_commands(target *t, const struct command_s *cmds, const char *name); -void target_add_ram(target *t, uint32_t start, uint32_t len); -void target_add_flash(target *t, struct target_flash *f); -const char *target_mem_map(target *t); -int target_flash_write_buffered(struct target_flash *f, - uint32_t dest, const void *src, size_t len); -int target_flash_done_buffered(struct target_flash *f); - -static inline uint32_t target_mem_read32(target *t, uint32_t addr) -{ - uint32_t ret; - target_mem_read(t, &ret, addr, sizeof(ret)); - return ret; -} - -static inline void target_mem_write32(target *t, uint32_t addr, uint32_t value) -{ - target_mem_write(t, addr, &value, sizeof(value)); -} - -static inline uint16_t target_mem_read16(target *t, uint32_t addr) -{ - uint16_t ret; - target_mem_read(t, &ret, addr, sizeof(ret)); - return ret; -} - -static inline void target_mem_write16(target *t, uint32_t addr, uint16_t value) -{ - target_mem_write(t, addr, &value, sizeof(value)); -} - -static inline uint8_t target_mem_read8(target *t, uint32_t addr) -{ - uint8_t ret; - target_mem_read(t, &ret, addr, sizeof(ret)); - return ret; -} - -static inline void target_mem_write8(target *t, uint32_t addr, uint8_t value) -{ - target_mem_write(t, addr, &value, sizeof(value)); -} - - -/* Probe for various targets. - * Actual functions implemented in their respective drivers. - */ -bool stm32f1_probe(target *t); -bool stm32f4_probe(target *t); -bool stm32l0_probe(target *t); -bool stm32l1_probe(target *t); -bool stm32l4_probe(target *t); -bool lmi_probe(target *t); -bool lpc11xx_probe(target *t); -bool lpc15xx_probe(target *t); -bool lpc43xx_probe(target *t); -bool sam3x_probe(target *t); -bool nrf51_probe(target *t); -bool samd_probe(target *t); -bool kinetis_probe(target *t); -bool efm32_probe(target *t); + /* Interface to host system calls */ + int (*open)(struct target_controller *, + target_addr path, size_t path_len, + enum target_open_flags flags, mode_t mode); + int (*close)(struct target_controller *, int fd); + int (*read)(struct target_controller *, + int fd, target_addr buf, unsigned int count); + int (*write)(struct target_controller *, + int fd, target_addr buf, unsigned int count); + long (*lseek)(struct target_controller *, + int fd, long offset, enum target_seek_flag flag); + int (*rename)(struct target_controller *, + target_addr oldpath, size_t old_len, + target_addr newpath, size_t new_len); + int (*unlink)(struct target_controller *, + target_addr path, size_t path_len); + int (*stat)(struct target_controller *, + target_addr path, size_t path_len, target_addr buf); + int (*fstat)(struct target_controller *, int fd, target_addr buf); + int (*gettimeofday)(struct target_controller *, + target_addr tv, target_addr tz); + int (*isatty)(struct target_controller *, int fd); + int (*system)(struct target_controller *, + target_addr cmd, size_t cmd_len); + enum target_errno errno_; + bool interrupted; +}; #endif diff --git a/src/main.c b/src/main.c index 9f37107..de11953 100644 --- a/src/main.c +++ b/src/main.c @@ -25,8 +25,6 @@ #include "general.h" #include "gdb_if.h" #include "gdb_main.h" -#include "jtagtap.h" -#include "jtag_scan.h" #include "target.h" #include "exception.h" #include "gdb_packet.h" diff --git a/src/platforms/stm32/swdptap.c b/src/platforms/common/swdptap.c similarity index 57% rename from src/platforms/stm32/swdptap.c rename to src/platforms/common/swdptap.c index e7049d3..bcc3ccb 100644 --- a/src/platforms/stm32/swdptap.c +++ b/src/platforms/common/swdptap.c @@ -20,24 +20,24 @@ /* This file implements the low-level SW-DP interface. */ -#include - #include "general.h" - #include "swdptap.h" -#include "gdb_packet.h" +int swdptap_init(void) +{ + return 0; +} static void swdptap_turnaround(uint8_t dir) { static uint8_t olddir = 0; - DEBUG("%s", dir ? "\n-> ":"\n<- "); - /* Don't turnaround if direction not changing */ if(dir == olddir) return; olddir = dir; + DEBUG("%s", dir ? "\n-> ":"\n<- "); + if(dir) SWDIO_MODE_FLOAT(); gpio_set(SWCLK_PORT, SWCLK_PIN); @@ -46,10 +46,12 @@ static void swdptap_turnaround(uint8_t dir) SWDIO_MODE_DRIVE(); } -static uint8_t swdptap_bit_in(void) +bool swdptap_bit_in(void) { uint16_t ret; + swdptap_turnaround(1); + ret = gpio_get(SWDIO_PORT, SWDIO_PIN); gpio_set(SWCLK_PORT, SWCLK_PIN); gpio_clear(SWCLK_PORT, SWCLK_PIN); @@ -59,95 +61,14 @@ static uint8_t swdptap_bit_in(void) return ret != 0; } -static void swdptap_bit_out(uint8_t val) +void swdptap_bit_out(bool val) { DEBUG("%d", val); + swdptap_turnaround(0); + gpio_set_val(SWDIO_PORT, SWDIO_PIN, val); gpio_set(SWCLK_PORT, SWCLK_PIN); gpio_clear(SWCLK_PORT, SWCLK_PIN); } -int swdptap_init(void) -{ - /* This must be investigated in more detail. - * As described in STM32 Reference Manual... */ - swdptap_reset(); - swdptap_seq_out(0xE79E, 16); /* 0b0111100111100111 */ - swdptap_reset(); - swdptap_seq_out(0, 16); - - return 0; -} - - -void swdptap_reset(void) -{ - swdptap_turnaround(0); - /* 50 clocks with TMS high */ - for(int i = 0; i < 50; i++) swdptap_bit_out(1); -} - - -uint32_t swdptap_seq_in(int ticks) -{ - uint32_t index = 1; - uint32_t ret = 0; - - swdptap_turnaround(1); - - while(ticks--) { - if(swdptap_bit_in()) ret |= index; - index <<= 1; - } - - return ret; -} - - -uint8_t swdptap_seq_in_parity(uint32_t *ret, int ticks) -{ - uint32_t index = 1; - uint8_t parity = 0; - *ret = 0; - - swdptap_turnaround(1); - - while(ticks--) { - if(swdptap_bit_in()) { - *ret |= index; - parity ^= 1; - } - index <<= 1; - } - if(swdptap_bit_in()) parity ^= 1; - - return parity; -} - - -void swdptap_seq_out(uint32_t MS, int ticks) -{ - swdptap_turnaround(0); - - while(ticks--) { - swdptap_bit_out(MS & 1); - MS >>= 1; - } -} - - -void swdptap_seq_out_parity(uint32_t MS, int ticks) -{ - uint8_t parity = 0; - - swdptap_turnaround(0); - - while(ticks--) { - swdptap_bit_out(MS & 1); - parity ^= MS; - MS >>= 1; - } - swdptap_bit_out(parity & 1); -} - diff --git a/src/platforms/libftdi/swdptap.c b/src/platforms/libftdi/swdptap.c index 6aafa7d..c48fb1a 100644 --- a/src/platforms/libftdi/swdptap.c +++ b/src/platforms/libftdi/swdptap.c @@ -29,9 +29,7 @@ #include "general.h" #include "swdptap.h" -static void swdptap_turnaround(uint8_t dir); -static uint8_t swdptap_bit_in(void); -static void swdptap_bit_out(uint8_t val); +static uint8_t olddir = 0; int swdptap_init(void) { @@ -46,33 +44,17 @@ int swdptap_init(void) } assert(ftdi_write_data(ftdic, (void*)"\xAB\xA8", 2) == 2); - - /* This must be investigated in more detail. - * As described in STM32 Reference Manual... */ - swdptap_seq_out(0xFFFF, 16); - swdptap_reset(); - swdptap_seq_out(0xE79E, 16); /* 0b0111100111100111 */ - swdptap_reset(); - swdptap_seq_out(0, 16); + olddir = 0; return 0; } -void swdptap_reset(void) -{ - swdptap_turnaround(0); - /* 50 clocks with TMS high */ - for(int i = 0; i < 50; i++) - swdptap_bit_out(1); -} - static void swdptap_turnaround(uint8_t dir) { - static uint8_t olddir = 0; - platform_buffer_flush(); - if(dir == olddir) return; + if (dir == olddir) + return; olddir = dir; if(dir) /* SWDIO goes to input */ @@ -85,10 +67,12 @@ static void swdptap_turnaround(uint8_t dir) assert(ftdi_set_bitmode(ftdic, 0xAB, BITMODE_BITBANG) == 0); } -static uint8_t swdptap_bit_in(void) +bool swdptap_bit_in(void) { uint8_t ret; + swdptap_turnaround(1); + ftdi_read_pins(ftdic, &ret); ret &= 0x08; ftdi_write_data(ftdic, (void *)"\xA1\xA0", 2); @@ -96,75 +80,16 @@ static uint8_t swdptap_bit_in(void) return ret; } -static void swdptap_bit_out(uint8_t val) +void swdptap_bit_out(bool val) { uint8_t buf[3] = "\xA0\xA1\xA0"; - if(val) { + swdptap_turnaround(0); + + if (val) { for(int i = 0; i < 3; i++) buf[i] |= 0x08; } platform_buffer_write(buf, 3); } -uint32_t swdptap_seq_in(int ticks) -{ - uint32_t index = 1; - uint32_t ret = 0; - - swdptap_turnaround(1); - - while (ticks--) { - if (swdptap_bit_in()) - ret |= index; - index <<= 1; - } - - return ret; -} - -uint8_t swdptap_seq_in_parity(uint32_t *ret, int ticks) -{ - uint32_t index = 1; - uint8_t parity = 0; - *ret = 0; - - swdptap_turnaround(1); - - while (ticks--) { - if (swdptap_bit_in()) { - *ret |= index; - parity ^= 1; - } - index <<= 1; - } - if (swdptap_bit_in()) - parity ^= 1; - - return parity; -} - -void swdptap_seq_out(uint32_t MS, int ticks) -{ - swdptap_turnaround(0); - - while (ticks--) { - swdptap_bit_out(MS & 1); - MS >>= 1; - } -} - -void swdptap_seq_out_parity(uint32_t MS, int ticks) -{ - uint8_t parity = 0; - - swdptap_turnaround(0); - - while (ticks--) { - swdptap_bit_out(MS & 1); - parity ^= MS; - MS >>= 1; - } - swdptap_bit_out(parity & 1); -} - diff --git a/src/platforms/stm32/jtagtap.c b/src/platforms/stm32/jtagtap.c index baaa149..ecd0698 100644 --- a/src/platforms/stm32/jtagtap.c +++ b/src/platforms/stm32/jtagtap.c @@ -66,11 +66,3 @@ inline uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDO) return ret != 0; } - - -#define PROVIDE_GENERIC_JTAGTAP_TMS_SEQ -#define PROVIDE_GENERIC_JTAGTAP_TDI_TDO_SEQ -#define PROVIDE_GENERIC_JTAGTAP_TDI_SEQ - -#include "jtagtap_generic.c" - diff --git a/src/platforms/tm4c/jtagtap.c b/src/platforms/tm4c/jtagtap.c index c32a437..c6b8d7e 100644 --- a/src/platforms/tm4c/jtagtap.c +++ b/src/platforms/tm4c/jtagtap.c @@ -41,7 +41,3 @@ jtagtap_next(const uint8_t dTMS, const uint8_t dTDO) return ret != 0; } -#define PROVIDE_GENERIC_JTAGTAP_TMS_SEQ -#define PROVIDE_GENERIC_JTAGTAP_TDI_TDO_SEQ -#define PROVIDE_GENERIC_JTAGTAP_TDI_SEQ -#include "jtagtap_generic.c" diff --git a/src/platforms/tm4c/swdptap.c b/src/platforms/tm4c/swdptap.c deleted file mode 100644 index 058f6ba..0000000 --- a/src/platforms/tm4c/swdptap.c +++ /dev/null @@ -1,124 +0,0 @@ -#include "general.h" -#include "swdptap.h" - -static void swdptap_turnaround(uint8_t dir) -{ - static uint8_t olddir = 0; - - DEBUG("%s", dir ? "\n-> ":"\n<- "); - - /* Don't turnaround if direction not changing */ - if(dir == olddir) return; - olddir = dir; - - if(dir) - SWDIO_MODE_FLOAT(); - gpio_set(SWCLK_PORT, SWCLK_PIN); - gpio_clear(SWCLK_PORT, SWCLK_PIN); - if(!dir) - SWDIO_MODE_DRIVE(); -} - -static uint8_t swdptap_bit_in(void) -{ - uint16_t ret; - - ret = gpio_get(SWDIO_PORT, SWDIO_PIN); - gpio_set(SWCLK_PORT, SWCLK_PIN); - gpio_clear(SWCLK_PORT, SWCLK_PIN); - - DEBUG("%d", ret?1:0); - - return ret != 0; -} - -static void swdptap_bit_out(uint8_t val) -{ - DEBUG("%d", val); - - gpio_set_val(SWDIO_PORT, SWDIO_PIN, val); - gpio_set(SWCLK_PORT, SWCLK_PIN); - gpio_clear(SWCLK_PORT, SWCLK_PIN); -} - -int -swdptap_init(void) -{ - swdptap_reset(); - swdptap_seq_out(0xE79E, 16); /* 0b0111100111100111 */ - swdptap_reset(); - swdptap_seq_out(0, 16); - - return 0; -} - -void -swdptap_reset(void) -{ - swdptap_turnaround(0); - /* 50 clocks with TMS high */ - for(int i = 0; i < 50; i++) swdptap_bit_out(1); -} - -uint32_t -swdptap_seq_in(int ticks) -{ - uint32_t index = 1; - uint32_t ret = 0; - - swdptap_turnaround(1); - - while(ticks--) { - if(swdptap_bit_in()) ret |= index; - index <<= 1; - } - - return ret; -} - -uint8_t -swdptap_seq_in_parity(uint32_t *ret, int ticks) -{ - uint32_t index = 1; - uint8_t parity = 0; - *ret = 0; - - swdptap_turnaround(1); - - while(ticks--) { - if(swdptap_bit_in()) { - *ret |= index; - parity ^= 1; - } - index <<= 1; - } - if(swdptap_bit_in()) parity ^= 1; - - return parity; -} - -void -swdptap_seq_out(uint32_t MS, int ticks) -{ - swdptap_turnaround(0); - - while(ticks--) { - swdptap_bit_out(MS & 1); - MS >>= 1; - } -} - -void -swdptap_seq_out_parity(uint32_t MS, int ticks) -{ - uint8_t parity = 0; - - swdptap_turnaround(0); - - while(ticks--) { - swdptap_bit_out(MS & 1); - parity ^= MS; - MS >>= 1; - } - swdptap_bit_out(parity & 1); -} diff --git a/src/target.c b/src/target.c deleted file mode 100644 index 5e44c48..0000000 --- a/src/target.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * This file is part of the Black Magic Debug project. - * - * Copyright (C) 2012 Black Sphere Technologies Ltd. - * Written by Gareth McMullin - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "general.h" -#include "target.h" - -target *target_list = NULL; - -target *target_new(unsigned size) -{ - target *t = (void*)calloc(1, size); - t->next = target_list; - target_list = t; - - return t; -} - -void target_list_free(void) -{ - struct target_command_s *tc; - - while(target_list) { - target *t = target_list->next; - if (target_list->destroy_callback) - target_list->destroy_callback(target_list); - if (target_list->priv) - target_list->priv_free(target_list->priv); - while (target_list->commands) { - tc = target_list->commands->next; - free(target_list->commands); - target_list->commands = tc; - } - if (target_list->dyn_mem_map) - free(target_list->dyn_mem_map); - while (target_list->ram) { - void * next = target_list->ram->next; - free(target_list->ram); - target_list->ram = next; - } - while (target_list->flash) { - void * next = target_list->flash->next; - if (target_list->flash->buf) - free(target_list->flash->buf); - free(target_list->flash); - target_list->flash = next; - } - free(target_list); - target_list = t; - } -} - -void target_add_commands(target *t, const struct command_s *cmds, const char *name) -{ - struct target_command_s *tc; - if (t->commands) { - for (tc = t->commands; tc->next; tc = tc->next); - tc = tc->next = malloc(sizeof(*tc)); - } else { - t->commands = tc = malloc(sizeof(*tc)); - } - tc->specific_name = name; - tc->cmds = cmds; - tc->next = NULL; -} - -target *target_attach(target *t, target_destroy_callback destroy_cb) -{ - if (t->destroy_callback) - t->destroy_callback(t); - - t->destroy_callback = destroy_cb; - - if (!t->attach(t)) - return NULL; - - return t; -} - -void target_add_ram(target *t, uint32_t start, uint32_t len) -{ - struct target_ram *ram = malloc(sizeof(*ram)); - ram->start = start; - ram->length = len; - ram->next = t->ram; - t->ram = ram; -} - -void target_add_flash(target *t, struct target_flash *f) -{ - f->t = t; - f->next = t->flash; - t->flash = f; -} - -static ssize_t map_ram(char *buf, size_t len, struct target_ram *ram) -{ - return snprintf(buf, len, "", - ram->start, ram->length); -} - -static ssize_t map_flash(char *buf, size_t len, struct target_flash *f) -{ - int i = 0; - i += snprintf(&buf[i], len - i, "", - f->start, f->length); - i += snprintf(&buf[i], len - i, "0x%08"PRIx32 - "", - f->blocksize); - return i; -} - -const char *target_mem_map(target *t) -{ - if (t->dyn_mem_map) - return t->dyn_mem_map; - - /* FIXME size buffer */ - size_t len = 1024; - char *tmp = malloc(len); - size_t i = 0; - i = snprintf(&tmp[i], len - i, ""); - /* Map each defined RAM */ - for (struct target_ram *r = t->ram; r; r = r->next) - i += map_ram(&tmp[i], len - i, r); - /* Map each defined Flash */ - for (struct target_flash *f = t->flash; f; f = f->next) - i += map_flash(&tmp[i], len - i, f); - i += snprintf(&tmp[i], len - i, ""); - - t->dyn_mem_map = tmp; - - return t->dyn_mem_map; -} - -static struct target_flash *flash_for_addr(target *t, uint32_t addr) -{ - for (struct target_flash *f = t->flash; f; f = f->next) - if ((f->start <= addr) && - (addr < (f->start + f->length))) - return f; - return NULL; -} - -int target_flash_erase(target *t, uint32_t addr, size_t len) -{ - int ret = 0; - while (len) { - struct target_flash *f = flash_for_addr(t, addr); - size_t tmplen = MIN(len, f->length - (addr % f->length)); - ret |= f->erase(f, addr, tmplen); - addr += tmplen; - len -= tmplen; - } - return ret; -} - -int target_flash_write(target *t, - uint32_t dest, const void *src, size_t len) -{ - int ret = 0; - while (len) { - struct target_flash *f = flash_for_addr(t, dest); - size_t tmplen = MIN(len, f->length - (dest % f->length)); - if (f->align > 1) { - uint32_t offset = dest % f->align; - uint8_t data[ALIGN(offset + len, f->align)]; - memset(data, f->erased, sizeof(data)); - memcpy((uint8_t *)data + offset, src, len); - ret |= f->write(f, dest - offset, data, sizeof(data)); - } else { - ret |= f->write(f, dest, src, tmplen); - } - src += tmplen; - len -= tmplen; - } - return ret; -} - -int target_flash_done(target *t) -{ - for (struct target_flash *f = t->flash; f; f = f->next) { - if (f->done) { - int tmp = f->done(f); - if (tmp) - return tmp; - } - } - return 0; -} - -int target_flash_write_buffered(struct target_flash *f, - uint32_t dest, const void *src, size_t len) -{ - int ret = 0; - - if (f->buf == NULL) { - /* Allocate flash sector buffer */ - f->buf = malloc(f->buf_size); - f->buf_addr = -1; - } - while (len) { - uint32_t offset = dest % f->buf_size; - uint32_t base = dest - offset; - if (base != f->buf_addr) { - if (f->buf_addr != (uint32_t)-1) { - /* Write sector to flash if valid */ - ret |= f->write_buf(f, f->buf_addr, - f->buf, f->buf_size); - } - /* Setup buffer for a new sector */ - f->buf_addr = base; - memset(f->buf, f->erased, f->buf_size); - } - /* Copy chunk into sector buffer */ - size_t sectlen = MIN(f->buf_size - offset, len); - memcpy(f->buf + offset, src, sectlen); - dest += sectlen; - src += sectlen; - len -= sectlen; - } - return ret; -} - -int target_flash_done_buffered(struct target_flash *f) -{ - int ret = 0; - if ((f->buf != NULL) &&(f->buf_addr != (uint32_t)-1)) { - /* Write sector to flash if valid */ - ret = f->write_buf(f, f->buf_addr, f->buf, f->buf_size); - f->buf_addr = -1; - free(f->buf); - f->buf = NULL; - } - - return ret; -} - - diff --git a/src/adiv5.c b/src/target/adiv5.c similarity index 96% rename from src/adiv5.c rename to src/target/adiv5.c index 478f5be..8a38057 100644 --- a/src/adiv5.c +++ b/src/target/adiv5.c @@ -22,8 +22,8 @@ * ARM Debug Interface v5 Architecure Specification, ARM doc IHI0031A. */ #include "general.h" -#include "jtag_scan.h" -#include "gdb_packet.h" +#include "target.h" +#include "target_internal.h" #include "adiv5.h" #include "cortexm.h" #include "exception.h" @@ -277,8 +277,6 @@ static void adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr) /* Extract Component ID class nibble */ uint32_t cid_class = (cidr & CID_CLASS_MASK) >> CID_CLASS_SHIFT; - DEBUG("0x%X: \"%s\"\n", addr, cidc_debug_strings[cid_class]); - if (cid_class == cidc_romtab) { /* ROM table, probe recursively */ for (int i = 0; i < 256; i++) { uint32_t entry = adiv5_mem_read32(ap, addr + i*4); @@ -304,15 +302,18 @@ static void adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr) /* Find the part number in our part list and run the appropriate probe * routine if applicable. */ - for (int i = 0; pidr_pn_bits[i].arch != aa_end; i++) { + int i; + for (i = 0; pidr_pn_bits[i].arch != aa_end; i++) { if (pidr_pn_bits[i].part_number == part_number) { - DEBUG("0x%X: %s %s\n", addr, + DEBUG("0x%X: %s - %s %s\n", addr, + cidc_debug_strings[cid_class], pidr_pn_bits[i].type, pidr_pn_bits[i].full); /* Perform sanity check, if we know what to expect as component ID * class. */ - if (cid_class != pidr_pn_bits[i].cidc) { + if ((pidr_pn_bits[i].cidc != cidc_unknown) && + (cid_class != pidr_pn_bits[i].cidc)) { DEBUG("WARNING: \"%s\" !match expected \"%s\"\n", cidc_debug_strings[cid_class], cidc_debug_strings[pidr_pn_bits[i].cidc]); @@ -327,11 +328,15 @@ static void adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr) cortexa_probe(ap, addr); break; default: - DEBUG("-> skip\n"); + break; } break; } } + if (pidr_pn_bits[i].arch == aa_end) { + DEBUG("0x%X: %s - Unknown (PIDR = 0x%"PRIx64")\n", addr, + cidc_debug_strings[cid_class], pidr); + } } } @@ -368,11 +373,11 @@ ADIv5_AP_t *adiv5_new_ap(ADIv5_DP_t *dp, uint8_t apsel) ~(ADIV5_AP_CSW_SIZE_MASK | ADIV5_AP_CSW_ADDRINC_MASK); if (ap->csw & ADIV5_AP_CSW_TRINPROG) { - gdb_out("AP transaction in progress. Target may not be usable.\n"); + DEBUG("AP transaction in progress. Target may not be usable.\n"); ap->csw &= ~ADIV5_AP_CSW_TRINPROG; } - DEBUG("%3d: IDR=%08X CFG=%08X BASE=%08X CSW=%08X\n", + DEBUG(" AP %3d: IDR=%08X CFG=%08X BASE=%08X CSW=%08X\n", apsel, ap->idr, ap->cfg, ap->base, ap->csw); return ap; @@ -390,7 +395,7 @@ void adiv5_dp_init(ADIv5_DP_t *dp) ctrlstat = adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT); } if (e.type) { - gdb_out("DP not responding! Trying abort sequence...\n"); + DEBUG("DP not responding! Trying abort sequence...\n"); adiv5_dp_abort(dp, ADIV5_DP_ABORT_DAPABORT); ctrlstat = adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT); } @@ -499,6 +504,9 @@ adiv5_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len) uint32_t osrc = src; enum align align = MIN(ALIGNOF(src), ALIGNOF(len)); + if (len == 0) + return; + len >>= align; ap_mem_access_setup(ap, src, align); adiv5_dp_low_access(ap->dp, ADIV5_LOW_READ, ADIV5_AP_DRW, 0); diff --git a/src/include/adiv5.h b/src/target/adiv5.h similarity index 99% rename from src/include/adiv5.h rename to src/target/adiv5.h index 6bebd3e..ca81471 100644 --- a/src/include/adiv5.h +++ b/src/target/adiv5.h @@ -164,7 +164,6 @@ void adiv5_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value); uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr); void adiv5_jtag_dp_handler(jtag_dev_t *dev); -int adiv5_swdp_scan(void); void adiv5_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len); void adiv5_mem_write(ADIv5_AP_t *ap, uint32_t dest, const void *src, size_t len); diff --git a/src/adiv5_jtagdp.c b/src/target/adiv5_jtagdp.c similarity index 100% rename from src/adiv5_jtagdp.c rename to src/target/adiv5_jtagdp.c diff --git a/src/adiv5_swdp.c b/src/target/adiv5_swdp.c similarity index 93% rename from src/adiv5_swdp.c rename to src/target/adiv5_swdp.c index 57d0e67..d62a18e 100644 --- a/src/adiv5_swdp.c +++ b/src/target/adiv5_swdp.c @@ -26,10 +26,8 @@ #include "exception.h" #include "adiv5.h" #include "swdptap.h" -#include "jtagtap.h" -#include "command.h" -#include "morse.h" -#include "gdb_packet.h" +#include "target.h" +#include "target_internal.h" #define SWDP_ACK_OK 0x01 #define SWDP_ACK_WAIT 0x02 @@ -52,6 +50,16 @@ int adiv5_swdp_scan(void) ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp)); swdptap_init(); + + /* Switch from JTAG to SWD mode */ + swdptap_seq_out(0xFFFF, 16); + for(int i = 0; i < 50; i++) + swdptap_bit_out(1); + swdptap_seq_out(0xE79E, 16); /* 0b0111100111100111 */ + for(int i = 0; i < 50; i++) + swdptap_bit_out(1); + swdptap_seq_out(0, 16); + /* Read the SW-DP IDCODE register to syncronise */ /* This could be done with adiv_swdp_low_access(), but this doesn't * allow the ack to be checked here. */ @@ -59,7 +67,6 @@ int adiv5_swdp_scan(void) ack = swdptap_seq_in(3); if((ack != SWDP_ACK_OK) || swdptap_seq_in_parity(&dp->idcode, 32)) { DEBUG("\n"); - morse("NO TARGETS.", 1); free(dp); return -1; } @@ -72,9 +79,6 @@ int adiv5_swdp_scan(void) adiv5_swdp_error(dp); adiv5_dp_init(dp); - if(!target_list) morse("NO TARGETS.", 1); - else morse(NULL, 0); - return target_list?1:0; } diff --git a/src/cortexa.c b/src/target/cortexa.c similarity index 87% rename from src/cortexa.c rename to src/target/cortexa.c index 0d731d2..a9c8593 100644 --- a/src/cortexa.c +++ b/src/target/cortexa.c @@ -29,25 +29,12 @@ */ #include "general.h" #include "exception.h" -#include "jtagtap.h" -#include "jtag_scan.h" #include "adiv5.h" #include "target.h" -#include "command.h" -#include "gdb_packet.h" -#include "cortexm.h" -#include "morse.h" - -#include +#include "target_internal.h" static char cortexa_driver_str[] = "ARM Cortex-A"; -/* Signals returned by cortexa_halt_wait() */ -#define SIGINT 2 -#define SIGTRAP 5 -#define SIGSEGV 11 -#define SIGLOST 29 - static bool cortexa_attach(target *t); static void cortexa_detach(target *t); static void cortexa_halt_resume(target *t, bool step); @@ -58,11 +45,11 @@ static void cortexa_regs_read_internal(target *t); static void cortexa_regs_write_internal(target *t); static void cortexa_reset(target *t); -static int cortexa_halt_wait(target *t); +static enum target_halt_reason cortexa_halt_poll(target *t, target_addr *watch); static void cortexa_halt_request(target *t); -static int cortexa_set_hw_bp(target *t, uint32_t addr, uint8_t len); -static int cortexa_clear_hw_bp(target *t, uint32_t addr, uint8_t len); +static int cortexa_breakwatch_set(target *t, struct breakwatch *); +static int cortexa_breakwatch_clear(target *t, struct breakwatch *); static uint32_t bp_bas(uint32_t addr, uint8_t len); static void apb_write(target *t, uint16_t reg, uint32_t val); @@ -81,7 +68,7 @@ struct cortexa_priv { uint64_t d[16]; } reg_cache; unsigned hw_breakpoint_max; - unsigned hw_breakpoint[16]; + bool hw_breakpoint[16]; uint32_t bpc0; bool mmu_fault; }; @@ -228,7 +215,7 @@ static uint32_t va_to_pa(target *t, uint32_t va) return pa; } -static void cortexa_mem_read(target *t, void *dest, uint32_t src, size_t len) +static void cortexa_mem_read(target *t, void *dest, target_addr src, size_t len) { /* Clean cache before reading */ for (uint32_t cl = src & ~(CACHE_LINE_LENGTH-1); @@ -241,7 +228,7 @@ static void cortexa_mem_read(target *t, void *dest, uint32_t src, size_t len) adiv5_mem_read(ahb, dest, va_to_pa(t, src), len); } -static void cortexa_slow_mem_read(target *t, void *dest, uint32_t src, size_t len) +static void cortexa_slow_mem_read(target *t, void *dest, target_addr src, size_t len) { struct cortexa_priv *priv = t->priv; unsigned words = (len + (src & 3) + 3) / 4; @@ -280,7 +267,7 @@ static void cortexa_slow_mem_read(target *t, void *dest, uint32_t src, size_t le } } -static void cortexa_mem_write(target *t, uint32_t dest, const void *src, size_t len) +static void cortexa_mem_write(target *t, target_addr dest, const void *src, size_t len) { /* Clean and invalidate cache before writing */ for (uint32_t cl = dest & ~(CACHE_LINE_LENGTH-1); @@ -292,7 +279,7 @@ static void cortexa_mem_write(target *t, uint32_t dest, const void *src, size_t adiv5_mem_write(ahb, va_to_pa(t, dest), src, len); } -static void cortexa_slow_mem_write_bytes(target *t, uint32_t dest, const uint8_t *src, size_t len) +static void cortexa_slow_mem_write_bytes(target *t, target_addr dest, const uint8_t *src, size_t len) { struct cortexa_priv *priv = t->priv; @@ -311,7 +298,7 @@ static void cortexa_slow_mem_write_bytes(target *t, uint32_t dest, const uint8_t } } -static void cortexa_slow_mem_write(target *t, uint32_t dest, const void *src, size_t len) +static void cortexa_slow_mem_write(target *t, target_addr dest, const void *src, size_t len) { struct cortexa_priv *priv = t->priv; if (len == 0) @@ -360,10 +347,7 @@ bool cortexa_probe(ADIv5_AP_t *apb, uint32_t debug_base) { target *t; - DEBUG("%s base=0x%08"PRIx32"\n", __func__, debug_base); - - /* Prepend to target list... */ - t = target_new(sizeof(*t)); + t = target_new(); adiv5_ap_ref(apb); struct cortexa_priv *priv = calloc(1, sizeof(*priv)); t->priv = priv; @@ -391,7 +375,6 @@ bool cortexa_probe(ADIv5_AP_t *apb, uint32_t debug_base) adiv5_ap_write(apb, ADIV5_AP_CSW, csw); uint32_t dbgdidr = apb_read(t, DBGDIDR); priv->hw_breakpoint_max = ((dbgdidr >> 24) & 15)+1; - DEBUG("Target has %d breakpoints\n", priv->hw_breakpoint_max); t->check_error = cortexa_check_error; @@ -406,12 +389,12 @@ bool cortexa_probe(ADIv5_AP_t *apb, uint32_t debug_base) t->reset = cortexa_reset; t->halt_request = cortexa_halt_request; - t->halt_wait = cortexa_halt_wait; + t->halt_poll = cortexa_halt_poll; t->halt_resume = cortexa_halt_resume; t->regs_size = sizeof(priv->reg_cache); - t->set_hw_bp = cortexa_set_hw_bp; - t->clear_hw_bp = cortexa_clear_hw_bp; + t->breakwatch_set = cortexa_breakwatch_set; + t->breakwatch_clear = cortexa_breakwatch_clear; return true; } @@ -433,7 +416,7 @@ bool cortexa_attach(target *t) target_halt_request(t); tries = 10; - while(!platform_srst_get_val() && !target_halt_wait(t) && --tries) + while(!platform_srst_get_val() && !target_halt_poll(t, NULL) && --tries) platform_delay(200); if(!tries) return false; @@ -593,12 +576,14 @@ static void cortexa_halt_request(target *t) apb_write(t, DBGDRCR, DBGDRCR_HRQ); } if (e.type) { - gdb_out("Timeout sending interrupt, is target in WFI?\n"); + tc_printf(t, "Timeout sending interrupt, is target in WFI?\n"); } } -static int cortexa_halt_wait(target *t) +static enum target_halt_reason cortexa_halt_poll(target *t, target_addr *watch) { + (void)watch; /* No watchpoint support yet */ + volatile uint32_t dbgdscr = 0; volatile struct exception e; TRY_CATCH (e, EXCEPTION_ALL) { @@ -610,15 +595,14 @@ static int cortexa_halt_wait(target *t) case EXCEPTION_ERROR: /* Oh crap, there's no recovery from this... */ target_list_free(); - morse("TARGET LOST.", 1); - return SIGLOST; + return TARGET_HALT_ERROR; case EXCEPTION_TIMEOUT: /* Timeout isn't a problem, target could be in WFI */ - return 0; + return TARGET_HALT_RUNNING; } if (!(dbgdscr & DBGDSCR_HALTED)) /* Not halted */ - return 0; + return TARGET_HALT_RUNNING; DEBUG("%s: DBGDSCR = 0x%08x\n", __func__, dbgdscr); /* Reenable DBGITR */ @@ -626,18 +610,18 @@ static int cortexa_halt_wait(target *t) apb_write(t, DBGDSCR, dbgdscr); /* Find out why we halted */ - int sig; + enum target_halt_reason reason; switch (dbgdscr & DBGDSCR_MOE_MASK) { case DBGDSCR_MOE_HALT_REQ: - sig = SIGINT; + reason = TARGET_HALT_REQUEST; break; default: - sig = SIGTRAP; + reason = TARGET_HALT_BREAKPOINT; } cortexa_regs_read_internal(t); - return sig; + return reason; } void cortexa_halt_resume(target *t, bool step) @@ -689,45 +673,75 @@ static uint32_t bp_bas(uint32_t addr, uint8_t len) return DBGBCR_BAS_LOW_HW; } -static int cortexa_set_hw_bp(target *t, uint32_t addr, uint8_t len) +static int cortexa_breakwatch_set(target *t, struct breakwatch *bw) { struct cortexa_priv *priv = t->priv; unsigned i; - for(i = 0; i < priv->hw_breakpoint_max; i++) - if((priv->hw_breakpoint[i] & 1) == 0) break; + switch (bw->type) { + case TARGET_BREAK_SOFT: + switch (bw->size) { + case 2: + bw->reserved[0] = target_mem_read16(t, bw->addr); + target_mem_write16(t, bw->addr, 0xBE00); + return 0; + case 4: + bw->reserved[0] = target_mem_read32(t, bw->addr); + target_mem_write32(t, bw->addr, 0xE1200070); + return 0; + default: + return -1; + } + case TARGET_BREAK_HARD: + if ((bw->size != 4) && (bw->size != 2)) + return -1; - if(i == priv->hw_breakpoint_max) return -1; + for (i = 0; i < priv->hw_breakpoint_max; i++) + if ((priv->hw_breakpoint[i] & 1) == 0) + break; - priv->hw_breakpoint[i] = addr | 1; + if (i == priv->hw_breakpoint_max) + return -1; - apb_write(t, DBGBVR(i), addr & ~3); - uint32_t bpc = bp_bas(addr, len) | DBGBCR_EN; - apb_write(t, DBGBCR(i), bpc); - if (i == 0) - priv->bpc0 = bpc; + bw->reserved[0] = i; - return 0; + priv->hw_breakpoint[i] = true; + + apb_write(t, DBGBVR(i), bw->addr & ~3); + uint32_t bpc = bp_bas(bw->addr, bw->size) | DBGBCR_EN; + apb_write(t, DBGBCR(i), bpc); + if (i == 0) + priv->bpc0 = bpc; + + return 0; + default: + return 1; + } } -static int cortexa_clear_hw_bp(target *t, uint32_t addr, uint8_t len) +static int cortexa_breakwatch_clear(target *t, struct breakwatch *bw) { struct cortexa_priv *priv = t->priv; - unsigned i; - - (void)len; - - for (i = 0; i < priv->hw_breakpoint_max; i++) - if ((priv->hw_breakpoint[i] & ~1) == addr) - break; - if (i == priv->hw_breakpoint_max) - return -1; - - priv->hw_breakpoint[i] = 0; - - apb_write(t, DBGBCR(i), 0); - if (i == 0) - priv->bpc0 = 0; - - return 0; + unsigned i = bw->reserved[0]; + switch (bw->type) { + case TARGET_BREAK_SOFT: + switch (bw->size) { + case 2: + target_mem_write16(t, bw->addr, i); + return 0; + case 4: + target_mem_write32(t, bw->addr, i); + return 0; + default: + return -1; + } + case TARGET_BREAK_HARD: + priv->hw_breakpoint[i] = false; + apb_write(t, DBGBCR(i), 0); + if (i == 0) + priv->bpc0 = 0; + return 0; + default: + return 1; + } } diff --git a/src/cortexm.c b/src/target/cortexm.c similarity index 74% rename from src/cortexm.c rename to src/target/cortexm.c index 570cdd9..d768fde 100644 --- a/src/cortexm.c +++ b/src/target/cortexm.c @@ -29,16 +29,11 @@ #include "exception.h" #include "adiv5.h" #include "target.h" -#include "command.h" -#include "gdb_packet.h" +#include "target_internal.h" #include "cortexm.h" -#include "morse.h" #include -/* On some systems this is a macro and causes problems */ -#undef errno - static char cortexm_driver_str[] = "ARM Cortex-M"; static bool cortexm_vector_catch(target *t, int argc, char *argv[]); @@ -52,56 +47,37 @@ const struct command_s cortexm_cmd_list[] = { #define TOPT_FLAVOUR_V6M (1<<0) /* if not set, target is assumed to be v7m */ #define TOPT_FLAVOUR_V7MF (1<<1) /* if set, floating-point enabled. */ -/* Signals returned by cortexm_halt_wait() */ -#define SIGINT 2 -#define SIGTRAP 5 -#define SIGSEGV 11 -#define SIGLOST 29 - static void cortexm_regs_read(target *t, void *data); static void cortexm_regs_write(target *t, const void *data); static uint32_t cortexm_pc_read(target *t); static void cortexm_reset(target *t); -static int cortexm_halt_wait(target *t); +static enum target_halt_reason cortexm_halt_poll(target *t, target_addr *watch); static void cortexm_halt_request(target *t); static int cortexm_fault_unwind(target *t); -static int cortexm_set_hw_bp(target *t, uint32_t addr, uint8_t len); -static int cortexm_clear_hw_bp(target *t, uint32_t addr, uint8_t len); - -static int cortexm_set_hw_wp(target *t, uint8_t type, uint32_t addr, uint8_t len); -static int cortexm_clear_hw_wp(target *t, uint8_t type, uint32_t addr, uint8_t len); - -static int cortexm_check_hw_wp(target *t, uint32_t *addr); +static int cortexm_breakwatch_set(target *t, struct breakwatch *); +static int cortexm_breakwatch_clear(target *t, struct breakwatch *); +static target_addr cortexm_check_watch(target *t); #define CORTEXM_MAX_WATCHPOINTS 4 /* architecture says up to 15, no implementation has > 4 */ #define CORTEXM_MAX_BREAKPOINTS 6 /* architecture says up to 127, no implementation has > 6 */ static int cortexm_hostio_request(target *t); -static void cortexm_hostio_reply(target *t, int32_t retcode, uint32_t errcode); struct cortexm_priv { ADIv5_AP_t *ap; bool stepping; bool on_bkpt; /* Watchpoint unit status */ - struct wp_unit_s { - uint32_t addr; - uint8_t type; - uint8_t size; - } hw_watchpoint[CORTEXM_MAX_WATCHPOINTS]; + bool hw_watchpoint[CORTEXM_MAX_WATCHPOINTS]; unsigned flash_patch_revision; unsigned hw_watchpoint_max; /* Breakpoint unit status */ - uint32_t hw_breakpoint[CORTEXM_MAX_BREAKPOINTS]; + bool hw_breakpoint[CORTEXM_MAX_BREAKPOINTS]; unsigned hw_breakpoint_max; /* Copy of DEMCR for vector-catch */ uint32_t demcr; - /* Semihosting state */ - uint32_t syscall; - uint32_t errno; - uint32_t byte_count; }; /* Register number tables */ @@ -203,12 +179,12 @@ ADIv5_AP_t *cortexm_ap(target *t) return ((struct cortexm_priv *)t->priv)->ap; } -static void cortexm_mem_read(target *t, void *dest, uint32_t src, size_t len) +static void cortexm_mem_read(target *t, void *dest, target_addr src, size_t len) { adiv5_mem_read(cortexm_ap(t), dest, src, len); } -static void cortexm_mem_write(target *t, uint32_t dest, const void *src, size_t len) +static void cortexm_mem_write(target *t, target_addr dest, const void *src, size_t len) { adiv5_mem_write(cortexm_ap(t), dest, src, len); } @@ -229,7 +205,7 @@ bool cortexm_probe(ADIv5_AP_t *ap) { target *t; - t = target_new(sizeof(*t)); + t = target_new(); adiv5_ap_ref(ap); struct cortexm_priv *priv = calloc(1, sizeof(*priv)); t->priv = priv; @@ -252,11 +228,12 @@ bool cortexm_probe(ADIv5_AP_t *ap) t->reset = cortexm_reset; t->halt_request = cortexm_halt_request; - t->halt_wait = cortexm_halt_wait; + t->halt_poll = cortexm_halt_poll; t->halt_resume = cortexm_halt_resume; t->regs_size = sizeof(regnum_cortex_m); - t->hostio_reply = cortexm_hostio_reply; + t->breakwatch_set = cortexm_breakwatch_set; + t->breakwatch_clear = cortexm_breakwatch_clear; target_add_commands(t, cortexm_cmd_list, cortexm_driver_str); @@ -307,7 +284,7 @@ bool cortexm_attach(target *t) target_halt_request(t); tries = 10; - while(!platform_srst_get_val() && !target_halt_wait(t) && --tries) + while(!platform_srst_get_val() && !target_halt_poll(t, NULL) && --tries) platform_delay(200); if(!tries) return false; @@ -338,19 +315,12 @@ bool cortexm_attach(target *t) /* Clear any stale watchpoints */ for(i = 0; i < priv->hw_watchpoint_max; i++) { target_mem_write32(t, CORTEXM_DWT_FUNC(i), 0); - priv->hw_watchpoint[i].type = 0; + priv->hw_watchpoint[i] = 0; } /* Flash Patch Control Register: set ENABLE */ target_mem_write32(t, CORTEXM_FPB_CTRL, CORTEXM_FPB_CTRL_KEY | CORTEXM_FPB_CTRL_ENABLE); - t->set_hw_bp = cortexm_set_hw_bp; - t->clear_hw_bp = cortexm_clear_hw_bp; - - /* Data Watchpoint and Trace */ - t->set_hw_wp = cortexm_set_hw_wp; - t->clear_hw_wp = cortexm_clear_hw_wp; - t->check_hw_wp = cortexm_check_hw_wp; platform_srst_set_val(false); @@ -488,11 +458,11 @@ static void cortexm_halt_request(target *t) CORTEXM_DHCSR_C_DEBUGEN); } if (e.type) { - gdb_out("Timeout sending interrupt, is target in WFI?\n"); + tc_printf(t, "Timeout sending interrupt, is target in WFI?\n"); } } -static int cortexm_halt_wait(target *t) +static enum target_halt_reason cortexm_halt_poll(target *t, target_addr *watch) { struct cortexm_priv *priv = t->priv; @@ -507,22 +477,21 @@ static int cortexm_halt_wait(target *t) case EXCEPTION_ERROR: /* Oh crap, there's no recovery from this... */ target_list_free(); - morse("TARGET LOST.", 1); - return SIGLOST; + return TARGET_HALT_ERROR; case EXCEPTION_TIMEOUT: /* Timeout isn't a problem, target could be in WFI */ - return 0; + return TARGET_HALT_RUNNING; } if (!(dhcsr & CORTEXM_DHCSR_S_HALT)) - return 0; + return TARGET_HALT_RUNNING; /* We've halted. Let's find out why. */ uint32_t dfsr = target_mem_read32(t, CORTEXM_DFSR); target_mem_write32(t, CORTEXM_DFSR, dfsr); /* write back to reset */ if ((dfsr & CORTEXM_DFSR_VCATCH) && cortexm_fault_unwind(t)) - return SIGSEGV; + return TARGET_HALT_FAULT; /* Remember if we stopped on a breakpoint */ priv->on_bkpt = dfsr & (CORTEXM_DFSR_BKPT); @@ -533,24 +502,27 @@ static int cortexm_halt_wait(target *t) uint16_t bkpt_instr; bkpt_instr = target_mem_read16(t, pc); if (bkpt_instr == 0xBEAB) { - int n = cortexm_hostio_request(t); - if (n > 0) { + if (cortexm_hostio_request(t)) { + return TARGET_HALT_REQUEST; + } else { target_halt_resume(t, priv->stepping); return 0; - } else if (n < 0) { - return -1; } } } - if (dfsr & (CORTEXM_DFSR_BKPT | CORTEXM_DFSR_DWTTRAP)) - return SIGTRAP; + if (dfsr & CORTEXM_DFSR_DWTTRAP) { + if (watch != NULL) + *watch = cortexm_check_watch(t); + return TARGET_HALT_WATCHPOINT; + } + if (dfsr & CORTEXM_DFSR_BKPT) + return TARGET_HALT_BREAKPOINT; if (dfsr & CORTEXM_DFSR_HALTED) - return priv->stepping ? SIGTRAP : SIGINT; - - return SIGTRAP; + return priv->stepping ? TARGET_HALT_STEPPING : TARGET_HALT_REQUEST; + return TARGET_HALT_BREAKPOINT; } void cortexm_halt_resume(target *t, bool step) @@ -656,7 +628,7 @@ int cortexm_run_stub(target *t, uint32_t loadaddr, /* Execute the stub */ cortexm_halt_resume(t, 0); - while (!cortexm_halt_wait(t)) + while (!cortexm_halt_poll(t, NULL)) ; uint32_t pc = cortexm_pc_read(t); @@ -667,148 +639,128 @@ int cortexm_run_stub(target *t, uint32_t loadaddr, return bkpt_instr & 0xff; } -/* The following routines implement hardware breakpoints. - * The Flash Patch and Breakpoint (FPB) system is used. */ +/* The following routines implement hardware breakpoints and watchpoints. + * The Flash Patch and Breakpoint (FPB) and Data Watch and Trace (DWT) + * systems are used. */ -static int cortexm_set_hw_bp(target *t, uint32_t addr, uint8_t len) +static uint32_t dwt_mask(size_t len) { - (void)len; - struct cortexm_priv *priv = t->priv; - uint32_t val = addr; - unsigned i; - - if (priv->flash_patch_revision == 0) { - val = addr & 0x1FFFFFFC; - val |= (addr & 2)?0x80000000:0x40000000; + switch (len) { + case 1: + return CORTEXM_DWT_MASK_BYTE; + case 2: + return CORTEXM_DWT_MASK_HALFWORD; + case 4: + return CORTEXM_DWT_MASK_WORD; + default: + return -1; } - val |= 1; - - for(i = 0; i < priv->hw_breakpoint_max; i++) - if((priv->hw_breakpoint[i] & 1) == 0) break; - - if(i == priv->hw_breakpoint_max) return -1; - - priv->hw_breakpoint[i] = addr | 1; - - target_mem_write32(t, CORTEXM_FPB_COMP(i), val); - - return 0; } -static int cortexm_clear_hw_bp(target *t, uint32_t addr, uint8_t len) +static uint32_t dwt_func(target *t, enum target_breakwatch type) { - (void)len; - struct cortexm_priv *priv = t->priv; - unsigned i; + uint32_t x = 0; - for(i = 0; i < priv->hw_breakpoint_max; i++) - if((priv->hw_breakpoint[i] & ~1) == addr) break; + if ((t->target_options & TOPT_FLAVOUR_V6M) == 0) + x = CORTEXM_DWT_FUNC_DATAVSIZE_WORD; - if(i == priv->hw_breakpoint_max) return -1; - - priv->hw_breakpoint[i] = 0; - - target_mem_write32(t, CORTEXM_FPB_COMP(i), 0); - - return 0; + switch (type) { + case TARGET_WATCH_WRITE: + return CORTEXM_DWT_FUNC_FUNC_WRITE | x; + case TARGET_WATCH_READ: + return CORTEXM_DWT_FUNC_FUNC_READ | x; + case TARGET_WATCH_ACCESS: + return CORTEXM_DWT_FUNC_FUNC_ACCESS | x; + default: + return -1; + } } -/* The following routines implement hardware watchpoints. - * The Data Watch and Trace (DWT) system is used. */ - -static int -cortexm_set_hw_wp(target *t, uint8_t type, uint32_t addr, uint8_t len) +static int cortexm_breakwatch_set(target *t, struct breakwatch *bw) { struct cortexm_priv *priv = t->priv; unsigned i; + uint32_t val = bw->addr; - switch(len) { /* Convert bytes size to mask size */ - case 1: len = CORTEXM_DWT_MASK_BYTE; break; - case 2: len = CORTEXM_DWT_MASK_HALFWORD; break; - case 4: len = CORTEXM_DWT_MASK_WORD; break; - default: + switch (bw->type) { + case TARGET_BREAK_HARD: + if (priv->flash_patch_revision == 0) { + val &= 0x1FFFFFFC; + val |= (bw->addr & 2)?0x80000000:0x40000000; + } + val |= 1; + + for(i = 0; i < priv->hw_breakpoint_max; i++) + if (!priv->hw_breakpoint[i]) + break; + + if (i == priv->hw_breakpoint_max) return -1; - } - switch(type) { /* Convert gdb type to function type */ - case 2: type = CORTEXM_DWT_FUNC_FUNC_WRITE; break; - case 3: type = CORTEXM_DWT_FUNC_FUNC_READ; break; - case 4: type = CORTEXM_DWT_FUNC_FUNC_ACCESS; break; - default: + priv->hw_breakpoint[i] = true; + target_mem_write32(t, CORTEXM_FPB_COMP(i), val); + bw->reserved[0] = i; + return 0; + + case TARGET_WATCH_WRITE: + case TARGET_WATCH_READ: + case TARGET_WATCH_ACCESS: + for(i = 0; i < priv->hw_watchpoint_max; i++) + if (!priv->hw_watchpoint[i]) + break; + + if (i == priv->hw_watchpoint_max) return -1; + + priv->hw_watchpoint[i] = true; + + target_mem_write32(t, CORTEXM_DWT_COMP(i), val); + target_mem_write32(t, CORTEXM_DWT_MASK(i), dwt_mask(bw->size)); + target_mem_write32(t, CORTEXM_DWT_FUNC(i), dwt_func(t, bw->type)); + + bw->reserved[0] = i; + return 0; + default: + return 1; } - - for(i = 0; i < priv->hw_watchpoint_max; i++) - if((priv->hw_watchpoint[i].type == 0) && - ((target_mem_read32(t, CORTEXM_DWT_FUNC(i)) & 0xF) == 0)) - break; - - if(i == priv->hw_watchpoint_max) return -2; - - priv->hw_watchpoint[i].type = type; - priv->hw_watchpoint[i].addr = addr; - priv->hw_watchpoint[i].size = len; - - target_mem_write32(t, CORTEXM_DWT_COMP(i), addr); - target_mem_write32(t, CORTEXM_DWT_MASK(i), len); - target_mem_write32(t, CORTEXM_DWT_FUNC(i), type | - ((t->target_options & TOPT_FLAVOUR_V6M) ? 0: CORTEXM_DWT_FUNC_DATAVSIZE_WORD)); - - return 0; } -static int -cortexm_clear_hw_wp(target *t, uint8_t type, uint32_t addr, uint8_t len) +static int cortexm_breakwatch_clear(target *t, struct breakwatch *bw) { struct cortexm_priv *priv = t->priv; - unsigned i; - - switch(len) { - case 1: len = CORTEXM_DWT_MASK_BYTE; break; - case 2: len = CORTEXM_DWT_MASK_HALFWORD; break; - case 4: len = CORTEXM_DWT_MASK_WORD; break; - default: - return -1; + unsigned i = bw->reserved[0]; + switch (bw->type) { + case TARGET_BREAK_HARD: + priv->hw_breakpoint[i] = false; + target_mem_write32(t, CORTEXM_FPB_COMP(i), 0); + return 0; + case TARGET_WATCH_WRITE: + case TARGET_WATCH_READ: + case TARGET_WATCH_ACCESS: + priv->hw_watchpoint[i] = false; + target_mem_write32(t, CORTEXM_DWT_FUNC(i), 0); + return 0; + default: + return 1; } - - switch(type) { - case 2: type = CORTEXM_DWT_FUNC_FUNC_WRITE; break; - case 3: type = CORTEXM_DWT_FUNC_FUNC_READ; break; - case 4: type = CORTEXM_DWT_FUNC_FUNC_ACCESS; break; - default: - return -1; - } - - for(i = 0; i < priv->hw_watchpoint_max; i++) - if((priv->hw_watchpoint[i].addr == addr) && - (priv->hw_watchpoint[i].type == type) && - (priv->hw_watchpoint[i].size == len)) break; - - if(i == priv->hw_watchpoint_max) return -2; - - priv->hw_watchpoint[i].type = 0; - - target_mem_write32(t, CORTEXM_DWT_FUNC(i), 0); - - return 0; } -static int cortexm_check_hw_wp(target *t, uint32_t *addr) +static target_addr cortexm_check_watch(target *t) { struct cortexm_priv *priv = t->priv; unsigned i; for(i = 0; i < priv->hw_watchpoint_max; i++) /* if SET and MATCHED then break */ - if(priv->hw_watchpoint[i].type && + if(priv->hw_watchpoint[i] && (target_mem_read32(t, CORTEXM_DWT_FUNC(i)) & CORTEXM_DWT_FUNC_MATCHED)) break; - if(i == priv->hw_watchpoint_max) return 0; + if (i == priv->hw_watchpoint_max) + return 0; - *addr = priv->hw_watchpoint[i].addr; - return 1; + return target_mem_read32(t, CORTEXM_DWT_COMP(i)); } static bool cortexm_vector_catch(target *t, int argc, char *argv[]) @@ -820,8 +772,8 @@ static bool cortexm_vector_catch(target *t, int argc, char *argv[]) unsigned i; if ((argc < 3) || ((argv[1][0] != 'e') && (argv[1][0] != 'd'))) { - gdb_out("usage: monitor vector_catch (enable|disable) " - "(hard|int|bus|stat|chk|nocp|mm|reset)\n"); + tc_printf(t, "usage: monitor vector_catch (enable|disable) " + "(hard|int|bus|stat|chk|nocp|mm|reset)\n"); } else { for (int j = 0; j < argc; j++) for (i = 0; i < sizeof(vectors) / sizeof(char*); i++) { @@ -837,14 +789,14 @@ static bool cortexm_vector_catch(target *t, int argc, char *argv[]) target_mem_write32(t, CORTEXM_DEMCR, priv->demcr); } - gdb_out("Catching vectors: "); + tc_printf(t, "Catching vectors: "); for (i = 0; i < sizeof(vectors) / sizeof(char*); i++) { if (!vectors[i]) continue; if (priv->demcr & (1 << i)) - gdb_outf("%s ", vectors[i]); + tc_printf(t, "%s ", vectors[i]); } - gdb_out("\n"); + tc_printf(t, "\n"); return true; } @@ -878,40 +830,30 @@ static bool cortexm_vector_catch(target *t, int argc, char *argv[]) #define SYS_WRITEC 0x03 #define SYS_WRITE0 0x04 -#define FILEIO_O_RDONLY 0 -#define FILEIO_O_WRONLY 1 -#define FILEIO_O_RDWR 2 -#define FILEIO_O_APPEND 0x008 -#define FILEIO_O_CREAT 0x200 -#define FILEIO_O_TRUNC 0x400 - -#define FILEIO_SEEK_SET 0 -#define FILEIO_SEEK_CUR 1 -#define FILEIO_SEEK_END 2 - static int cortexm_hostio_request(target *t) { - struct cortexm_priv *priv = t->priv; uint32_t arm_regs[t->regs_size]; uint32_t params[4]; + t->tc->interrupted = false; target_regs_read(t, arm_regs); target_mem_read(t, params, arm_regs[1], sizeof(params)); - priv->syscall = arm_regs[0]; + uint32_t syscall = arm_regs[0]; + int32_t ret = 0; - DEBUG("syscall 0x%x (%x %x %x %x)\n", priv->syscall, + DEBUG("syscall 0x%x (%x %x %x %x)\n", syscall, params[0], params[1], params[2], params[3]); - switch (priv->syscall) { + switch (syscall) { case SYS_OPEN:{ /* open */ /* Translate stupid fopen modes to open flags. * See DUI0471C, Table 8-3 */ const uint32_t flags[] = { - FILEIO_O_RDONLY, /* r, rb */ - FILEIO_O_RDWR, /* r+, r+b */ - FILEIO_O_WRONLY | FILEIO_O_CREAT | FILEIO_O_TRUNC,/*w*/ - FILEIO_O_RDWR | FILEIO_O_CREAT | FILEIO_O_TRUNC,/*w+*/ - FILEIO_O_WRONLY | FILEIO_O_CREAT | FILEIO_O_APPEND,/*a*/ - FILEIO_O_RDWR | FILEIO_O_CREAT | FILEIO_O_APPEND,/*a+*/ + TARGET_O_RDONLY, /* r, rb */ + TARGET_O_RDWR, /* r+, r+b */ + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC,/*w*/ + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC,/*w+*/ + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND,/*a*/ + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND,/*a+*/ }; uint32_t pflag = flags[params[1] >> 1]; char filename[4]; @@ -919,91 +861,70 @@ static int cortexm_hostio_request(target *t) target_mem_read(t, filename, params[0], sizeof(filename)); /* handle requests for console i/o */ if (!strcmp(filename, ":tt")) { - if (pflag == FILEIO_O_RDONLY) - arm_regs[0] = STDIN_FILENO; - else if (pflag & FILEIO_O_TRUNC) - arm_regs[0] = STDOUT_FILENO; + if (pflag == TARGET_O_RDONLY) + ret = STDIN_FILENO; + else if (pflag & TARGET_O_TRUNC) + ret = STDOUT_FILENO; else - arm_regs[0] = STDERR_FILENO; - arm_regs[0]++; - target_regs_write(t, arm_regs); - return 1; + ret = STDERR_FILENO; + ret++; + break; } - gdb_putpacket_f("Fopen,%08X/%X,%08X,%08X", - params[0], params[2] + 1, - pflag, 0644); + ret = tc_open(t, params[0], params[2] + 1, pflag, 0644); + if (ret != -1) + ret++; break; } case SYS_CLOSE: /* close */ - gdb_putpacket_f("Fclose,%08X", params[0] - 1); + ret = tc_close(t, params[0] - 1); break; case SYS_READ: /* read */ - priv->byte_count = params[2]; - gdb_putpacket_f("Fread,%08X,%08X,%08X", - params[0] - 1, params[1], params[2]); + ret = tc_read(t, params[0] - 1, params[1], params[2]); + if (ret > 0) + ret = params[2] - ret; break; case SYS_WRITE: /* write */ - priv->byte_count = params[2]; - gdb_putpacket_f("Fwrite,%08X,%08X,%08X", - params[0] - 1, params[1], params[2]); + ret = tc_write(t, params[0] - 1, params[1], params[2]); + if (ret > 0) + ret = params[2] - ret; break; case SYS_WRITEC: /* writec */ - gdb_putpacket_f("Fwrite,2,%08X,1", arm_regs[1]); + ret = tc_write(t, 2, arm_regs[1], 1); break; case SYS_ISTTY: /* isatty */ - gdb_putpacket_f("Fisatty,%08X", params[0] - 1); + ret = tc_isatty(t, params[0] - 1); break; case SYS_SEEK: /* lseek */ - gdb_putpacket_f("Flseek,%08X,%08X,%08X", - params[0] - 1, params[1], FILEIO_SEEK_SET); + ret = tc_lseek(t, params[0] - 1, params[1], TARGET_SEEK_SET); break; case SYS_RENAME:/* rename */ - gdb_putpacket_f("Frename,%08X/%X,%08X/%X", - params[0] - 1, params[1] + 1, + ret = tc_rename(t, params[0] - 1, params[1] + 1, params[2], params[3] + 1); break; case SYS_REMOVE:/* unlink */ - gdb_putpacket_f("Funlink,%08X/%X", params[0] - 1, - params[1] + 1); + ret = tc_unlink(t, params[0] - 1, params[1] + 1); break; case SYS_SYSTEM:/* system */ - gdb_putpacket_f("Fsystem,%08X/%X", params[0] - 1, - params[1] + 1); + ret = tc_system(t, params[0] - 1, params[1] + 1); break; case SYS_FLEN: /* Not supported, fake success */ - priv->errno = 0; - return 1; + t->tc->errno_ = 0; + break; case SYS_ERRNO: /* Return last errno from GDB */ - arm_regs[0] = priv->errno; - target_regs_write(t, arm_regs); - return 1; + ret = t->tc->errno_; + break; case SYS_TIME: /* gettimeofday */ /* FIXME How do we use gdb's gettimeofday? */ - default: - return 0; + break; } - return -1; -} - -static void cortexm_hostio_reply(target *t, int32_t retcode, uint32_t errcode) -{ - struct cortexm_priv *priv = t->priv; - uint32_t arm_regs[t->regs_size]; - - DEBUG("syscall return ret=%d errno=%d\n", retcode, errcode); - target_regs_read(t, arm_regs); - if (((priv->syscall == SYS_READ) || (priv->syscall == SYS_WRITE)) && - (retcode > 0)) - retcode = priv->byte_count - retcode; - if ((priv->syscall == SYS_OPEN) && (retcode != -1)) - retcode++; - arm_regs[0] = retcode; + arm_regs[0] = ret; target_regs_write(t, arm_regs); - priv->errno = errcode; + + return t->tc->interrupted; } diff --git a/src/include/cortexm.h b/src/target/cortexm.h similarity index 100% rename from src/include/cortexm.h rename to src/target/cortexm.h diff --git a/src/efm32.c b/src/target/efm32.c similarity index 95% rename from src/efm32.c rename to src/target/efm32.c index 52b2ea0..c76b17c 100644 --- a/src/efm32.c +++ b/src/target/efm32.c @@ -37,22 +37,19 @@ */ #include "general.h" -#include "jtagtap.h" -#include "adiv5.h" #include "target.h" -#include "command.h" -#include "gdb_packet.h" +#include "target_internal.h" #include "cortexm.h" #define SRAM_BASE 0x20000000 #define STUB_BUFFER_BASE ALIGN(SRAM_BASE + sizeof(efm32_flash_write_stub), 4) -static int efm32_flash_erase(struct target_flash *t, uint32_t addr, size_t len); +static int efm32_flash_erase(struct target_flash *t, target_addr addr, size_t len); static int efm32_flash_write(struct target_flash *f, - uint32_t dest, const void *src, size_t len); + target_addr dest, const void *src, size_t len); static const uint16_t efm32_flash_write_stub[] = { -#include "../flashstub/efm32.stub" +#include "flashstub/efm32.stub" }; static bool efm32_cmd_erase_all(target *t); @@ -233,7 +230,7 @@ uint16_t efm32_read_radio_part_number(target *t) -static void efm32_add_flash(target *t, uint32_t addr, size_t length, +static void efm32_add_flash(target *t, target_addr addr, size_t length, size_t page_size) { struct target_flash *f = calloc(1, sizeof(*f)); @@ -336,7 +333,7 @@ bool efm32_probe(target *t) /* Setup Target */ t->target_options |= CORTEXM_TOPT_INHIBIT_SRST; t->driver = variant_string; - gdb_outf("flash size %d page size %d\n", flash_size, flash_page_size); + tc_printf(t, "flash size %d page size %d\n", flash_size, flash_page_size); target_add_ram (t, SRAM_BASE, ram_size); efm32_add_flash(t, 0x00000000, flash_size, flash_page_size); target_add_commands(t, efm32_cmd_list, "EFM32"); @@ -347,7 +344,7 @@ bool efm32_probe(target *t) /** * Erase flash row by row */ -static int efm32_flash_erase(struct target_flash *f, uint32_t addr, size_t len) +static int efm32_flash_erase(struct target_flash *f, target_addr addr, size_t len) { target *t = f->t; @@ -379,7 +376,7 @@ static int efm32_flash_erase(struct target_flash *f, uint32_t addr, size_t len) * Write flash page by page */ static int efm32_flash_write(struct target_flash *f, - uint32_t dest, const void *src, size_t len) + target_addr dest, const void *src, size_t len) { (void)len; target *t = f->t; @@ -418,7 +415,7 @@ static bool efm32_cmd_erase_all(target *t) /* Relock mass erase */ target_mem_write32(t, EFM32_MSC_MASSLOCK, 0); - gdb_outf("Erase successful!\n"); + tc_printf(t, "Erase successful!\n"); return true; } @@ -432,7 +429,7 @@ static bool efm32_cmd_serial(target *t) uint64_t eui = efm32_read_eui(t); /* 64 bits of unique number */ - gdb_outf("Unique Number: 0x%016llx\n", eui); + tc_printf(t, "Unique Number: 0x%016llx\n", eui); return true; } diff --git a/flashstub/Makefile b/src/target/flashstub/Makefile similarity index 90% rename from flashstub/Makefile rename to src/target/flashstub/Makefile index a18cd23..3b137a0 100644 --- a/flashstub/Makefile +++ b/src/target/flashstub/Makefile @@ -8,7 +8,7 @@ ifneq ($(V), 1) Q = @ endif -CFLAGS=-Os -std=gnu99 -mcpu=cortex-m0 -mthumb -I../libopencm3/include +CFLAGS=-Os -std=gnu99 -mcpu=cortex-m0 -mthumb -I../../../libopencm3/include ASFLAGS=-mcpu=cortex-m3 -mthumb all: lmi.stub stm32f4.stub stm32l4.stub nrf51.stub stm32f1.stub efm32.stub diff --git a/src/target/flashstub/README.md b/src/target/flashstub/README.md new file mode 100644 index 0000000..df6bb71 --- /dev/null +++ b/src/target/flashstub/README.md @@ -0,0 +1,13 @@ +Flash Stubs +=========== + +These are simple routines for programming the flash on various Cortex-M +microcontrollers. The routines should be provided with the naked attribute +as the stack may not be available, and must not make any function calls. +The stub must call `stub_exit(code)` provided by `stub.h` to return control +to the debugger. Up to 4 word sized parameters may be taken. + +These stubs are compiled instructions comma separated hex values in the +resulting `*.stub` files here, which may be included in the drivers for the +specific device. The drivers call these flash stubs on the target by calling +`cortexm_run_stub` defined in `cortexm.h`. diff --git a/flashstub/efm32.c b/src/target/flashstub/efm32.c similarity index 100% rename from flashstub/efm32.c rename to src/target/flashstub/efm32.c diff --git a/flashstub/efm32.stub b/src/target/flashstub/efm32.stub similarity index 100% rename from flashstub/efm32.stub rename to src/target/flashstub/efm32.stub diff --git a/flashstub/lmi.c b/src/target/flashstub/lmi.c similarity index 100% rename from flashstub/lmi.c rename to src/target/flashstub/lmi.c diff --git a/flashstub/lmi.stub b/src/target/flashstub/lmi.stub similarity index 100% rename from flashstub/lmi.stub rename to src/target/flashstub/lmi.stub diff --git a/flashstub/nrf51.s b/src/target/flashstub/nrf51.s similarity index 100% rename from flashstub/nrf51.s rename to src/target/flashstub/nrf51.s diff --git a/flashstub/nrf51.stub b/src/target/flashstub/nrf51.stub similarity index 100% rename from flashstub/nrf51.stub rename to src/target/flashstub/nrf51.stub diff --git a/flashstub/stm32f1.c b/src/target/flashstub/stm32f1.c similarity index 100% rename from flashstub/stm32f1.c rename to src/target/flashstub/stm32f1.c diff --git a/flashstub/stm32f1.stub b/src/target/flashstub/stm32f1.stub similarity index 100% rename from flashstub/stm32f1.stub rename to src/target/flashstub/stm32f1.stub diff --git a/flashstub/stm32f4.c b/src/target/flashstub/stm32f4.c similarity index 100% rename from flashstub/stm32f4.c rename to src/target/flashstub/stm32f4.c diff --git a/flashstub/stm32f4.stub b/src/target/flashstub/stm32f4.stub similarity index 100% rename from flashstub/stm32f4.stub rename to src/target/flashstub/stm32f4.stub diff --git a/flashstub/stm32l4.c b/src/target/flashstub/stm32l4.c similarity index 100% rename from flashstub/stm32l4.c rename to src/target/flashstub/stm32l4.c diff --git a/flashstub/stm32l4.stub b/src/target/flashstub/stm32l4.stub similarity index 100% rename from flashstub/stm32l4.stub rename to src/target/flashstub/stm32l4.stub diff --git a/flashstub/stub.h b/src/target/flashstub/stub.h similarity index 100% rename from flashstub/stub.h rename to src/target/flashstub/stub.h diff --git a/src/jtag_scan.c b/src/target/jtag_scan.c similarity index 98% rename from src/jtag_scan.c rename to src/target/jtag_scan.c index db39c5c..4546be5 100644 --- a/src/jtag_scan.c +++ b/src/target/jtag_scan.c @@ -25,9 +25,7 @@ #include "general.h" #include "jtagtap.h" -#include "morse.h" #include "jtag_scan.h" -#include "gdb_packet.h" #include "target.h" #include "adiv5.h" @@ -187,7 +185,6 @@ int jtag_scan(const uint8_t *irlens) jtagtap_next(1, 1); jtagtap_return_idle(); if(!jtag_dev_count) { - morse("NO TARGETS.", 1); return 0; } @@ -224,9 +221,6 @@ int jtag_scan(const uint8_t *irlens) break; } - if(!target_list) morse("NO TARGETS.", 1); - else morse(NULL, 0); - return jtag_dev_count; } diff --git a/src/include/jtag_scan.h b/src/target/jtag_scan.h similarity index 97% rename from src/include/jtag_scan.h rename to src/target/jtag_scan.h index 0819dfa..e96f6e7 100644 --- a/src/include/jtag_scan.h +++ b/src/target/jtag_scan.h @@ -45,8 +45,6 @@ typedef struct jtag_dev_s { extern struct jtag_dev_s jtag_devs[JTAG_MAX_DEVS+1]; extern int jtag_dev_count; -int jtag_scan(const uint8_t *lrlens); - void jtag_dev_write_ir(jtag_dev_t *dev, uint32_t ir); void jtag_dev_shift_dr(jtag_dev_t *dev, uint8_t *dout, const uint8_t *din, int ticks); diff --git a/src/jtagtap_generic.c b/src/target/jtagtap_generic.c similarity index 90% rename from src/jtagtap_generic.c rename to src/target/jtagtap_generic.c index 63c8e44..416bcb6 100644 --- a/src/jtagtap_generic.c +++ b/src/target/jtagtap_generic.c @@ -21,9 +21,10 @@ /* This file provides generic forms of the low-level jtagtap functions * for platforms that don't require optimised forms. */ +#include "general.h" +#include "jtagtap.h" -#ifdef PROVIDE_GENERIC_JTAGTAP_TMS_SEQ -void +void __attribute__((weak)) jtagtap_tms_seq(uint32_t MS, int ticks) { while(ticks--) { @@ -31,11 +32,8 @@ jtagtap_tms_seq(uint32_t MS, int ticks) MS >>= 1; } } -#endif - -#ifdef PROVIDE_GENERIC_JTAGTAP_TDI_TDO_SEQ -void +void __attribute__((weak)) jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks) { uint8_t index = 1; @@ -51,11 +49,8 @@ jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int } } } -#endif - -#ifdef PROVIDE_GENERIC_JTAGTAP_TDI_SEQ -void +void __attribute__((weak)) jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int ticks) { uint8_t index = 1; @@ -67,6 +62,4 @@ jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int ticks) } } } -#endif - diff --git a/src/kinetis.c b/src/target/kinetis.c similarity index 93% rename from src/kinetis.c rename to src/target/kinetis.c index 914df7e..f8842a3 100644 --- a/src/kinetis.c +++ b/src/target/kinetis.c @@ -29,6 +29,7 @@ #include "general.h" #include "target.h" +#include "target_internal.h" #define SIM_SDID 0x40048024 @@ -60,9 +61,9 @@ #define KL_GEN_PAGESIZE 0x400 -static int kl_gen_flash_erase(struct target_flash *f, uint32_t addr, size_t len); +static int kl_gen_flash_erase(struct target_flash *f, target_addr addr, size_t len); static int kl_gen_flash_write(struct target_flash *f, - uint32_t dest, const void *src, size_t len); + target_addr dest, const void *src, size_t len); static void kl_gen_add_flash(target *t, uint32_t addr, size_t length, size_t erasesize) @@ -158,7 +159,7 @@ kl_gen_command(target *t, uint8_t cmd, uint32_t addr, const uint8_t data[8]) return true; } -static int kl_gen_flash_erase(struct target_flash *f, uint32_t addr, size_t len) +static int kl_gen_flash_erase(struct target_flash *f, target_addr addr, size_t len) { while (len) { if (kl_gen_command(f->t, FTFA_CMD_ERASE_SECTOR, addr, NULL)) { @@ -172,7 +173,7 @@ static int kl_gen_flash_erase(struct target_flash *f, uint32_t addr, size_t len) } static int kl_gen_flash_write(struct target_flash *f, - uint32_t dest, const void *src, size_t len) + target_addr dest, const void *src, size_t len) { while (len) { if (kl_gen_command(f->t, FTFA_CMD_PROGRAM_LONGWORD, dest, src)) { diff --git a/src/lmi.c b/src/target/lmi.c similarity index 89% rename from src/lmi.c rename to src/target/lmi.c index e2d1809..e331b39 100644 --- a/src/lmi.c +++ b/src/target/lmi.c @@ -26,6 +26,7 @@ #include "general.h" #include "target.h" +#include "target_internal.h" #include "cortexm.h" #define SRAM_BASE 0x20000000 @@ -46,14 +47,14 @@ #define LMI_FLASH_FMC_COMT (1 << 3) #define LMI_FLASH_FMC_WRKEY 0xA4420000 -static int lmi_flash_erase(struct target_flash *f, uint32_t addr, size_t len); +static int lmi_flash_erase(struct target_flash *f, target_addr addr, size_t len); static int lmi_flash_write(struct target_flash *f, - uint32_t dest, const void *src, size_t len); + target_addr dest, const void *src, size_t len); static const char lmi_driver_str[] = "TI Stellaris/Tiva"; static const uint16_t lmi_flash_write_stub[] = { -#include "../flashstub/lmi.stub" +#include "flashstub/lmi.stub" }; static void lmi_add_flash(target *t, size_t length) @@ -88,7 +89,7 @@ bool lmi_probe(target *t) return false; } -int lmi_flash_erase(struct target_flash *f, uint32_t addr, size_t len) +int lmi_flash_erase(struct target_flash *f, target_addr addr, size_t len) { target *t = f->t; while(len) { @@ -105,7 +106,7 @@ int lmi_flash_erase(struct target_flash *f, uint32_t addr, size_t len) } int lmi_flash_write(struct target_flash *f, - uint32_t dest, const void *src, size_t len) + target_addr dest, const void *src, size_t len) { target *t = f->t; diff --git a/src/lpc11xx.c b/src/target/lpc11xx.c similarity index 99% rename from src/lpc11xx.c rename to src/target/lpc11xx.c index fcf9f0e..e929d6a 100644 --- a/src/lpc11xx.c +++ b/src/target/lpc11xx.c @@ -20,6 +20,7 @@ #include "general.h" #include "target.h" +#include "target_internal.h" #include "cortexm.h" #include "lpc_common.h" diff --git a/src/lpc15xx.c b/src/target/lpc15xx.c similarity index 98% rename from src/lpc15xx.c rename to src/target/lpc15xx.c index 3f23f9f..4e362e2 100644 --- a/src/lpc15xx.c +++ b/src/target/lpc15xx.c @@ -21,6 +21,7 @@ #include "general.h" #include "target.h" +#include "target_internal.h" #include "cortexm.h" #include "lpc_common.h" diff --git a/src/lpc43xx.c b/src/target/lpc43xx.c similarity index 94% rename from src/lpc43xx.c rename to src/target/lpc43xx.c index b6c499a..f08c4f8 100644 --- a/src/lpc43xx.c +++ b/src/target/lpc43xx.c @@ -19,9 +19,8 @@ */ #include "general.h" -#include "command.h" #include "target.h" -#include "gdb_packet.h" +#include "target_internal.h" #include "cortexm.h" #include "lpc_common.h" @@ -51,7 +50,7 @@ static bool lpc43xx_cmd_erase(target *t, int argc, const char *argv[]); static bool lpc43xx_cmd_reset(target *t, int argc, const char *argv[]); static bool lpc43xx_cmd_mkboot(target *t, int argc, const char *argv[]); static int lpc43xx_flash_init(target *t); -static int lpc43xx_flash_erase(struct target_flash *f, uint32_t addr, size_t len); +static int lpc43xx_flash_erase(struct target_flash *f, target_addr addr, size_t len); static void lpc43xx_set_internal_clock(target *t); static void lpc43xx_wdt_set_period(target *t); static void lpc43xx_wdt_pet(target *t); @@ -174,7 +173,7 @@ static bool lpc43xx_cmd_erase(target *t, int argc, const char *argv[]) return false; } - gdb_outf("Erase OK.\n"); + tc_printf(t, "Erase OK.\n"); return true; } @@ -195,7 +194,7 @@ static int lpc43xx_flash_init(target *t) return 0; } -static int lpc43xx_flash_erase(struct target_flash *f, uint32_t addr, size_t len) +static int lpc43xx_flash_erase(struct target_flash *f, target_addr addr, size_t len) { if (lpc43xx_flash_init(f->t)) return -1; @@ -220,14 +219,14 @@ static bool lpc43xx_cmd_mkboot(target *t, int argc, const char *argv[]) { /* Usage: mkboot 0 or mkboot 1 */ if (argc != 2) { - gdb_outf("Expected bank argument 0 or 1.\n"); + tc_printf(t, "Expected bank argument 0 or 1.\n"); return false; } const long int bank = strtol(argv[1], NULL, 0); if ((bank != 0) && (bank != 1)) { - gdb_outf("Unexpected bank number, should be 0 or 1.\n"); + tc_printf(t, "Unexpected bank number, should be 0 or 1.\n"); return false; } @@ -236,11 +235,11 @@ static bool lpc43xx_cmd_mkboot(target *t, int argc, const char *argv[]) /* special command to compute/write magic vector for signature */ struct lpc_flash *f = (struct lpc_flash *)t->flash; if (lpc_iap_call(f, IAP_CMD_SET_ACTIVE_BANK, bank, CPU_CLK_KHZ)) { - gdb_outf("Set bootable failed.\n"); + tc_printf(t, "Set bootable failed.\n"); return false; } - gdb_outf("Set bootable OK.\n"); + tc_printf(t, "Set bootable OK.\n"); return true; } diff --git a/src/lpc_common.c b/src/target/lpc_common.c similarity index 91% rename from src/lpc_common.c rename to src/target/lpc_common.c index ad62e15..63d844e 100644 --- a/src/lpc_common.c +++ b/src/target/lpc_common.c @@ -18,6 +18,7 @@ */ #include "general.h" #include "target.h" +#include "target_internal.h" #include "cortexm.h" #include "lpc_common.h" @@ -32,7 +33,7 @@ struct flash_param { } __attribute__((aligned(4))); -struct lpc_flash *lpc_add_flash(target *t, uint32_t addr, size_t length) +struct lpc_flash *lpc_add_flash(target *t, target_addr addr, size_t length) { struct lpc_flash *lf = calloc(1, sizeof(*lf)); struct target_flash *f = &lf->f; @@ -81,7 +82,7 @@ enum iap_status lpc_iap_call(struct lpc_flash *f, enum iap_cmd cmd, ...) /* start the target and wait for it to halt again */ target_halt_resume(t, false); - while (!target_halt_wait(t)); + while (!target_halt_poll(t, NULL)); /* copy back just the parameters structure */ target_mem_read(t, ¶m, f->iap_ram, sizeof(param)); @@ -93,7 +94,7 @@ static uint8_t lpc_sector_for_addr(struct lpc_flash *f, uint32_t addr) return f->base_sector + (addr - f->f.start) / f->f.blocksize; } -int lpc_flash_erase(struct target_flash *tf, uint32_t addr, size_t len) +int lpc_flash_erase(struct target_flash *tf, target_addr addr, size_t len) { struct lpc_flash *f = (struct lpc_flash *)tf; uint32_t start = lpc_sector_for_addr(f, addr); @@ -114,7 +115,7 @@ int lpc_flash_erase(struct target_flash *tf, uint32_t addr, size_t len) } int lpc_flash_write(struct target_flash *tf, - uint32_t dest, const void *src, size_t len) + target_addr dest, const void *src, size_t len) { struct lpc_flash *f = (struct lpc_flash *)tf; /* prepare... */ @@ -134,7 +135,7 @@ int lpc_flash_write(struct target_flash *tf, } int lpc_flash_write_magic_vect(struct target_flash *f, - uint32_t dest, const void *src, size_t len) + target_addr dest, const void *src, size_t len) { if (dest == 0) { /* Fill in the magic vector to allow booting the flash */ diff --git a/src/include/lpc_common.h b/src/target/lpc_common.h similarity index 86% rename from src/include/lpc_common.h rename to src/target/lpc_common.h index 8ca361d..dd7dc88 100644 --- a/src/include/lpc_common.h +++ b/src/target/lpc_common.h @@ -58,13 +58,13 @@ struct lpc_flash { uint32_t iap_msp; }; -struct lpc_flash *lpc_add_flash(target *t, uint32_t addr, size_t length); +struct lpc_flash *lpc_add_flash(target *t, target_addr addr, size_t length); enum iap_status lpc_iap_call(struct lpc_flash *f, enum iap_cmd cmd, ...); -int lpc_flash_erase(struct target_flash *f, uint32_t addr, size_t len); +int lpc_flash_erase(struct target_flash *f, target_addr addr, size_t len); int lpc_flash_write(struct target_flash *f, - uint32_t dest, const void *src, size_t len); + target_addr dest, const void *src, size_t len); int lpc_flash_write_magic_vect(struct target_flash *f, - uint32_t dest, const void *src, size_t len); + target_addr dest, const void *src, size_t len); #endif diff --git a/src/nrf51.c b/src/target/nrf51.c similarity index 91% rename from src/nrf51.c rename to src/target/nrf51.c index 88e63f5..0649c59 100644 --- a/src/nrf51.c +++ b/src/target/nrf51.c @@ -22,22 +22,20 @@ */ #include "general.h" -#include "adiv5.h" #include "target.h" -#include "command.h" -#include "gdb_packet.h" +#include "target_internal.h" #include "cortexm.h" -static int nrf51_flash_erase(struct target_flash *f, uint32_t addr, size_t len); +static int nrf51_flash_erase(struct target_flash *f, target_addr addr, size_t len); static int nrf51_flash_write(struct target_flash *f, - uint32_t dest, const void *src, size_t len); + target_addr dest, const void *src, size_t len); static bool nrf51_cmd_erase_all(target *t); static bool nrf51_cmd_read_hwid(target *t); static bool nrf51_cmd_read_fwid(target *t); static bool nrf51_cmd_read_deviceid(target *t); static bool nrf51_cmd_read_deviceaddr(target *t); -static bool nrf51_cmd_read_help(void); +static bool nrf51_cmd_read_help(target *t); static bool nrf51_cmd_read(target *t, int argc, const char *argv[]); const struct command_s nrf51_cmd_list[] = { @@ -87,7 +85,7 @@ const struct command_s nrf51_read_cmd_list[] = { #define STUB_BUFFER_BASE (SRAM_BASE + 0x28) static const uint16_t nrf51_flash_write_stub[] = { -#include "../flashstub/nrf51.stub" +#include "flashstub/nrf51.stub" }; static void nrf51_add_flash(target *t, @@ -174,7 +172,7 @@ bool nrf51_probe(target *t) return false; } -static int nrf51_flash_erase(struct target_flash *f, uint32_t addr, size_t len) +static int nrf51_flash_erase(struct target_flash *f, target_addr addr, size_t len) { target *t = f->t; /* Enable erase */ @@ -216,7 +214,7 @@ static int nrf51_flash_erase(struct target_flash *f, uint32_t addr, size_t len) } static int nrf51_flash_write(struct target_flash *f, - uint32_t dest, const void *src, size_t len) + target_addr dest, const void *src, size_t len) { target *t = f->t; uint32_t data[2 + len/4]; @@ -250,7 +248,7 @@ static int nrf51_flash_write(struct target_flash *f, static bool nrf51_cmd_erase_all(target *t) { - gdb_out("erase..\n"); + tc_printf(t, "erase..\n"); /* Enable erase */ target_mem_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_EEN); @@ -274,14 +272,14 @@ static bool nrf51_cmd_erase_all(target *t) static bool nrf51_cmd_read_hwid(target *t) { uint32_t hwid = target_mem_read32(t, NRF51_FICR_CONFIGID) & 0xFFFF; - gdb_outf("Hardware ID: 0x%04X\n", hwid); + tc_printf(t, "Hardware ID: 0x%04X\n", hwid); return true; } static bool nrf51_cmd_read_fwid(target *t) { uint32_t fwid = (target_mem_read32(t, NRF51_FICR_CONFIGID) >> 16) & 0xFFFF; - gdb_outf("Firmware ID: 0x%04X\n", fwid); + tc_printf(t, "Firmware ID: 0x%04X\n", fwid); return true; } @@ -290,7 +288,7 @@ static bool nrf51_cmd_read_deviceid(target *t) uint32_t deviceid_low = target_mem_read32(t, NRF51_FICR_DEVICEID_LOW); uint32_t deviceid_high = target_mem_read32(t, NRF51_FICR_DEVICEID_HIGH); - gdb_outf("Device ID: 0x%08X%08X\n", deviceid_high, deviceid_low); + tc_printf(t, "Device ID: 0x%08X%08X\n", deviceid_high, deviceid_low); return true; } @@ -301,20 +299,20 @@ static bool nrf51_cmd_read_deviceaddr(target *t) uint32_t addr_high = target_mem_read32(t, NRF51_FICR_DEVICEADDR_HIGH) & 0xFFFF; if ((addr_type & 1) == 0) { - gdb_outf("Publicly Listed Address: 0x%04X%08X\n", addr_high, addr_low); + tc_printf(t, "Publicly Listed Address: 0x%04X%08X\n", addr_high, addr_low); } else { - gdb_outf("Randomly Assigned Address: 0x%04X%08X\n", addr_high, addr_low); + tc_printf(t, "Randomly Assigned Address: 0x%04X%08X\n", addr_high, addr_low); } return true; } -static bool nrf51_cmd_read_help(void) +static bool nrf51_cmd_read_help(target *t) { const struct command_s *c; - gdb_out("Read commands:\n"); + tc_printf(t, "Read commands:\n"); for(c = nrf51_read_cmd_list; c->cmd; c++) - gdb_outf("\t%s -- %s\n", c->cmd, c->help); + tc_printf(t, "\t%s -- %s\n", c->cmd, c->help); return true; } @@ -330,6 +328,6 @@ static bool nrf51_cmd_read(target *t, int argc, const char *argv[]) return !c->handler(t, argc - 1, &argv[1]); } - return nrf51_cmd_read_help(); + return nrf51_cmd_read_help(t); } diff --git a/src/sam3x.c b/src/target/sam3x.c similarity index 94% rename from src/sam3x.c rename to src/target/sam3x.c index 703bacc..0f990d0 100644 --- a/src/sam3x.c +++ b/src/target/sam3x.c @@ -25,14 +25,12 @@ */ #include "general.h" -#include "adiv5.h" #include "target.h" -#include "command.h" -#include "gdb_packet.h" +#include "target_internal.h" -static int sam4_flash_erase(struct target_flash *f, uint32_t addr, size_t len); -static int sam3_flash_erase(struct target_flash *f, uint32_t addr, size_t len); -static int sam3x_flash_write(struct target_flash *f, uint32_t dest, +static int sam4_flash_erase(struct target_flash *f, target_addr addr, size_t len); +static int sam3_flash_erase(struct target_flash *f, target_addr addr, size_t len); +static int sam3x_flash_write(struct target_flash *f, target_addr dest, const void *src, size_t len); static bool sam3x_cmd_gpnvm_get(target *t); @@ -283,7 +281,7 @@ static uint32_t sam3x_flash_base(target *t) return SAM3N_EEFC_BASE; } -static int sam4_flash_erase(struct target_flash *f, uint32_t addr, size_t len) +static int sam4_flash_erase(struct target_flash *f, target_addr addr, size_t len) { target *t = f->t; uint32_t base = ((struct sam_flash *)f)->eefc_base; @@ -306,7 +304,7 @@ static int sam4_flash_erase(struct target_flash *f, uint32_t addr, size_t len) return 0; } -static int sam3_flash_erase(struct target_flash *f, uint32_t addr, size_t len) +static int sam3_flash_erase(struct target_flash *f, target_addr addr, size_t len) { /* The SAM3X/SAM3N don't really have a page erase function. * We do nothing here and use Erase/Write page in flash_write. @@ -315,7 +313,7 @@ static int sam3_flash_erase(struct target_flash *f, uint32_t addr, size_t len) return 0; } -static int sam3x_flash_write(struct target_flash *f, uint32_t dest, +static int sam3x_flash_write(struct target_flash *f, target_addr dest, const void *src, size_t len) { target *t = f->t; @@ -335,7 +333,7 @@ static bool sam3x_cmd_gpnvm_get(target *t) uint32_t base = sam3x_flash_base(t); sam3x_flash_cmd(t, base, EEFC_FCR_FCMD_GGPB, 0); - gdb_outf("GPNVM: 0x%08X\n", target_mem_read32(t, EEFC_FRR(base))); + tc_printf(t, "GPNVM: 0x%08X\n", target_mem_read32(t, EEFC_FRR(base))); return true; } @@ -346,7 +344,7 @@ static bool sam3x_cmd_gpnvm_set(target *t, int argc, char *argv[]) uint32_t base = sam3x_flash_base(t); if (argc != 3) { - gdb_out("usage: monitor gpnvm_set \n"); + tc_printf(t, "usage: monitor gpnvm_set \n"); return false; } bit = atol(argv[1]); diff --git a/src/samd.c b/src/target/samd.c similarity index 95% rename from src/samd.c rename to src/target/samd.c index a39cc37..7861873 100644 --- a/src/samd.c +++ b/src/target/samd.c @@ -33,16 +33,13 @@ */ #include "general.h" -#include "jtagtap.h" -#include "adiv5.h" #include "target.h" -#include "command.h" -#include "gdb_packet.h" +#include "target_internal.h" #include "cortexm.h" -static int samd_flash_erase(struct target_flash *t, uint32_t addr, size_t len); +static int samd_flash_erase(struct target_flash *t, target_addr addr, size_t len); static int samd_flash_write(struct target_flash *f, - uint32_t dest, const void *src, size_t len); + target_addr dest, const void *src, size_t len); static bool samd_cmd_erase_all(target *t); static bool samd_cmd_lock_flash(target *t); @@ -460,7 +457,7 @@ static void samd_unlock_current_address(target *t) /** * Erase flash row by row */ -static int samd_flash_erase(struct target_flash *f, uint32_t addr, size_t len) +static int samd_flash_erase(struct target_flash *f, target_addr addr, size_t len) { target *t = f->t; while (len) { @@ -493,7 +490,7 @@ static int samd_flash_erase(struct target_flash *f, uint32_t addr, size_t len) * Write flash page by page */ static int samd_flash_write(struct target_flash *f, - uint32_t dest, const void *src, size_t len) + target_addr dest, const void *src, size_t len) { target *t = f->t; @@ -540,17 +537,17 @@ static bool samd_cmd_erase_all(target *t) /* Test the protection error bit in Status A */ if (status & SAMD_STATUSA_PERR) { - gdb_outf("Erase failed due to a protection error.\n"); + tc_printf(t, "Erase failed due to a protection error.\n"); return true; } /* Test the fail bit in Status A */ if (status & SAMD_STATUSA_FAIL) { - gdb_outf("Erase failed.\n"); + tc_printf(t, "Erase failed.\n"); return true; } - gdb_outf("Erase successful!\n"); + tc_printf(t, "Erase successful!\n"); return true; } @@ -606,7 +603,7 @@ static bool samd_cmd_unlock_flash(target *t) static bool samd_cmd_read_userrow(target *t) { - gdb_outf("User Row: 0x%08x%08x\n", + tc_printf(t, "User Row: 0x%08x%08x\n", target_mem_read32(t, SAMD_NVM_USER_ROW_HIGH), target_mem_read32(t, SAMD_NVM_USER_ROW_LOW)); @@ -618,13 +615,13 @@ static bool samd_cmd_read_userrow(target *t) */ static bool samd_cmd_serial(target *t) { - gdb_outf("Serial Number: 0x"); + tc_printf(t, "Serial Number: 0x"); for (uint32_t i = 0; i < 4; i++) { - gdb_outf("%08x", target_mem_read32(t, SAMD_NVM_SERIAL(i))); + tc_printf(t, "%08x", target_mem_read32(t, SAMD_NVM_SERIAL(i))); } - gdb_outf("\n"); + tc_printf(t, "\n"); return true; } @@ -668,16 +665,16 @@ static bool samd_cmd_mbist(target *t) /* Test the protection error bit in Status A */ if (status & SAMD_STATUSA_PERR) { - gdb_outf("MBIST not run due to protection error.\n"); + tc_printf(t, "MBIST not run due to protection error.\n"); return true; } /* Test the fail bit in Status A */ if (status & SAMD_STATUSA_FAIL) { - gdb_outf("MBIST Fail @ 0x%08x\n", - target_mem_read32(t, SAMD_DSU_ADDRESS)); + tc_printf(t, "MBIST Fail @ 0x%08x\n", + target_mem_read32(t, SAMD_DSU_ADDRESS)); } else { - gdb_outf("MBIST Passed!\n"); + tc_printf(t, "MBIST Passed!\n"); } return true; @@ -696,8 +693,8 @@ static bool samd_cmd_ssb(target *t) if (target_check_error(t)) return -1; - gdb_outf("Set the security bit! " - "You will need to issue 'monitor erase_mass' to clear this.\n"); + tc_printf(t, "Set the security bit! " + "You will need to issue 'monitor erase_mass' to clear this.\n"); return true; } diff --git a/src/stm32f1.c b/src/target/stm32f1.c similarity index 92% rename from src/stm32f1.c rename to src/target/stm32f1.c index 17d6126..4cc1661 100644 --- a/src/stm32f1.c +++ b/src/target/stm32f1.c @@ -30,11 +30,9 @@ */ #include "general.h" -#include "adiv5.h" #include "target.h" +#include "target_internal.h" #include "cortexm.h" -#include "command.h" -#include "gdb_packet.h" static bool stm32f1_cmd_erase_mass(target *t); static bool stm32f1_cmd_option(target *t, int argc, char *argv[]); @@ -47,9 +45,9 @@ const struct command_s stm32f1_cmd_list[] = { static int stm32f1_flash_erase(struct target_flash *f, - uint32_t addr, size_t len); + target_addr addr, size_t len); static int stm32f1_flash_write(struct target_flash *f, - uint32_t dest, const void *src, size_t len); + target_addr dest, const void *src, size_t len); /* Flash Program ad Erase Controller Register Map */ #define FPEC_BASE 0x40022000 @@ -91,7 +89,7 @@ static int stm32f1_flash_write(struct target_flash *f, #define FLASHSIZE_F0 0x1FFFF7CC static const uint16_t stm32f1_flash_write_stub[] = { -#include "../flashstub/stm32f1.stub" +#include "flashstub/stm32f1.stub" }; #define SRAM_BASE 0x20000000 @@ -167,7 +165,7 @@ bool stm32f1_probe(target *t) } flash_size = (target_mem_read32(t, FLASHSIZE_F0) & 0xffff) *0x400; - gdb_outf("flash size %d block_size %d\n", flash_size, block_size); + tc_printf(t, "flash size %d block_size %d\n", flash_size, block_size); target_add_ram(t, 0x20000000, 0x5000); stm32f1_add_flash(t, 0x8000000, flash_size, block_size); target_add_commands(t, stm32f1_cmd_list, "STM32F0"); @@ -181,7 +179,7 @@ static void stm32f1_flash_unlock(target *t) } static int stm32f1_flash_erase(struct target_flash *f, - uint32_t addr, size_t len) + target_addr addr, size_t len) { target *t = f->t; uint16_t sr; @@ -214,7 +212,7 @@ static int stm32f1_flash_erase(struct target_flash *f, } static int stm32f1_flash_write(struct target_flash *f, - uint32_t dest, const void *src, size_t len) + target_addr dest, const void *src, size_t len) { target *t = f->t; /* Write stub and data to target ram and set PC */ @@ -324,16 +322,16 @@ static bool stm32f1_cmd_option(target *t, int argc, char *argv[]) stm32f1_option_erase(t); stm32f1_option_write_erased(t, FLASH_OBP_RDP, flash_obp_rdp_key); } else if (rdprt) { - gdb_out("Device is Read Protected\n"); - gdb_out("Use \"monitor option erase\" to unprotect, erasing device\n"); + tc_printf(t, "Device is Read Protected\n"); + tc_printf(t, "Use \"monitor option erase\" to unprotect, erasing device\n"); return true; } else if (argc == 3) { addr = strtol(argv[1], NULL, 0); val = strtol(argv[2], NULL, 0); stm32f1_option_write(t, addr, val); } else { - gdb_out("usage: monitor option erase\n"); - gdb_out("usage: monitor option \n"); + tc_printf(t, "usage: monitor option erase\n"); + tc_printf(t, "usage: monitor option \n"); } if (0 && flash_obp_rdp_key == FLASH_OBP_RDP_KEY_F3) { @@ -348,8 +346,8 @@ static bool stm32f1_cmd_option(target *t, int argc, char *argv[]) for (int i = 0; i < 0xf; i += 4) { addr = 0x1ffff800 + i; val = target_mem_read32(t, addr); - gdb_outf("0x%08X: 0x%04X\n", addr, val & 0xFFFF); - gdb_outf("0x%08X: 0x%04X\n", addr + 2, val >> 16); + tc_printf(t, "0x%08X: 0x%04X\n", addr, val & 0xFFFF); + tc_printf(t, "0x%08X: 0x%04X\n", addr + 2, val >> 16); } return true; } diff --git a/src/stm32f4.c b/src/target/stm32f4.c similarity index 93% rename from src/stm32f4.c rename to src/target/stm32f4.c index f94f8db..4749849 100644 --- a/src/stm32f4.c +++ b/src/target/stm32f4.c @@ -31,11 +31,9 @@ */ #include "general.h" -#include "adiv5.h" #include "target.h" +#include "target_internal.h" #include "cortexm.h" -#include "command.h" -#include "gdb_packet.h" static bool stm32f4_cmd_erase_mass(target *t); static bool stm32f4_cmd_option(target *t, int argc, char *argv[]); @@ -47,9 +45,9 @@ const struct command_s stm32f4_cmd_list[] = { }; -static int stm32f4_flash_erase(struct target_flash *f, uint32_t addr, size_t len); +static int stm32f4_flash_erase(struct target_flash *f, target_addr addr, size_t len); static int stm32f4_flash_write(struct target_flash *f, - uint32_t dest, const void *src, size_t len); + target_addr dest, const void *src, size_t len); static const char stm32f4_driver_str[] = "STM32F4xx"; static const char stm32f7_driver_str[] = "STM32F7xx"; @@ -106,7 +104,7 @@ static const char stm32f2_driver_str[] = "STM32F2xx"; /* This routine uses word access. Only usable on target voltage >2.7V */ static const uint16_t stm32f4_flash_write_stub[] = { -#include "../flashstub/stm32f4.stub" +#include "flashstub/stm32f4.stub" }; #define SRAM_BASE 0x20000000 @@ -221,7 +219,7 @@ static void stm32f4_flash_unlock(target *t) } } -static int stm32f4_flash_erase(struct target_flash *f, uint32_t addr, size_t len) +static int stm32f4_flash_erase(struct target_flash *f, target_addr addr, size_t len) { target *t = f->t; uint16_t sr; @@ -256,7 +254,7 @@ static int stm32f4_flash_erase(struct target_flash *f, uint32_t addr, size_t len } static int stm32f4_flash_write(struct target_flash *f, - uint32_t dest, const void *src, size_t len) + target_addr dest, const void *src, size_t len) { /* Write buffer to target ram call stub */ target_mem_write(f->t, SRAM_BASE, stm32f4_flash_write_stub, @@ -271,7 +269,7 @@ static bool stm32f4_cmd_erase_mass(target *t) const char spinner[] = "|/-\\"; int spinindex = 0; - gdb_out("Erasing flash... This may take a few seconds. "); + tc_printf(t, "Erasing flash... This may take a few seconds. "); stm32f4_flash_unlock(t); /* Flash mass erase start instruction */ @@ -280,13 +278,13 @@ static bool stm32f4_cmd_erase_mass(target *t) /* Read FLASH_SR to poll for BSY bit */ while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) { - gdb_outf("\b%c", spinner[spinindex++ % 4]); + tc_printf(t, "\b%c", spinner[spinindex++ % 4]); if(target_check_error(t)) { - gdb_out("\n"); + tc_printf(t, "\n"); return false; } } - gdb_out("\n"); + tc_printf(t, "\n"); /* Check for error */ uint16_t sr = target_mem_read32(t, FLASH_SR); @@ -337,14 +335,14 @@ static bool stm32f4_cmd_option(target *t, int argc, char *argv[]) val = strtoul(argv[2], NULL, 0); stm32f4_option_write(t, val); } else { - gdb_out("usage: monitor option erase\n"); - gdb_out("usage: monitor option write \n"); + tc_printf(t, "usage: monitor option erase\n"); + tc_printf(t, "usage: monitor option write \n"); } for (int i = 0; i < len; i += 8) { uint32_t addr = start + i; val = target_mem_read32(t, addr); - gdb_outf("0x%08X: 0x%04X\n", addr, val & 0xFFFF); + tc_printf(t, "0x%08X: 0x%04X\n", addr, val & 0xFFFF); } return true; } diff --git a/src/stm32l0.c b/src/target/stm32l0.c similarity index 75% rename from src/stm32l0.c rename to src/target/stm32l0.c index 0c35577..8e81d84 100644 --- a/src/stm32l0.c +++ b/src/target/stm32l0.c @@ -74,25 +74,84 @@ */ #include "general.h" -#include "adiv5.h" #include "target.h" -#include "command.h" -#include "gdb_packet.h" +#include "target_internal.h" #include "cortexm.h" -#include "stm32lx-nvm.h" +#define STM32Lx_NVM_PECR(p) ((p) + 0x04) +#define STM32Lx_NVM_PEKEYR(p) ((p) + 0x0C) +#define STM32Lx_NVM_PRGKEYR(p) ((p) + 0x10) +#define STM32Lx_NVM_OPTKEYR(p) ((p) + 0x14) +#define STM32Lx_NVM_SR(p) ((p) + 0x18) +#define STM32Lx_NVM_OPTR(p) ((p) + 0x1C) + +#define STM32L0_NVM_PHYS (0x40022000ul) +#define STM32L0_NVM_OPT_SIZE (12) +#define STM32L0_NVM_EEPROM_SIZE (2*1024) + +#define STM32L1_NVM_PHYS (0x40023c00ul) +#define STM32L1_NVM_OPT_SIZE (32) +#define STM32L1_NVM_EEPROM_SIZE (16*1024) + +#define STM32Lx_NVM_OPT_PHYS 0x1ff80000ul +#define STM32Lx_NVM_EEPROM_PHYS 0x08080000ul + +#define STM32Lx_NVM_PEKEY1 (0x89abcdeful) +#define STM32Lx_NVM_PEKEY2 (0x02030405ul) +#define STM32Lx_NVM_PRGKEY1 (0x8c9daebful) +#define STM32Lx_NVM_PRGKEY2 (0x13141516ul) +#define STM32Lx_NVM_OPTKEY1 (0xfbead9c8ul) +#define STM32Lx_NVM_OPTKEY2 (0x24252627ul) + +#define STM32Lx_NVM_PECR_OBL_LAUNCH (1<<18) +#define STM32Lx_NVM_PECR_ERRIE (1<<17) +#define STM32Lx_NVM_PECR_EOPIE (1<<16) +#define STM32Lx_NVM_PECR_FPRG (1<<10) +#define STM32Lx_NVM_PECR_ERASE (1<< 9) +#define STM32Lx_NVM_PECR_FIX (1<< 8) /* FTDW */ +#define STM32Lx_NVM_PECR_DATA (1<< 4) +#define STM32Lx_NVM_PECR_PROG (1<< 3) +#define STM32Lx_NVM_PECR_OPTLOCK (1<< 2) +#define STM32Lx_NVM_PECR_PRGLOCK (1<< 1) +#define STM32Lx_NVM_PECR_PELOCK (1<< 0) + +#define STM32Lx_NVM_SR_NOTZEROERR (1<<16) +#define STM32Lx_NVM_SR_SIZERR (1<<10) +#define STM32Lx_NVM_SR_PGAERR (1<<9) +#define STM32Lx_NVM_SR_WRPERR (1<<8) +#define STM32Lx_NVM_SR_EOP (1<<1) +#define STM32Lx_NVM_SR_BSY (1<<0) +#define STM32Lx_NVM_SR_ERR_M (STM32Lx_NVM_SR_WRPERR | \ + STM32Lx_NVM_SR_PGAERR | \ + STM32Lx_NVM_SR_SIZERR | \ + STM32Lx_NVM_SR_NOTZEROERR) + +#define STM32L0_NVM_OPTR_BOOT1 (1<<31) +#define STM32Lx_NVM_OPTR_WDG_SW (1<<20) +#define STM32L0_NVM_OPTR_WPRMOD (1<<8) +#define STM32Lx_NVM_OPTR_RDPROT_S (0) +#define STM32Lx_NVM_OPTR_RDPROT_M (0xff) +#define STM32Lx_NVM_OPTR_RDPROT_0 (0xaa) +#define STM32Lx_NVM_OPTR_RDPROT_2 (0xcc) + +#define STM32L1_NVM_OPTR_nBFB2 (1<<23) +#define STM32L1_NVM_OPTR_nRST_STDBY (1<<22) +#define STM32L1_NVM_OPTR_nRST_STOP (1<<21) +#define STM32L1_NVM_OPTR_BOR_LEV_S (16) +#define STM32L1_NVM_OPTR_BOR_LEV_M (0xf) +#define STM32L1_NVM_OPTR_SPRMOD (1<<8) static int stm32lx_nvm_prog_erase(struct target_flash* f, - uint32_t addr, size_t len); + target_addr addr, size_t len); static int stm32lx_nvm_prog_write(struct target_flash* f, - uint32_t destination, + target_addr destination, const void* src, size_t size); static int stm32lx_nvm_data_erase(struct target_flash* f, - uint32_t addr, size_t len); + target_addr addr, size_t len); static int stm32lx_nvm_data_write(struct target_flash* f, - uint32_t destination, + target_addr destination, const void* source, size_t size); @@ -263,7 +322,7 @@ static bool stm32lx_nvm_opt_unlock(target *t, uint32_t nvm) flash array is erased for all pages from addr to addr+len inclusive. NVM register file address chosen from target. */ static int stm32lx_nvm_prog_erase(struct target_flash* f, - uint32_t addr, size_t len) + target_addr addr, size_t len) { target *t = f->t; const size_t page_size = f->blocksize; @@ -313,7 +372,7 @@ static int stm32lx_nvm_prog_erase(struct target_flash* f, /** Write to program flash using operations through the debug interface. */ static int stm32lx_nvm_prog_write(struct target_flash *f, - uint32_t dest, + target_addr dest, const void* src, size_t size) { @@ -356,7 +415,7 @@ static int stm32lx_nvm_prog_write(struct target_flash *f, addr+len, inclusive, on a word boundary. NVM register file address chosen from target. */ static int stm32lx_nvm_data_erase(struct target_flash *f, - uint32_t addr, size_t len) + target_addr addr, size_t len) { target *t = f->t; const size_t page_size = f->blocksize; @@ -408,7 +467,7 @@ static int stm32lx_nvm_data_erase(struct target_flash *f, destination writes are supported (though unaligned sources are not). */ static int stm32lx_nvm_data_write(struct target_flash *f, - uint32_t destination, + target_addr destination, const void* src, size_t size) { @@ -516,7 +575,7 @@ static bool stm32lx_cmd_option(target* t, int argc, char** argv) const size_t opt_size = stm32lx_nvm_option_size(t); if (!stm32lx_nvm_opt_unlock(t, nvm)) { - gdb_out("unable to unlock NVM option bytes\n"); + tc_printf(t, "unable to unlock NVM option bytes\n"); return true; } @@ -529,25 +588,25 @@ static bool stm32lx_cmd_option(target* t, int argc, char** argv) else if (argc == 4 && !strncasecmp(argv[1], "raw", cb)) { uint32_t addr = strtoul(argv[2], NULL, 0); uint32_t val = strtoul(argv[3], NULL, 0); - gdb_outf("raw %08x <- %08x\n", addr, val); + tc_printf(t, "raw %08x <- %08x\n", addr, val); if ( addr < STM32Lx_NVM_OPT_PHYS || addr >= STM32Lx_NVM_OPT_PHYS + opt_size || (addr & 3)) goto usage; if (!stm32lx_option_write(t, addr, val)) - gdb_out("option write failed\n"); + tc_printf(t, "option write failed\n"); } else if (argc == 4 && !strncasecmp(argv[1], "write", cb)) { uint32_t addr = strtoul(argv[2], NULL, 0); uint32_t val = strtoul(argv[3], NULL, 0); val = (val & 0xffff) | ((~val & 0xffff) << 16); - gdb_outf("write %08x <- %08x\n", addr, val); + tc_printf(t, "write %08x <- %08x\n", addr, val); if ( addr < STM32Lx_NVM_OPT_PHYS || addr >= STM32Lx_NVM_OPT_PHYS + opt_size || (addr & 3)) goto usage; if (!stm32lx_option_write(t, addr, val)) - gdb_out("option write failed\n"); + tc_printf(t, "option write failed\n"); } else if (argc == 2 && !strncasecmp(argv[1], "show", cb)) ; @@ -558,66 +617,66 @@ static bool stm32lx_cmd_option(target* t, int argc, char** argv) for(unsigned i = 0; i < opt_size; i += sizeof(uint32_t)) { uint32_t addr = STM32Lx_NVM_OPT_PHYS + i; uint32_t val = target_mem_read32(t, addr); - gdb_outf("0x%08x: 0x%04x 0x%04x %s\n", - addr, val & 0xffff, (val >> 16) & 0xffff, - ((val & 0xffff) == ((~val >> 16) & 0xffff)) - ? "OK" : "ERR"); + tc_printf(t, "0x%08x: 0x%04x 0x%04x %s\n", + addr, val & 0xffff, (val >> 16) & 0xffff, + ((val & 0xffff) == ((~val >> 16) & 0xffff)) + ? "OK" : "ERR"); } if (stm32lx_is_stm32l1(t)) { uint32_t optr = target_mem_read32(t, STM32Lx_NVM_OPTR(nvm)); - uint8_t rdprot = (optr >> STM32L1_NVM_OPTR_RDPROT_S) - & STM32L1_NVM_OPTR_RDPROT_M; - if (rdprot == STM32L1_NVM_OPTR_RDPROT_0) + uint8_t rdprot = (optr >> STM32Lx_NVM_OPTR_RDPROT_S) + & STM32Lx_NVM_OPTR_RDPROT_M; + if (rdprot == STM32Lx_NVM_OPTR_RDPROT_0) rdprot = 0; - else if (rdprot == STM32L1_NVM_OPTR_RDPROT_2) + else if (rdprot == STM32Lx_NVM_OPTR_RDPROT_2) rdprot = 2; else rdprot = 1; - gdb_outf("OPTR: 0x%08x, RDPRT %d, SPRMD %d, " - "BOR %d, WDG_SW %d, nRST_STP %d, nRST_STBY %d, " - "nBFB2 %d\n", - optr, rdprot, - (optr & STM32L1_NVM_OPTR_SPRMOD) ? 1 : 0, - (optr >> STM32L1_NVM_OPTR_BOR_LEV_S) - & STM32L1_NVM_OPTR_BOR_LEV_M, - (optr & STM32L1_NVM_OPTR_WDG_SW) ? 1 : 0, - (optr & STM32L1_NVM_OPTR_nRST_STOP) ? 1 : 0, - (optr & STM32L1_NVM_OPTR_nRST_STDBY) ? 1 : 0, - (optr & STM32L1_NVM_OPTR_nBFB2) ? 1 : 0); + tc_printf(t, "OPTR: 0x%08x, RDPRT %d, SPRMD %d, " + "BOR %d, WDG_SW %d, nRST_STP %d, nRST_STBY %d, " + "nBFB2 %d\n", + optr, rdprot, + (optr & STM32L1_NVM_OPTR_SPRMOD) ? 1 : 0, + (optr >> STM32L1_NVM_OPTR_BOR_LEV_S) + & STM32L1_NVM_OPTR_BOR_LEV_M, + (optr & STM32Lx_NVM_OPTR_WDG_SW) ? 1 : 0, + (optr & STM32L1_NVM_OPTR_nRST_STOP) ? 1 : 0, + (optr & STM32L1_NVM_OPTR_nRST_STDBY) ? 1 : 0, + (optr & STM32L1_NVM_OPTR_nBFB2) ? 1 : 0); } else { uint32_t optr = target_mem_read32(t, STM32Lx_NVM_OPTR(nvm)); - uint8_t rdprot = (optr >> STM32L0_NVM_OPTR_RDPROT_S) - & STM32L0_NVM_OPTR_RDPROT_M; - if (rdprot == STM32L0_NVM_OPTR_RDPROT_0) + uint8_t rdprot = (optr >> STM32Lx_NVM_OPTR_RDPROT_S) + & STM32Lx_NVM_OPTR_RDPROT_M; + if (rdprot == STM32Lx_NVM_OPTR_RDPROT_0) rdprot = 0; - else if (rdprot == STM32L0_NVM_OPTR_RDPROT_2) + else if (rdprot == STM32Lx_NVM_OPTR_RDPROT_2) rdprot = 2; else rdprot = 1; - gdb_outf("OPTR: 0x%08x, RDPROT %d, WPRMOD %d, WDG_SW %d, " - "BOOT1 %d\n", - optr, rdprot, - (optr & STM32L0_NVM_OPTR_WPRMOD) ? 1 : 0, - (optr & STM32L0_NVM_OPTR_WDG_SW) ? 1 : 0, - (optr & STM32L0_NVM_OPTR_BOOT1) ? 1 : 0); + tc_printf(t, "OPTR: 0x%08x, RDPROT %d, WPRMOD %d, WDG_SW %d, " + "BOOT1 %d\n", + optr, rdprot, + (optr & STM32L0_NVM_OPTR_WPRMOD) ? 1 : 0, + (optr & STM32Lx_NVM_OPTR_WDG_SW) ? 1 : 0, + (optr & STM32L0_NVM_OPTR_BOOT1) ? 1 : 0); } goto done; usage: - gdb_out("usage: monitor option [ARGS]\n"); - gdb_out(" show - Show options in NVM and as" - " loaded\n"); - gdb_out(" obl_launch - Reload options from NVM\n"); - gdb_out(" write - Set option half-word; " - "complement computed\n"); - gdb_out(" raw - Set option word\n"); - gdb_outf("The value of must be word aligned and from 0x%08x " - "to +0x%x\n", - STM32Lx_NVM_OPT_PHYS, - STM32Lx_NVM_OPT_PHYS + opt_size - sizeof(uint32_t)); + tc_printf(t, "usage: monitor option [ARGS]\n"); + tc_printf(t, " show - Show options in NVM and as" + " loaded\n"); + tc_printf(t, " obl_launch - Reload options from NVM\n"); + tc_printf(t, " write - Set option half-word; " + "complement computed\n"); + tc_printf(t, " raw - Set option word\n"); + tc_printf(t, "The value of must be word aligned and from 0x%08x " + "to +0x%x\n", + STM32Lx_NVM_OPT_PHYS, + STM32Lx_NVM_OPT_PHYS + opt_size - sizeof(uint32_t)); done: stm32lx_nvm_lock(t, nvm); @@ -630,7 +689,7 @@ static bool stm32lx_cmd_eeprom(target* t, int argc, char** argv) const uint32_t nvm = stm32lx_nvm_phys(t); if (!stm32lx_nvm_prog_data_unlock(t, nvm)) { - gdb_out("unable to unlock EEPROM\n"); + tc_printf(t, "unable to unlock EEPROM\n"); return true; } @@ -646,23 +705,23 @@ static bool stm32lx_cmd_eeprom(target* t, int argc, char** argv) goto usage; if (!strncasecmp(argv[1], "byte", cb)) { - gdb_outf("write byte 0x%08x <- 0x%08x\n", addr, val); + tc_printf(t, "write byte 0x%08x <- 0x%08x\n", addr, val); if (!stm32lx_eeprom_write(t, addr, 1, val)) - gdb_out("eeprom write failed\n"); + tc_printf(t, "eeprom write failed\n"); } else if (!strncasecmp(argv[1], "halfword", cb)) { val &= 0xffff; - gdb_outf("write halfword 0x%08x <- 0x%04x\n", + tc_printf(t, "write halfword 0x%08x <- 0x%04x\n", addr, val); if (addr & 1) goto usage; if (!stm32lx_eeprom_write(t, addr, 2, val)) - gdb_out("eeprom write failed\n"); + tc_printf(t, "eeprom write failed\n"); } else if (!strncasecmp(argv[1], "word", cb)) { - gdb_outf("write word 0x%08x <- 0x%08x\n", addr, val); + tc_printf(t, "write word 0x%08x <- 0x%08x\n", addr, val); if (addr & 3) goto usage; if (!stm32lx_eeprom_write(t, addr, 4, val)) - gdb_out("eeprom write failed\n"); + tc_printf(t, "eeprom write failed\n"); } else goto usage; @@ -673,14 +732,13 @@ static bool stm32lx_cmd_eeprom(target* t, int argc, char** argv) goto done; usage: - gdb_out("usage: monitor eeprom [ARGS]\n"); - gdb_out(" byte - Write a byte\n"); - gdb_out(" halfword - Write a half-word\n"); - gdb_out(" word - Write a word\n"); - gdb_outf("The value of must in the interval [0x%08x, 0x%x)\n", - STM32Lx_NVM_EEPROM_PHYS, - STM32Lx_NVM_EEPROM_PHYS - + stm32lx_nvm_eeprom_size(t)); + tc_printf(t, "usage: monitor eeprom [ARGS]\n"); + tc_printf(t, " byte - Write a byte\n"); + tc_printf(t, " halfword - Write a half-word\n"); + tc_printf(t, " word - Write a word\n"); + tc_printf(t, "The value of must in the interval [0x%08x, 0x%x)\n", + STM32Lx_NVM_EEPROM_PHYS, + STM32Lx_NVM_EEPROM_PHYS + stm32lx_nvm_eeprom_size(t)); done: stm32lx_nvm_lock(t, nvm); diff --git a/src/stm32l4.c b/src/target/stm32l4.c similarity index 92% rename from src/stm32l4.c rename to src/target/stm32l4.c index d4e22a7..d65caca 100644 --- a/src/stm32l4.c +++ b/src/target/stm32l4.c @@ -31,11 +31,9 @@ */ #include "general.h" -#include "adiv5.h" #include "target.h" +#include "target_internal.h" #include "cortexm.h" -#include "command.h" -#include "gdb_packet.h" static bool stm32l4_cmd_erase_mass(target *t); static bool stm32l4_cmd_erase_bank1(target *t); @@ -51,9 +49,9 @@ const struct command_s stm32l4_cmd_list[] = { }; -static int stm32l4_flash_erase(struct target_flash *f, uint32_t addr, size_t len); +static int stm32l4_flash_erase(struct target_flash *f, target_addr addr, size_t len); static int stm32l4_flash_write(struct target_flash *f, - uint32_t dest, const void *src, size_t len); + target_addr dest, const void *src, size_t len); static const char stm32l4_driver_str[] = "STM32L4xx"; @@ -112,7 +110,7 @@ static const char stm32l4_driver_str[] = "STM32L4xx"; /* This routine is uses double word access.*/ static const uint16_t stm32l4_flash_write_stub[] = { -#include "../flashstub/stm32l4.stub" +#include "flashstub/stm32l4.stub" }; #define SRAM_BASE 0x20000000 @@ -173,7 +171,7 @@ static void stm32l4_flash_unlock(target *t) } } -static int stm32l4_flash_erase(struct target_flash *f, uint32_t addr, size_t len) +static int stm32l4_flash_erase(struct target_flash *f, target_addr addr, size_t len) { target *t = f->t; uint16_t sr; @@ -214,7 +212,7 @@ static int stm32l4_flash_erase(struct target_flash *f, uint32_t addr, size_t len } static int stm32l4_flash_write(struct target_flash *f, - uint32_t dest, const void *src, size_t len) + target_addr dest, const void *src, size_t len) { /* Write buffer to target ram call stub */ target_mem_write(f->t, SRAM_BASE, stm32l4_flash_write_stub, @@ -229,7 +227,7 @@ static bool stm32l4_cmd_erase(target *t, uint32_t action) const char spinner[] = "|/-\\"; int spinindex = 0; - gdb_out("Erasing flash... This may take a few seconds. "); + tc_printf(t, "Erasing flash... This may take a few seconds. "); stm32l4_flash_unlock(t); /* Flash erase action start instruction */ @@ -238,13 +236,13 @@ static bool stm32l4_cmd_erase(target *t, uint32_t action) /* Read FLASH_SR to poll for BSY bit */ while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) { - gdb_outf("\b%c", spinner[spinindex++ % 4]); + tc_printf(t, "\b%c", spinner[spinindex++ % 4]); if(target_check_error(t)) { - gdb_out("\n"); + tc_printf(t, "\n"); return false; } } - gdb_out("\n"); + tc_printf(t, "\n"); /* Check for error */ uint16_t sr = target_mem_read32(t, FLASH_SR); @@ -277,12 +275,12 @@ static bool stm32l4_cmd_option(target *t, int argc, char *argv[]) for (int i = 0; i < 0x23; i += 8) { addr = 0x1fff7800 + i; val = target_mem_read32(t, addr); - gdb_outf("0x%08X: 0x%08x\n", addr, val); + tc_printf(t, "0x%08X: 0x%08x\n", addr, val); } for (int i = 8; i < 0x23; i += 8) { addr = 0x1ffff800 + i; val = target_mem_read32(t, addr); - gdb_outf("0x%08X: 0x%08X\n", addr, val); + tc_printf(t, "0x%08X: 0x%08X\n", addr, val); } return true; } diff --git a/src/target/swdptap_generic.c b/src/target/swdptap_generic.c new file mode 100644 index 0000000..13ee02f --- /dev/null +++ b/src/target/swdptap_generic.c @@ -0,0 +1,79 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2016 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "general.h" +#include "swdptap.h" + +uint32_t __attribute__((weak)) +swdptap_seq_in(int ticks) +{ + uint32_t index = 1; + uint32_t ret = 0; + + while (ticks--) { + if (swdptap_bit_in()) + ret |= index; + index <<= 1; + } + + return ret; +} + +bool __attribute__((weak)) +swdptap_seq_in_parity(uint32_t *ret, int ticks) +{ + uint32_t index = 1; + uint8_t parity = 0; + *ret = 0; + + while (ticks--) { + if (swdptap_bit_in()) { + *ret |= index; + parity ^= 1; + } + index <<= 1; + } + if (swdptap_bit_in()) + parity ^= 1; + + return parity; +} + +void __attribute__((weak)) +swdptap_seq_out(uint32_t MS, int ticks) +{ + while (ticks--) { + swdptap_bit_out(MS & 1); + MS >>= 1; + } +} + +void __attribute__((weak)) +swdptap_seq_out_parity(uint32_t MS, int ticks) +{ + uint8_t parity = 0; + + while (ticks--) { + swdptap_bit_out(MS & 1); + parity ^= MS; + MS >>= 1; + } + swdptap_bit_out(parity & 1); +} + diff --git a/src/target/target.c b/src/target/target.c new file mode 100644 index 0000000..8ba1605 --- /dev/null +++ b/src/target/target.c @@ -0,0 +1,554 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2016 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "general.h" +#include "target.h" +#include "target_internal.h" + +#include + +target *target_list = NULL; + +target *target_new(void) +{ + target *t = (void*)calloc(1, sizeof(*t)); + t->next = target_list; + target_list = t; + + return t; +} + +bool target_foreach(void (*cb)(int, target *t, void *context), void *context) +{ + int i = 1; + target *t = target_list; + for (; t; t = t->next, i++) + cb(i, t, context); + return target_list != NULL; +} + +void target_list_free(void) +{ + struct target_command_s *tc; + + while(target_list) { + target *t = target_list->next; + if (target_list->tc) + target_list->tc->destroy_callback(target_list->tc, target_list); + if (target_list->priv) + target_list->priv_free(target_list->priv); + while (target_list->commands) { + tc = target_list->commands->next; + free(target_list->commands); + target_list->commands = tc; + } + if (target_list->dyn_mem_map) + free(target_list->dyn_mem_map); + while (target_list->ram) { + void * next = target_list->ram->next; + free(target_list->ram); + target_list->ram = next; + } + while (target_list->flash) { + void * next = target_list->flash->next; + if (target_list->flash->buf) + free(target_list->flash->buf); + free(target_list->flash); + target_list->flash = next; + } + while (target_list->bw_list) { + void * next = target_list->bw_list->next; + free(target_list->bw_list); + target_list->bw_list = next; + } + free(target_list); + target_list = t; + } +} + +void target_add_commands(target *t, const struct command_s *cmds, const char *name) +{ + struct target_command_s *tc; + if (t->commands) { + for (tc = t->commands; tc->next; tc = tc->next); + tc = tc->next = malloc(sizeof(*tc)); + } else { + t->commands = tc = malloc(sizeof(*tc)); + } + tc->specific_name = name; + tc->cmds = cmds; + tc->next = NULL; +} + +target *target_attach_n(int n, struct target_controller *tc) +{ + target *t; + int i; + for(t = target_list, i = 1; t; t = t->next, i++) + if(i == n) + return target_attach(t, tc); + return NULL; +} + +target *target_attach(target *t, struct target_controller *tc) +{ + if (t->tc) + t->tc->destroy_callback(t->tc, t); + + t->tc = tc; + + if (!t->attach(t)) + return NULL; + + t->attached = true; + return t; +} + +void target_add_ram(target *t, target_addr start, uint32_t len) +{ + struct target_ram *ram = malloc(sizeof(*ram)); + ram->start = start; + ram->length = len; + ram->next = t->ram; + t->ram = ram; +} + +void target_add_flash(target *t, struct target_flash *f) +{ + f->t = t; + f->next = t->flash; + t->flash = f; +} + +static ssize_t map_ram(char *buf, size_t len, struct target_ram *ram) +{ + return snprintf(buf, len, "", + ram->start, ram->length); +} + +static ssize_t map_flash(char *buf, size_t len, struct target_flash *f) +{ + int i = 0; + i += snprintf(&buf[i], len - i, "", + f->start, f->length); + i += snprintf(&buf[i], len - i, "0x%08zx" + "", + f->blocksize); + return i; +} + +const char *target_mem_map(target *t) +{ + if (t->dyn_mem_map) + return t->dyn_mem_map; + + /* FIXME size buffer */ + size_t len = 1024; + char *tmp = malloc(len); + size_t i = 0; + i = snprintf(&tmp[i], len - i, ""); + /* Map each defined RAM */ + for (struct target_ram *r = t->ram; r; r = r->next) + i += map_ram(&tmp[i], len - i, r); + /* Map each defined Flash */ + for (struct target_flash *f = t->flash; f; f = f->next) + i += map_flash(&tmp[i], len - i, f); + i += snprintf(&tmp[i], len - i, ""); + + t->dyn_mem_map = tmp; + + return t->dyn_mem_map; +} + +static struct target_flash *flash_for_addr(target *t, uint32_t addr) +{ + for (struct target_flash *f = t->flash; f; f = f->next) + if ((f->start <= addr) && + (addr < (f->start + f->length))) + return f; + return NULL; +} + +int target_flash_erase(target *t, target_addr addr, size_t len) +{ + int ret = 0; + while (len) { + struct target_flash *f = flash_for_addr(t, addr); + size_t tmplen = MIN(len, f->length - (addr % f->length)); + ret |= f->erase(f, addr, tmplen); + addr += tmplen; + len -= tmplen; + } + return ret; +} + +int target_flash_write(target *t, + target_addr dest, const void *src, size_t len) +{ + int ret = 0; + while (len) { + struct target_flash *f = flash_for_addr(t, dest); + size_t tmplen = MIN(len, f->length - (dest % f->length)); + if (f->align > 1) { + uint32_t offset = dest % f->align; + uint8_t data[ALIGN(offset + len, f->align)]; + memset(data, f->erased, sizeof(data)); + memcpy((uint8_t *)data + offset, src, len); + ret |= f->write(f, dest - offset, data, sizeof(data)); + } else { + ret |= f->write(f, dest, src, tmplen); + } + src += tmplen; + len -= tmplen; + } + return ret; +} + +int target_flash_done(target *t) +{ + for (struct target_flash *f = t->flash; f; f = f->next) { + if (f->done) { + int tmp = f->done(f); + if (tmp) + return tmp; + } + } + return 0; +} + +int target_flash_write_buffered(struct target_flash *f, + target_addr dest, const void *src, size_t len) +{ + int ret = 0; + + if (f->buf == NULL) { + /* Allocate flash sector buffer */ + f->buf = malloc(f->buf_size); + f->buf_addr = -1; + } + while (len) { + uint32_t offset = dest % f->buf_size; + uint32_t base = dest - offset; + if (base != f->buf_addr) { + if (f->buf_addr != (uint32_t)-1) { + /* Write sector to flash if valid */ + ret |= f->write_buf(f, f->buf_addr, + f->buf, f->buf_size); + } + /* Setup buffer for a new sector */ + f->buf_addr = base; + memset(f->buf, f->erased, f->buf_size); + } + /* Copy chunk into sector buffer */ + size_t sectlen = MIN(f->buf_size - offset, len); + memcpy(f->buf + offset, src, sectlen); + dest += sectlen; + src += sectlen; + len -= sectlen; + } + return ret; +} + +int target_flash_done_buffered(struct target_flash *f) +{ + int ret = 0; + if ((f->buf != NULL) &&(f->buf_addr != (uint32_t)-1)) { + /* Write sector to flash if valid */ + ret = f->write_buf(f, f->buf_addr, f->buf, f->buf_size); + f->buf_addr = -1; + free(f->buf); + f->buf = NULL; + } + + return ret; +} + +/* Wrapper functions */ +void target_detach(target *t) +{ + t->detach(t); + t->attached = false; +} + +bool target_check_error(target *t) { return t->check_error(t); } +bool target_attached(target *t) { return t->attached; } + +/* Memory access functions */ +int target_mem_read(target *t, void *dest, target_addr src, size_t len) +{ + t->mem_read(t, dest, src, len); + return target_check_error(t); +} + +int target_mem_write(target *t, target_addr dest, const void *src, size_t len) +{ + t->mem_write(t, dest, src, len); + return target_check_error(t); +} + +/* Register access functions */ +void target_regs_read(target *t, void *data) { t->regs_read(t, data); } +void target_regs_write(target *t, const void *data) { t->regs_write(t, data); } + +/* Halt/resume functions */ +void target_reset(target *t) { t->reset(t); } +void target_halt_request(target *t) { t->halt_request(t); } +enum target_halt_reason target_halt_poll(target *t, target_addr *watch) +{ + return t->halt_poll(t, watch); +} + +void target_halt_resume(target *t, bool step) { t->halt_resume(t, step); } + +/* Break-/watchpoint functions */ +int target_breakwatch_set(target *t, + enum target_breakwatch type, target_addr addr, size_t len) +{ + struct breakwatch bw = { + .type = type, + .addr = addr, + .size = len, + }; + int ret = 1; + + if (t->breakwatch_set) + ret = t->breakwatch_set(t, &bw); + + if (ret == 0) { + /* Success, make a heap copy and add to list */ + struct breakwatch *bwm = malloc(sizeof bw); + memcpy(bwm, &bw, sizeof(bw)); + bwm->next = t->bw_list; + t->bw_list = bwm; + } + + return ret; +} + +int target_breakwatch_clear(target *t, + enum target_breakwatch type, target_addr addr, size_t len) +{ + struct breakwatch *bwp = NULL, *bw; + int ret = 1; + for (bw = t->bw_list; bw; bw = bw->next, bwp = bw) + if ((bw->type == type) && + (bw->addr == addr) && + (bw->size == len)) + break; + + if (bw == NULL) + return -1; + + if (t->breakwatch_clear) + ret = t->breakwatch_clear(t, bw); + + if (ret == 0) { + if (bwp == NULL) { + t->bw_list = bw->next; + } else { + bwp->next = bw->next; + } + free(bw); + } + return ret; +} + +/* Accessor functions */ +size_t target_regs_size(target *t) +{ + return t->regs_size; +} + +const char *target_tdesc(target *t) +{ + return t->tdesc ? t->tdesc : ""; +} + +const char *target_driver_name(target *t) +{ + return t->driver; +} + +uint32_t target_mem_read32(target *t, uint32_t addr) +{ + uint32_t ret; + t->mem_read(t, &ret, addr, sizeof(ret)); + return ret; +} + +void target_mem_write32(target *t, uint32_t addr, uint32_t value) +{ + t->mem_write(t, addr, &value, sizeof(value)); +} + +uint16_t target_mem_read16(target *t, uint32_t addr) +{ + uint16_t ret; + t->mem_read(t, &ret, addr, sizeof(ret)); + return ret; +} + +void target_mem_write16(target *t, uint32_t addr, uint16_t value) +{ + t->mem_write(t, addr, &value, sizeof(value)); +} + +uint8_t target_mem_read8(target *t, uint32_t addr) +{ + uint8_t ret; + t->mem_read(t, &ret, addr, sizeof(ret)); + return ret; +} + +void target_mem_write8(target *t, uint32_t addr, uint8_t value) +{ + t->mem_write(t, addr, &value, sizeof(value)); +} + +void target_command_help(target *t) +{ + for (struct target_command_s *tc = t->commands; tc; tc = tc->next) { + tc_printf(t, "%s specific commands:\n", tc->specific_name); + for(const struct command_s *c = tc->cmds; c->cmd; c++) + tc_printf(t, "\t%s -- %s\n", c->cmd, c->help); + } +} + +int target_command(target *t, int argc, const char *argv[]) +{ + for (struct target_command_s *tc = t->commands; tc; tc = tc->next) + for(const struct command_s *c = tc->cmds; c->cmd; c++) + if(!strncmp(argv[0], c->cmd, strlen(argv[0]))) + return !c->handler(t, argc, argv); + return -1; +} + +void tc_printf(target *t, const char *fmt, ...) +{ + (void)t; + va_list ap; + va_start(ap, fmt); + t->tc->printf(t->tc, fmt, ap); + va_end(ap); +} + +/* Interface to host system calls */ +int tc_open(target *t, target_addr path, size_t plen, + enum target_open_flags flags, mode_t mode) +{ + if (t->tc->open == NULL) { + t->tc->errno_ = TARGET_ENFILE; + return -1; + } + return t->tc->open(t->tc, path, plen, flags, mode); +} + +int tc_close(target *t, int fd) +{ + if (t->tc->close == NULL) { + t->tc->errno_ = TARGET_EBADF; + return -1; + } + return t->tc->close(t->tc, fd); +} + +int tc_read(target *t, int fd, target_addr buf, unsigned int count) +{ + if (t->tc->read == NULL) + return 0; + return t->tc->read(t->tc, fd, buf, count); +} + +int tc_write(target *t, int fd, target_addr buf, unsigned int count) +{ + if (t->tc->write == NULL) + return 0; + return t->tc->write(t->tc, fd, buf, count); +} + +long tc_lseek(target *t, int fd, long offset, enum target_seek_flag flag) +{ + if (t->tc->lseek == NULL) + return 0; + return t->tc->lseek(t->tc, fd, offset, flag); +} + +int tc_rename(target *t, target_addr oldpath, size_t oldlen, + target_addr newpath, size_t newlen) +{ + if (t->tc->rename == NULL) { + t->tc->errno_ = TARGET_ENOENT; + return -1; + } + return t->tc->rename(t->tc, oldpath, oldlen, newpath, newlen); +} + +int tc_unlink(target *t, target_addr path, size_t plen) +{ + if (t->tc->unlink == NULL) { + t->tc->errno_ = TARGET_ENOENT; + return -1; + } + return t->tc->unlink(t->tc, path, plen); +} + +int tc_stat(target *t, target_addr path, size_t plen, target_addr buf) +{ + if (t->tc->stat == NULL) { + t->tc->errno_ = TARGET_ENOENT; + return -1; + } + return t->tc->stat(t->tc, path, plen, buf); +} + +int tc_fstat(target *t, int fd, target_addr buf) +{ + if (t->tc->fstat == NULL) { + return 0; + } + return t->tc->fstat(t->tc, fd, buf); +} + +int tc_gettimeofday(target *t, target_addr tv, target_addr tz) +{ + if (t->tc->gettimeofday == NULL) { + return -1; + } + return t->tc->gettimeofday(t->tc, tv, tz); +} + +int tc_isatty(target *t, int fd) +{ + if (t->tc->isatty == NULL) { + return 1; + } + return t->tc->isatty(t->tc, fd); +} + +int tc_system(target *t, target_addr cmd, size_t cmdlen) +{ + if (t->tc->system == NULL) { + return -1; + } + return t->tc->system(t->tc, cmd, cmdlen); +} + diff --git a/src/target/target_internal.h b/src/target/target_internal.h new file mode 100644 index 0000000..75bd743 --- /dev/null +++ b/src/target/target_internal.h @@ -0,0 +1,185 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2011 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TARGET_INTERNAL_H +#define __TARGET_INTERNAL_H + +extern target *target_list; +target *target_new(void); + +struct target_ram { + target_addr start; + size_t length; + struct target_ram *next; +}; + +struct target_flash; +typedef int (*flash_erase_func)(struct target_flash *f, target_addr addr, size_t len); +typedef int (*flash_write_func)(struct target_flash *f, target_addr dest, + const void *src, size_t len); +typedef int (*flash_done_func)(struct target_flash *f); +struct target_flash { + target_addr start; + size_t length; + size_t blocksize; + flash_erase_func erase; + flash_write_func write; + flash_done_func done; + target *t; + struct target_flash *next; + int align; + uint8_t erased; + + /* For buffered flash */ + size_t buf_size; + flash_write_func write_buf; + target_addr buf_addr; + void *buf; +}; + +typedef bool (*cmd_handler)(target *t, int argc, const char **argv); + +struct command_s { + const char *cmd; + cmd_handler handler; + const char *help; +}; + +struct target_command_s { + const char *specific_name; + const struct command_s *cmds; + struct target_command_s *next; +}; + +struct breakwatch { + struct breakwatch *next; + enum target_breakwatch type; + target_addr addr; + size_t size; + uint32_t reserved[4]; /* for use by the implementing driver */ +}; + +struct target_s { + bool attached; + struct target_controller *tc; + + /* Attach/Detach funcitons */ + bool (*attach)(target *t); + void (*detach)(target *t); + bool (*check_error)(target *t); + + /* Memory access functions */ + void (*mem_read)(target *t, void *dest, target_addr src, + size_t len); + void (*mem_write)(target *t, target_addr dest, + const void *src, size_t len); + + /* Register access functions */ + size_t regs_size; + const char *tdesc; + void (*regs_read)(target *t, void *data); + void (*regs_write)(target *t, const void *data); + + /* Halt/resume functions */ + void (*reset)(target *t); + void (*halt_request)(target *t); + enum target_halt_reason (*halt_poll)(target *t, target_addr *watch); + void (*halt_resume)(target *t, bool step); + + /* Break-/watchpoint functions */ + int (*breakwatch_set)(target *t, struct breakwatch*); + int (*breakwatch_clear)(target *t, struct breakwatch*); + struct breakwatch *bw_list; + + /* target-defined options */ + unsigned target_options; + uint32_t idcode; + + /* Target memory map */ + char *dyn_mem_map; + struct target_ram *ram; + struct target_flash *flash; + + /* Other stuff */ + const char *driver; + struct target_command_s *commands; + + struct target_s *next; + + void *priv; + void (*priv_free)(void *); +}; + +void target_add_commands(target *t, const struct command_s *cmds, const char *name); +void target_add_ram(target *t, target_addr start, uint32_t len); +void target_add_flash(target *t, struct target_flash *f); +int target_flash_write_buffered(struct target_flash *f, + target_addr dest, const void *src, size_t len); +int target_flash_done_buffered(struct target_flash *f); + +/* Convenience function for MMIO access */ +uint32_t target_mem_read32(target *t, uint32_t addr); +uint16_t target_mem_read16(target *t, uint32_t addr); +uint8_t target_mem_read8(target *t, uint32_t addr); +void target_mem_write32(target *t, uint32_t addr, uint32_t value); +void target_mem_write16(target *t, uint32_t addr, uint16_t value); +void target_mem_write8(target *t, uint32_t addr, uint8_t value); +bool target_check_error(target *t); + +/* Access to host controller interface */ +void tc_printf(target *t, const char *fmt, ...); + +/* Interface to host system calls */ +int tc_open(target *, target_addr path, size_t plen, + enum target_open_flags flags, mode_t mode); +int tc_close(target *t, int fd); +int tc_read(target *t, int fd, target_addr buf, unsigned int count); +int tc_write(target *t, int fd, target_addr buf, unsigned int count); +long tc_lseek(target *t, int fd, long offset, + enum target_seek_flag flag); +int tc_rename(target *t, target_addr oldpath, size_t oldlen, + target_addr newpath, size_t newlen); +int tc_unlink(target *t, target_addr path, size_t plen); +int tc_stat(target *t, target_addr path, size_t plen, target_addr buf); +int tc_fstat(target *t, int fd, target_addr buf); +int tc_gettimeofday(target *t, target_addr tv, target_addr tz); +int tc_isatty(target *t, int fd); +int tc_system(target *t, target_addr cmd, size_t cmdlen); + +/* Probe for various targets. + * Actual functions implemented in their respective drivers. + */ +bool stm32f1_probe(target *t); +bool stm32f4_probe(target *t); +bool stm32l0_probe(target *t); +bool stm32l1_probe(target *t); +bool stm32l4_probe(target *t); +bool lmi_probe(target *t); +bool lpc11xx_probe(target *t); +bool lpc15xx_probe(target *t); +bool lpc43xx_probe(target *t); +bool sam3x_probe(target *t); +bool nrf51_probe(target *t); +bool samd_probe(target *t); +bool kinetis_probe(target *t); +bool efm32_probe(target *t); + +#endif +