diff --git a/src/platforms/common/cdcacm.c b/src/platforms/common/cdcacm.c index 2ba76bfd..3b213b11 100644 --- a/src/platforms/common/cdcacm.c +++ b/src/platforms/common/cdcacm.c @@ -58,7 +58,7 @@ static const struct usb_device_descriptor dev = { .bDeviceClass = 0xEF, /* Miscellaneous Device */ .bDeviceSubClass = 2, /* Common Class */ .bDeviceProtocol = 1, /* Interface Association */ - .bMaxPacketSize0 = 64, + .bMaxPacketSize0 = 8, .idVendor = 0x1D50, .idProduct = 0x6018, .bcdDevice = 0x0100, diff --git a/src/platforms/common/timing.c b/src/platforms/common/timing.c index 9087ba74..1717bf5a 100644 --- a/src/platforms/common/timing.c +++ b/src/platforms/common/timing.c @@ -26,6 +26,5 @@ void platform_timeout_set(platform_timeout *t, uint32_t ms) bool platform_timeout_is_expired(platform_timeout *t) { - return platform_time_ms() > t->time; + return platform_time_ms() >= t->time; } - diff --git a/src/target/adiv5.c b/src/target/adiv5.c index 7cccffa6..778cd0c1 100644 --- a/src/target/adiv5.c +++ b/src/target/adiv5.c @@ -422,7 +422,6 @@ ADIv5_AP_t *adiv5_new_ap(ADIv5_DP_t *dp, uint8_t apsel) memcpy(ap, &tmpap, sizeof(*ap)); adiv5_dp_ref(dp); - ap->cfg = adiv5_ap_read(ap, ADIV5_AP_CFG); ap->base = adiv5_ap_read(ap, ADIV5_AP_BASE); ap->csw = adiv5_ap_read(ap, ADIV5_AP_CSW) & ~(ADIV5_AP_CSW_SIZE_MASK | ADIV5_AP_CSW_ADDRINC_MASK); @@ -432,8 +431,11 @@ ADIv5_AP_t *adiv5_new_ap(ADIv5_DP_t *dp, uint8_t apsel) ap->csw &= ~ADIV5_AP_CSW_TRINPROG; } +#if defined(ENABLE_DEBUG) + uint32_t cfg = adiv5_ap_read(ap, ADIV5_AP_CFG); DEBUG("AP %3d: IDR=%08"PRIx32" CFG=%08"PRIx32" BASE=%08"PRIx32" CSW=%08"PRIx32"\n", - apsel, ap->idr, ap->cfg, ap->base, ap->csw); + apsel, ap->idr, cfg, ap->base, ap->csw); +#endif return ap; } @@ -490,8 +492,8 @@ void adiv5_dp_init(ADIv5_DP_t *dp) ); DEBUG("RESET_SEQ %s\n", (platform_timeout_is_expired(&timeout)) ? "failed": "succeeded"); - dp->dp_idcode = adiv5_dp_read(dp, ADIV5_DP_IDCODE); - if ((dp->dp_idcode & ADIV5_DP_VERSION_MASK) == ADIV5_DPv2) { + uint32_t dp_idcode = adiv5_dp_read(dp, ADIV5_DP_IDCODE); + if ((dp_idcode & ADIV5_DP_VERSION_MASK) == ADIV5_DPv2) { /* Read TargetID. Can be done with device in WFI, sleep or reset!*/ adiv5_dp_write(dp, ADIV5_DP_SELECT, ADIV5_DP_BANK2); dp->targetid = adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT); diff --git a/src/target/adiv5.h b/src/target/adiv5.h index 60d89333..c72a7a42 100644 --- a/src/target/adiv5.h +++ b/src/target/adiv5.h @@ -134,7 +134,6 @@ typedef struct ADIv5_DP_s { int refcnt; uint32_t idcode; - uint32_t dp_idcode; /* Contains DPvX revision*/ uint32_t targetid; /* Contains IDCODE for DPv2 devices.*/ uint32_t (*dp_read)(struct ADIv5_DP_s *dp, uint16_t addr); @@ -177,7 +176,6 @@ typedef struct ADIv5_AP_s { uint8_t apsel; uint32_t idr; - uint32_t cfg; uint32_t base; uint32_t csw; } ADIv5_AP_t; diff --git a/src/target/cortexm.c b/src/target/cortexm.c index 4e47a23b..6f273799 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -26,6 +26,7 @@ * * Also supports Cortex-M0 / ARMv6-M */ + #include "general.h" #include "exception.h" #include "adiv5.h" @@ -37,6 +38,23 @@ #include +#ifdef PC_HOSTED + +/* + * pc-hosted semihosting does keyboard, file and screen i/o on the system + * where blackmagic_hosted runs, using linux system calls. + * semihosting in the probe does keyboard, file and screen i/o on the system + * where gdb runs, using gdb file i/o calls. + */ + +#define TARGET_NULL ((target_addr)0) +#include +#include +#include +#include +#include +#endif + static const char cortexm_driver_str[] = "ARM Cortex-M"; static bool cortexm_vector_catch(target *t, int argc, char *argv[]); @@ -71,9 +89,7 @@ static target_addr cortexm_check_watch(target *t); static int cortexm_hostio_request(target *t); -#if !defined(PC_HOSTED) static uint32_t time0_sec = UINT32_MAX; /* sys_clock time origin */ -#endif struct cortexm_priv { ADIv5_AP_t *ap; @@ -1013,6 +1029,17 @@ static bool cortexm_vector_catch(target *t, int argc, char *argv[]) #endif /* Semihosting support */ + +/* + * If the target wants to read the special filename ":semihosting-features" + * to know what semihosting features are supported, it's easiest to create + * that file on the host in the directory where gdb runs, + * or, if using pc-hosted, where blackmagic_hosted runs. + * + * $ echo -e 'SHFB\x03' > ":semihosting-features" + * $ chmod 0444 ":semihosting-features" + */ + /* ARM Semihosting syscall numbers, from "Semihosting for AArch32 and AArch64 Version 3.0" */ #define SYS_CLOCK 0x10 @@ -1062,6 +1089,7 @@ static void probe_mem_write(target *t __attribute__((unused)), target_addr targe return; } #endif + static int cortexm_hostio_request(target *t) { uint32_t arm_regs[t->regs_size]; @@ -1076,6 +1104,227 @@ static int cortexm_hostio_request(target *t) DEBUG("syscall 0"PRIx32"%"PRIx32" (%"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32")\n", syscall, params[0], params[1], params[2], params[3]); switch (syscall) { +#if defined(PC_HOSTED) + + /* code that runs in pc-hosted process. use linux system calls. */ + + case SYS_OPEN:{ /* open */ + target_addr fnam_taddr = params[0]; + uint32_t fnam_len = params[2]; + ret = -1; + if ((fnam_taddr == TARGET_NULL) || (fnam_len == 0)) break; + + /* Translate stupid fopen modes to open flags. + * See DUI0471C, Table 8-3 */ + const uint32_t flags[] = { + O_RDONLY, /* r, rb */ + O_RDWR, /* r+, r+b */ + O_WRONLY | O_CREAT | O_TRUNC,/*w*/ + O_RDWR | O_CREAT | O_TRUNC,/*w+*/ + O_WRONLY | O_CREAT | O_APPEND,/*a*/ + O_RDWR | O_CREAT | O_APPEND,/*a+*/ + }; + uint32_t pflag = flags[params[1] >> 1]; + char filename[4]; + + target_mem_read(t, filename, fnam_taddr, sizeof(filename)); + /* handle requests for console i/o */ + if (!strcmp(filename, ":tt")) { + if (pflag == TARGET_O_RDONLY) + ret = STDIN_FILENO; + else if (pflag & TARGET_O_TRUNC) + ret = STDOUT_FILENO; + else + ret = STDERR_FILENO; + ret++; + break; + } + + char *fnam = malloc(fnam_len + 1); + if (fnam == NULL) break; + target_mem_read(t, fnam, fnam_taddr, fnam_len + 1); + if (target_check_error(t)) {free(fnam); break;} + fnam[fnam_len]='\0'; + ret = open(fnam, pflag, 0644); + free(fnam); + if (ret != -1) + ret++; + break; + } + + case SYS_CLOSE: /* close */ + ret = close(params[0] - 1); + break; + + case SYS_READ: { /* read */ + ret = -1; + target_addr buf_taddr = params[1]; + uint32_t buf_len = params[2]; + if (buf_taddr == TARGET_NULL) break; + if (buf_len == 0) {ret = 0; break;} + uint8_t *buf = malloc(buf_len); + if (buf == NULL) break; + ssize_t rc = read(params[0] - 1, buf, buf_len); + if (rc >= 0) + rc = buf_len - rc; + target_mem_write(t, buf_taddr, buf, buf_len); + free(buf); + if (target_check_error(t)) break; + ret = rc; + break; + } + + case SYS_WRITE: { /* write */ + ret = -1; + target_addr buf_taddr = params[1]; + uint32_t buf_len = params[2]; + if (buf_taddr == TARGET_NULL) break; + if (buf_len == 0) {ret = 0; break;} + uint8_t *buf = malloc(buf_len); + if (buf == NULL) break; + target_mem_read(t, buf, buf_taddr, buf_len); + if (target_check_error(t)) {free(buf); break;} + ret = write(params[0] - 1, buf, buf_len); + free(buf); + if (ret >= 0) + ret = buf_len - ret; + break; + } + + case SYS_WRITEC: { /* writec */ + ret = -1; + uint8_t ch; + target_addr ch_taddr = arm_regs[1]; + if (ch_taddr == TARGET_NULL) break; + ch = target_mem_read8(t, ch_taddr); + if (target_check_error(t)) break; + fputc(ch, stderr); + ret = 0; + break; + } + + case SYS_WRITE0:{ /* write0 */ + ret = -1; + uint8_t ch; + target_addr str = arm_regs[1]; + if (str == TARGET_NULL) break; + while ((ch = target_mem_read8(t, str++)) != '\0') { + if (target_check_error(t)) break; + fputc(ch, stderr); + } + ret = 0; + break; + } + + case SYS_ISTTY: /* isatty */ + ret = isatty(params[0] - 1); + break; + + case SYS_SEEK:{ /* lseek */ + off_t pos = params[1]; + if (lseek(params[0] - 1, pos, SEEK_SET) == (off_t)pos) ret = 0; + else ret = -1; + break; + } + + case SYS_RENAME: { /* rename */ + ret = -1; + target_addr fnam1_taddr = params[0]; + uint32_t fnam1_len = params[1]; + if (fnam1_taddr == TARGET_NULL) break; + if (fnam1_len == 0) break; + target_addr fnam2_taddr = params[2]; + uint32_t fnam2_len = params[3]; + if (fnam2_taddr == TARGET_NULL) break; + if (fnam2_len == 0) break; + char *fnam1 = malloc(fnam1_len + 1); + if (fnam1 == NULL) break; + target_mem_read(t, fnam1, fnam1_taddr, fnam1_len + 1); + if (target_check_error(t)) {free(fnam1); break;} + fnam1[fnam1_len]='\0'; + char *fnam2 = malloc(fnam2_len + 1); + if (fnam2 == NULL) {free(fnam1); break;} + target_mem_read(t, fnam2, fnam2_taddr, fnam2_len + 1); + if (target_check_error(t)) {free(fnam1); free(fnam2); break;} + fnam2[fnam2_len]='\0'; + ret = rename(fnam1, fnam2); + free(fnam1); + free(fnam2); + break; + } + + case SYS_REMOVE: { /* unlink */ + ret = -1; + target_addr fnam_taddr = params[0]; + if (fnam_taddr == TARGET_NULL) break; + uint32_t fnam_len = params[1]; + if (fnam_len == 0) break; + char *fnam = malloc(fnam_len + 1); + if (fnam == NULL) break; + target_mem_read(t, fnam, fnam_taddr, fnam_len + 1); + if (target_check_error(t)) {free(fnam); break;} + fnam[fnam_len]='\0'; + ret = remove(fnam); + free(fnam); + break; + } + + case SYS_SYSTEM: { /* system */ + ret = -1; + target_addr cmd_taddr = params[0]; + if (cmd_taddr == TARGET_NULL) break; + uint32_t cmd_len = params[1]; + if (cmd_len == 0) break; + char *cmd = malloc(cmd_len + 1); + if (cmd == NULL) break; + target_mem_read(t, cmd, cmd_taddr, cmd_len + 1); + if (target_check_error(t)) {free(cmd); break;} + cmd[cmd_len]='\0'; + ret = system(cmd); + free(cmd); + break; + } + + case SYS_FLEN: { /* file length */ + ret = -1; + struct stat stat_buf; + if (fstat(params[0]-1, &stat_buf) != 0) break; + if (stat_buf.st_size > INT32_MAX) break; + ret = stat_buf.st_size; + break; + } + + case SYS_CLOCK: { /* clock */ + /* can't use clock() because that would give cpu time of pc-hosted process */ + ret = -1; + struct timeval timeval_buf; + if(gettimeofday(&timeval_buf, NULL) != 0) break; + uint32_t sec = timeval_buf.tv_sec; + uint64_t usec = timeval_buf.tv_usec; + if (time0_sec > sec) time0_sec = sec; + sec -= time0_sec; + uint64_t csec64 = (sec * 1000000ull + usec)/10000ull; + uint32_t csec = csec64 & 0x7fffffff; + ret = csec; + break; + } + + case SYS_TIME: /* time */ + ret = time(NULL); + break; + + case SYS_READC: /* readc */ + ret = getchar(); + break; + + case SYS_ERRNO: /* errno */ + ret = errno; + break; + +#else + + /* code that runs in probe. use gdb fileio calls. */ + case SYS_OPEN:{ /* open */ /* Translate stupid fopen modes to open flags. * See DUI0471C, Table 8-3 */ @@ -1102,13 +1351,13 @@ static int cortexm_hostio_request(target *t) ret++; break; } - /* FIXME handle requests for special filename ':semihosting-features' */ ret = tc_open(t, params[0], params[2] + 1, pflag, 0644); if (ret != -1) ret++; break; } + case SYS_CLOSE: /* close */ ret = tc_close(t, params[0] - 1); break; @@ -1161,10 +1410,6 @@ static int cortexm_hostio_request(target *t) break; case SYS_FLEN: -#if defined(PC_HOSTED) - t->tc->errno_ = 0; - break; -#else { /* file length */ ret = -1; uint32_t fio_stat[16]; /* same size as fio_stat in gdb/include/gdb/fileio.h */ @@ -1181,8 +1426,9 @@ static int cortexm_hostio_request(target *t) if (rc) break; /* tc_fstat() failed */ uint32_t fst_size_msw = fio_stat[7]; /* most significant 32 bits of fst_size in fio_stat */ uint32_t fst_size_lsw = fio_stat[8]; /* least significant 32 bits of fst_size in fio_stat */ - if (fst_size_msw != 0) break; /* file size too large for uint32_t return type */ + if (fst_size_msw != 0) break; /* file size too large for int32_t return type */ ret = __builtin_bswap32(fst_size_lsw); /* convert from bigendian to target order */ + if (ret < 0) ret = -1; /* file size too large for int32_t return type */ break; } @@ -1235,10 +1481,11 @@ static int cortexm_hostio_request(target *t) else ret = -1; break; } -#endif + case SYS_ERRNO: /* Return last errno from GDB */ ret = t->tc->errno_; break; +#endif case SYS_EXIT: /* _exit() */ tc_printf(t, "_exit(0x%x)\n", params[0]); @@ -1296,8 +1543,7 @@ static int cortexm_hostio_request(target *t) break; case SYS_TMPNAM: { /* tmpnam */ - /* Given a target identifier between 0 and 255, returns a temporary name. - * FIXME: add directory prefix */ + /* Given a target identifier between 0 and 255, returns a temporary name */ target_addr buf_ptr = params[0]; int target_id = params[1]; int buf_size = params[2]; diff --git a/src/target/lpc11xx.c b/src/target/lpc11xx.c index f93130ef..02c631db 100644 --- a/src/target/lpc11xx.c +++ b/src/target/lpc11xx.c @@ -129,6 +129,12 @@ lpc11xx_probe(target *t) target_add_ram(t, 0x10000000, 0x2000); lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x1000); return true; + case 0x00008A04: /* LPC8N04 (see UM11074 Rev.1.3 section 4.5.19) */ + t->driver = "LPC8N04"; + target_add_ram(t, 0x10000000, 0x2000); + lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400); + target_add_commands(t, lpc11xx_cmd_list, "LPC8N04"); + return true; } if (idcode) { DEBUG("LPC11xx: Unknown IDCODE 0x%08" PRIx32 "\n", idcode); diff --git a/src/target/stm32l4.c b/src/target/stm32l4.c index 63e1e8d8..bee108c5 100644 --- a/src/target/stm32l4.c +++ b/src/target/stm32l4.c @@ -326,13 +326,22 @@ static bool stm32l4_attach(target *t) } else stm32l4_add_flash(t, 0x08000000, 0x00200000, 0x2000, -1); } else if (chip->family == FAM_STM32G4xx) { - if (options & OR_DBANK) { - uint32_t banksize = size << 9; - stm32l4_add_flash(t, 0x08000000 , banksize, 0x0800, 0x08000000 + banksize); - stm32l4_add_flash(t, 0x08000000 + banksize, banksize, 0x0800, 0x08000000 + banksize); - } else { + // RM0440 describes G43x as Category 2, G47x/G48x as Category 3 devices + // Cat 2 is always 128k with 2k pages, single bank + // Cat 3 is dual bank with an option bit to choose single 512k bank with 4k pages or dual bank as 2x256k with 2k pages + if (chip->idcode == ID_STM32G43) { uint32_t banksize = size << 10; - stm32l4_add_flash(t, 0x08000000 , banksize, 0x1000, -1); + stm32l4_add_flash(t, 0x08000000, banksize, 0x0800, -1); + } + else { + if (options & OR_DBANK) { + uint32_t banksize = size << 9; + stm32l4_add_flash(t, 0x08000000 , banksize, 0x0800, 0x08000000 + banksize); + stm32l4_add_flash(t, 0x08000000 + banksize, banksize, 0x0800, 0x08000000 + banksize); + } else { + uint32_t banksize = size << 10; + stm32l4_add_flash(t, 0x08000000 , banksize, 0x1000, -1); + } } } else if (chip->flags & DUAL_BANK) { if (options & OR_DUALBANK) {