diff options
Diffstat (limited to 'src')
98 files changed, 2274 insertions, 1215 deletions
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 147807f..7a81b28 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -59,7 +59,7 @@ NOR_DRIVERS = \ %D%/psoc6.c \ %D%/qn908x.c \ %D%/renesas_rpchf.c \ - %D%/rp2040.c \ + %D%/rp2xxx.c \ %D%/rsl10.c \ %D%/sfdp.c \ %D%/sh_qspi.c \ diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h index 794566f..3b57ef9 100644 --- a/src/flash/nor/driver.h +++ b/src/flash/nor/driver.h @@ -289,7 +289,7 @@ extern const struct flash_driver psoc5lp_nvl_flash; extern const struct flash_driver psoc6_flash; extern const struct flash_driver qn908x_flash; extern const struct flash_driver renesas_rpchf_flash; -extern const struct flash_driver rp2040_flash; +extern const struct flash_driver rp2xxx_flash; extern const struct flash_driver rsl10_flash; extern const struct flash_driver sh_qspi_flash; extern const struct flash_driver sim3x_flash; diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 67d8624..3770bfb 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -66,7 +66,7 @@ static const struct flash_driver * const flash_drivers[] = { &psoc6_flash, &qn908x_flash, &renesas_rpchf_flash, - &rp2040_flash, + &rp2xxx_flash, &sh_qspi_flash, &sim3x_flash, &stellaris_flash, diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c deleted file mode 100644 index b2ebd9c..0000000 --- a/src/flash/nor/rp2040.c +++ /dev/null @@ -1,533 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "imp.h" -#include <helper/binarybuffer.h> -#include <target/algorithm.h> -#include <target/armv7m.h> -#include "spi.h" - -/* NOTE THAT THIS CODE REQUIRES FLASH ROUTINES in BOOTROM WITH FUNCTION TABLE PTR AT 0x00000010 - Your gdbinit should load the bootrom.elf if appropriate */ - -/* this is 'M' 'u', 1 (version) */ -#define BOOTROM_MAGIC 0x01754d -#define BOOTROM_MAGIC_ADDR 0x00000010 - -/* Call a ROM function via the debug trampoline - Up to four arguments passed in r0...r3 as per ABI - Function address is passed in r7 - the trampoline is needed because OpenOCD "algorithm" code insists on sw breakpoints. */ - -#define MAKE_TAG(a, b) (((b)<<8) | a) -#define FUNC_DEBUG_TRAMPOLINE MAKE_TAG('D', 'T') -#define FUNC_DEBUG_TRAMPOLINE_END MAKE_TAG('D', 'E') -#define FUNC_FLASH_EXIT_XIP MAKE_TAG('E', 'X') -#define FUNC_CONNECT_INTERNAL_FLASH MAKE_TAG('I', 'F') -#define FUNC_FLASH_RANGE_ERASE MAKE_TAG('R', 'E') -#define FUNC_FLASH_RANGE_PROGRAM MAKE_TAG('R', 'P') -#define FUNC_FLASH_FLUSH_CACHE MAKE_TAG('F', 'C') -#define FUNC_FLASH_ENTER_CMD_XIP MAKE_TAG('C', 'X') - -struct rp2040_flash_bank { - /* flag indicating successful flash probe */ - bool probed; - /* stack used by Boot ROM calls */ - struct working_area *stack; - /* function jump table populated by rp2040_flash_probe() */ - uint16_t jump_debug_trampoline; - uint16_t jump_debug_trampoline_end; - uint16_t jump_flash_exit_xip; - uint16_t jump_connect_internal_flash; - uint16_t jump_flash_range_erase; - uint16_t jump_flash_range_program; - uint16_t jump_flush_cache; - uint16_t jump_enter_cmd_xip; - /* detected model of SPI flash */ - const struct flash_device *dev; -}; - -/* guessed SPI flash description if autodetection disabled (same as win w25q16jv) */ -static const struct flash_device rp2040_default_spi_device = - FLASH_ID("autodetect disabled", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0, 0x100, 0x10000, 0); - -static uint32_t rp2040_lookup_symbol(struct target *target, uint32_t tag, uint16_t *symbol) -{ - uint32_t magic; - int err = target_read_u32(target, BOOTROM_MAGIC_ADDR, &magic); - if (err != ERROR_OK) - return err; - - magic &= 0xffffff; /* ignore bootrom version */ - if (magic != BOOTROM_MAGIC) { - if (!((magic ^ BOOTROM_MAGIC)&0xffff)) - LOG_ERROR("Incorrect RP2040 BOOT ROM version"); - else - LOG_ERROR("RP2040 BOOT ROM not found"); - return ERROR_FAIL; - } - - /* dereference the table pointer */ - uint16_t table_entry; - err = target_read_u16(target, BOOTROM_MAGIC_ADDR + 4, &table_entry); - if (err != ERROR_OK) - return err; - - uint16_t entry_tag; - do { - err = target_read_u16(target, table_entry, &entry_tag); - if (err != ERROR_OK) - return err; - if (entry_tag == tag) { - /* 16 bit symbol is next */ - return target_read_u16(target, table_entry + 2, symbol); - } - table_entry += 4; - } while (entry_tag); - return ERROR_FAIL; -} - -static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank *priv, - uint16_t func_offset, uint32_t argdata[], unsigned int n_args, unsigned int timeout_ms) -{ - char *regnames[4] = { "r0", "r1", "r2", "r3" }; - - assert(n_args <= ARRAY_SIZE(regnames)); /* only allow register arguments */ - - if (!priv->stack) { - LOG_ERROR("no stack for flash programming code"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - target_addr_t stacktop = priv->stack->address + priv->stack->size; - - LOG_TARGET_DEBUG(target, "Calling ROM func @0x%" PRIx16 " with %u arguments", func_offset, n_args); - - struct reg_param args[ARRAY_SIZE(regnames) + 2]; - struct armv7m_algorithm alg_info; - - for (unsigned int i = 0; i < n_args; ++i) { - init_reg_param(&args[i], regnames[i], 32, PARAM_OUT); - buf_set_u32(args[i].value, 0, 32, argdata[i]); - } - /* Pass function pointer in r7 */ - init_reg_param(&args[n_args], "r7", 32, PARAM_OUT); - buf_set_u32(args[n_args].value, 0, 32, func_offset); - /* Setup stack */ - init_reg_param(&args[n_args + 1], "sp", 32, PARAM_OUT); - buf_set_u32(args[n_args + 1].value, 0, 32, stacktop); - unsigned int n_reg_params = n_args + 2; /* User arguments + r7 + sp */ - - for (unsigned int i = 0; i < n_reg_params; ++i) - LOG_DEBUG("Set %s = 0x%" PRIx32, args[i].reg_name, buf_get_u32(args[i].value, 0, 32)); - - /* Actually call the function */ - alg_info.common_magic = ARMV7M_COMMON_MAGIC; - alg_info.core_mode = ARM_MODE_THREAD; - int err = target_run_algorithm( - target, - 0, NULL, /* No memory arguments */ - n_reg_params, args, /* User arguments + r7 + sp */ - priv->jump_debug_trampoline, priv->jump_debug_trampoline_end, - timeout_ms, - &alg_info - ); - - for (unsigned int i = 0; i < n_reg_params; ++i) - destroy_reg_param(&args[i]); - - if (err != ERROR_OK) - LOG_ERROR("Failed to invoke ROM function @0x%" PRIx16, func_offset); - - return err; -} - -/* Finalize flash write/erase/read ID - * - flush cache - * - enters memory-mapped (XIP) mode to make flash data visible - * - deallocates target ROM func stack if previously allocated - */ -static int rp2040_finalize_stack_free(struct flash_bank *bank) -{ - struct rp2040_flash_bank *priv = bank->driver_priv; - struct target *target = bank->target; - - /* Always flush before returning to execute-in-place, to invalidate stale - * cache contents. The flush call also restores regular hardware-controlled - * chip select following a rp2040_flash_exit_xip(). - */ - LOG_DEBUG("Flushing flash cache after write behind"); - int err = rp2040_call_rom_func(target, priv, priv->jump_flush_cache, NULL, 0, 1000); - if (err != ERROR_OK) { - LOG_ERROR("Failed to flush flash cache"); - /* Intentionally continue after error and try to setup xip anyway */ - } - - LOG_DEBUG("Configuring SSI for execute-in-place"); - err = rp2040_call_rom_func(target, priv, priv->jump_enter_cmd_xip, NULL, 0, 1000); - if (err != ERROR_OK) - LOG_ERROR("Failed to set SSI to XIP mode"); - - target_free_working_area(target, priv->stack); - priv->stack = NULL; - return err; -} - -/* Prepare flash write/erase/read ID - * - allocates a stack for target ROM func - * - switches the SPI interface from memory-mapped mode to direct command mode - * Always pair with a call of rp2040_finalize_stack_free() - * after flash operation finishes or fails. - */ -static int rp2040_stack_grab_and_prep(struct flash_bank *bank) -{ - struct rp2040_flash_bank *priv = bank->driver_priv; - struct target *target = bank->target; - - /* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */ - const int STACK_SIZE = 256; - int err = target_alloc_working_area(target, STACK_SIZE, &priv->stack); - if (err != ERROR_OK) { - LOG_ERROR("Could not allocate stack for flash programming code"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - LOG_DEBUG("Connecting internal flash"); - err = rp2040_call_rom_func(target, priv, priv->jump_connect_internal_flash, NULL, 0, 1000); - if (err != ERROR_OK) { - LOG_ERROR("Failed to connect internal flash"); - return err; - } - - LOG_DEBUG("Kicking flash out of XIP mode"); - err = rp2040_call_rom_func(target, priv, priv->jump_flash_exit_xip, NULL, 0, 1000); - if (err != ERROR_OK) { - LOG_ERROR("Failed to exit flash XIP mode"); - return err; - } - - return ERROR_OK; -} - -static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) -{ - LOG_DEBUG("Writing %d bytes starting at 0x%" PRIx32, count, offset); - - struct rp2040_flash_bank *priv = bank->driver_priv; - struct target *target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - struct working_area *bounce = NULL; - - int err = rp2040_stack_grab_and_prep(bank); - if (err != ERROR_OK) - goto cleanup; - - unsigned int avail_pages = target_get_working_area_avail(target) / priv->dev->pagesize; - /* We try to allocate working area rounded down to device page size, - * al least 1 page, at most the write data size - */ - unsigned int chunk_size = MIN(MAX(avail_pages, 1) * priv->dev->pagesize, count); - err = target_alloc_working_area(target, chunk_size, &bounce); - if (err != ERROR_OK) { - LOG_ERROR("Could not allocate bounce buffer for flash programming. Can't continue"); - goto cleanup; - } - - LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, bounce->address); - - while (count > 0) { - uint32_t write_size = count > chunk_size ? chunk_size : count; - LOG_DEBUG("Writing %d bytes to offset 0x%" PRIx32, write_size, offset); - err = target_write_buffer(target, bounce->address, write_size, buffer); - if (err != ERROR_OK) { - LOG_ERROR("Could not load data into target bounce buffer"); - break; - } - uint32_t args[3] = { - offset, /* addr */ - bounce->address, /* data */ - write_size /* count */ - }; - err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_program, - args, ARRAY_SIZE(args), 3000); - if (err != ERROR_OK) { - LOG_ERROR("Failed to invoke flash programming code on target"); - break; - } - - buffer += write_size; - offset += write_size; - count -= write_size; - } - -cleanup: - target_free_working_area(target, bounce); - - rp2040_finalize_stack_free(bank); - - return err; -} - -static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last) -{ - struct rp2040_flash_bank *priv = bank->driver_priv; - struct target *target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - uint32_t start_addr = bank->sectors[first].offset; - uint32_t length = bank->sectors[last].offset + bank->sectors[last].size - start_addr; - LOG_DEBUG("RP2040 erase %d bytes starting at 0x%" PRIx32, length, start_addr); - - int err = rp2040_stack_grab_and_prep(bank); - if (err != ERROR_OK) - goto cleanup; - - LOG_DEBUG("Remote call flash_range_erase"); - - uint32_t args[4] = { - bank->sectors[first].offset, /* addr */ - bank->sectors[last].offset + bank->sectors[last].size - bank->sectors[first].offset, /* count */ - priv->dev->sectorsize, /* block_size */ - priv->dev->erase_cmd /* block_cmd */ - }; - - /* - The RP2040 Boot ROM provides a _flash_range_erase() API call documented in Section 2.8.3.1.3: - https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf - and the particular source code for said Boot ROM function can be found here: - https://github.com/raspberrypi/pico-bootrom/blob/master/bootrom/program_flash_generic.c - - In theory, the function algorithm provides for erasing both a smaller "sector" (4096 bytes) and - an optional larger "block" (size and command provided in args). - */ - - unsigned int timeout_ms = 2000 * (last - first) + 1000; - err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_erase, - args, ARRAY_SIZE(args), timeout_ms); - -cleanup: - rp2040_finalize_stack_free(bank); - - return err; -} - -/* ----------------------------------------------------------------------------- - Driver probing etc */ - -static int rp2040_ssel_active(struct target *target, bool active) -{ - const target_addr_t qspi_ctrl_addr = 0x4001800c; - const uint32_t qspi_ctrl_outover_low = 2UL << 8; - const uint32_t qspi_ctrl_outover_high = 3UL << 8; - uint32_t state = (active) ? qspi_ctrl_outover_low : qspi_ctrl_outover_high; - uint32_t val; - - int err = target_read_u32(target, qspi_ctrl_addr, &val); - if (err != ERROR_OK) - return err; - - val = (val & ~qspi_ctrl_outover_high) | state; - - err = target_write_u32(target, qspi_ctrl_addr, val); - if (err != ERROR_OK) - return err; - - return ERROR_OK; -} - -static int rp2040_spi_read_flash_id(struct target *target, uint32_t *devid) -{ - uint32_t device_id = 0; - const target_addr_t ssi_dr0 = 0x18000060; - - int err = rp2040_ssel_active(target, true); - - /* write RDID request into SPI peripheral's FIFO */ - for (int count = 0; (count < 4) && (err == ERROR_OK); count++) - err = target_write_u32(target, ssi_dr0, SPIFLASH_READ_ID); - - /* by this time, there is a receive FIFO entry for every write */ - for (int count = 0; (count < 4) && (err == ERROR_OK); count++) { - uint32_t status; - err = target_read_u32(target, ssi_dr0, &status); - - device_id >>= 8; - device_id |= (status & 0xFF) << 24; - } - - if (err == ERROR_OK) - *devid = device_id >> 8; - - int err2 = rp2040_ssel_active(target, false); - if (err2 != ERROR_OK) - LOG_ERROR("SSEL inactive failed"); - - return err; -} - -static int rp2040_flash_probe(struct flash_bank *bank) -{ - struct rp2040_flash_bank *priv = bank->driver_priv; - struct target *target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - int err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE, &priv->jump_debug_trampoline); - if (err != ERROR_OK) { - LOG_ERROR("Debug trampoline not found in RP2040 ROM."); - return err; - } - priv->jump_debug_trampoline &= ~1u; /* mask off thumb bit */ - - err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE_END, &priv->jump_debug_trampoline_end); - if (err != ERROR_OK) { - LOG_ERROR("Debug trampoline end not found in RP2040 ROM."); - return err; - } - priv->jump_debug_trampoline_end &= ~1u; /* mask off thumb bit */ - - err = rp2040_lookup_symbol(target, FUNC_FLASH_EXIT_XIP, &priv->jump_flash_exit_xip); - if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_FLASH_EXIT_XIP not found in RP2040 ROM."); - return err; - } - - err = rp2040_lookup_symbol(target, FUNC_CONNECT_INTERNAL_FLASH, &priv->jump_connect_internal_flash); - if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_CONNECT_INTERNAL_FLASH not found in RP2040 ROM."); - return err; - } - - err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_ERASE, &priv->jump_flash_range_erase); - if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_FLASH_RANGE_ERASE not found in RP2040 ROM."); - return err; - } - - err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_PROGRAM, &priv->jump_flash_range_program); - if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_FLASH_RANGE_PROGRAM not found in RP2040 ROM."); - return err; - } - - err = rp2040_lookup_symbol(target, FUNC_FLASH_FLUSH_CACHE, &priv->jump_flush_cache); - if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_FLASH_FLUSH_CACHE not found in RP2040 ROM."); - return err; - } - - err = rp2040_lookup_symbol(target, FUNC_FLASH_ENTER_CMD_XIP, &priv->jump_enter_cmd_xip); - if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_FLASH_ENTER_CMD_XIP not found in RP2040 ROM."); - return err; - } - - if (bank->size) { - /* size overridden, suppress reading SPI flash ID */ - priv->dev = &rp2040_default_spi_device; - LOG_DEBUG("SPI flash autodetection disabled, using configured size"); - - } else { - /* zero bank size in cfg, read SPI flash ID and autodetect */ - err = rp2040_stack_grab_and_prep(bank); - - uint32_t device_id = 0; - if (err == ERROR_OK) - err = rp2040_spi_read_flash_id(target, &device_id); - - rp2040_finalize_stack_free(bank); - - if (err != ERROR_OK) - return err; - - /* search for a SPI flash Device ID match */ - priv->dev = NULL; - for (const struct flash_device *p = flash_devices; p->name ; p++) - if (p->device_id == device_id) { - priv->dev = p; - break; - } - - if (!priv->dev) { - LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", device_id); - return ERROR_FAIL; - } - LOG_INFO("Found flash device '%s' (ID 0x%08" PRIx32 ")", - priv->dev->name, priv->dev->device_id); - - bank->size = priv->dev->size_in_bytes; - } - - /* the Boot ROM flash_range_program() routine requires page alignment */ - bank->write_start_alignment = priv->dev->pagesize; - bank->write_end_alignment = priv->dev->pagesize; - - bank->num_sectors = bank->size / priv->dev->sectorsize; - LOG_INFO("RP2040 B0 Flash Probe: %" PRIu32 " bytes @" TARGET_ADDR_FMT ", in %u sectors\n", - bank->size, bank->base, bank->num_sectors); - bank->sectors = alloc_block_array(0, priv->dev->sectorsize, bank->num_sectors); - if (!bank->sectors) - return ERROR_FAIL; - - if (err == ERROR_OK) - priv->probed = true; - - return err; -} - -static int rp2040_flash_auto_probe(struct flash_bank *bank) -{ - struct rp2040_flash_bank *priv = bank->driver_priv; - - if (priv->probed) - return ERROR_OK; - - return rp2040_flash_probe(bank); -} - -static void rp2040_flash_free_driver_priv(struct flash_bank *bank) -{ - free(bank->driver_priv); - bank->driver_priv = NULL; -} - -/* ----------------------------------------------------------------------------- - Driver boilerplate */ - -FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command) -{ - struct rp2040_flash_bank *priv; - priv = malloc(sizeof(struct rp2040_flash_bank)); - priv->probed = false; - - /* Set up driver_priv */ - bank->driver_priv = priv; - - return ERROR_OK; -} - -const struct flash_driver rp2040_flash = { - .name = "rp2040_flash", - .flash_bank_command = rp2040_flash_bank_command, - .erase = rp2040_flash_erase, - .write = rp2040_flash_write, - .read = default_flash_read, - .probe = rp2040_flash_probe, - .auto_probe = rp2040_flash_auto_probe, - .erase_check = default_flash_blank_check, - .free_driver_priv = rp2040_flash_free_driver_priv -}; diff --git a/src/flash/nor/rp2xxx.c b/src/flash/nor/rp2xxx.c new file mode 100644 index 0000000..85c5911 --- /dev/null +++ b/src/flash/nor/rp2xxx.c @@ -0,0 +1,1442 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include <helper/binarybuffer.h> +#include <target/algorithm.h> +#include <target/armv7m.h> +#include "spi.h" +#include "sfdp.h" +#include <target/cortex_m.h> + +/* this is 'M' 'u', 1 (version) */ +#define BOOTROM_RP2040_MAGIC 0x01754d +/* this is 'M' 'u', 2 (version) */ +#define BOOTROM_RP2350_MAGIC 0x02754d +#define BOOTROM_MAGIC_MASK 0xffffff +#define BOOTROM_MAGIC_ADDR 0x00000010 + +#define MAKE_TAG(a, b) (((b)<<8) | a) +#define FUNC_FLASH_EXIT_XIP MAKE_TAG('E', 'X') +#define FUNC_CONNECT_INTERNAL_FLASH MAKE_TAG('I', 'F') +#define FUNC_FLASH_RANGE_ERASE MAKE_TAG('R', 'E') +#define FUNC_FLASH_RANGE_PROGRAM MAKE_TAG('R', 'P') +#define FUNC_FLASH_FLUSH_CACHE MAKE_TAG('F', 'C') +#define FUNC_FLASH_ENTER_CMD_XIP MAKE_TAG('C', 'X') +#define FUNC_BOOTROM_STATE_RESET MAKE_TAG('S', 'R') +#define FUNC_BOOTROM_SET_STACK MAKE_TAG('S', 'S') +#define FUNC_FLASH_RESET_ADDRESS_TRANS MAKE_TAG('R', 'A') + +/* ROM table flags for RP2350 A1 ROM onwards */ +#define RT_FLAG_FUNC_RISCV 0x01 +#define RT_FLAG_FUNC_ARM_SEC 0x04 +#define RT_FLAG_FUNC_ARM_NONSEC 0x10 +#define RT_FLAG_DATA 0x40 + +// these form a bit set +#define BOOTROM_STATE_RESET_CURRENT_CORE 0x01 +#define BOOTROM_STATE_RESET_OTHER_CORE 0x02 +#define BOOTROM_STATE_RESET_GLOBAL_STATE 0x04 + +#define ACCESSCTRL_LOCK_OFFSET 0x40060000u +#define ACCESSCTRL_LOCK_DEBUG_BITS 0x00000008u +#define ACCESSCTRL_CFGRESET_OFFSET 0x40060008u +#define ACCESSCTRL_WRITE_PASSWORD 0xacce0000u + +#define RP2040_SSI_DR0 0x18000060 +#define RP2040_QSPI_CTRL 0x4001800c + +#define RP2040_QSPI_CTRL_OUTOVER_MASK (3ul << 8) +#define RP2040_QSPI_CTRL_OUTOVER_LOW (2ul << 8) +#define RP2040_QSPI_CTRL_OUTOVER_HIGH (3ul << 8) + +#define RP2350_QMI_DIRECT_CSR 0x400d0000 +#define RP2350_QMI_DIRECT_TX 0x400d0004 +#define RP2350_QMI_DIRECT_RX 0x400d0008 + +#define RP2350_QMI_DIRECT_CSR_EN BIT(0) +#define RP2350_QMI_DIRECT_CSR_ASSERT_CS0N BIT(2) +#define RP2350_QMI_DIRECT_TX_NOPUSH BIT(20) +#define RP2350_QMI_DIRECT_TX_OE BIT(19) + +#define RP2XXX_SYSINFO_CHIP_ID 0x40000000 +#define RP2XXX_CHIP_ID_PART_MANUFACTURER(id) ((id) & 0x0fffffff) +#define RP2XXX_CHIP_ID_MANUFACTURER 0x493 +#define RP2XXX_MK_PART(part) (((part) << 12) | (RP2XXX_CHIP_ID_MANUFACTURER << 1) | 1) +#define RP2040_CHIP_ID_PART 0x0002 +#define IS_RP2040(id) (RP2XXX_CHIP_ID_PART_MANUFACTURER(id) == RP2XXX_MK_PART(RP2040_CHIP_ID_PART)) +#define RP2350_CHIP_ID_PART 0x0004 +#define IS_RP2350(id) (RP2XXX_CHIP_ID_PART_MANUFACTURER(id) == RP2XXX_MK_PART(RP2350_CHIP_ID_PART)) +#define RP2XXX_CHIP_ID_REVISION(id) ((id) >> 28) + +#define RP2XXX_MAX_ALGO_STACK_USAGE 1024 +#define RP2XXX_MAX_RAM_ALGO_SIZE 1024 + +#define RP2XXX_ROM_API_FIXED_FLASH_PAGE 256 +#define RP2XXX_ROM_API_FIXED_FLASH_SECTOR 4096 + +// Calling bootrom functions on Arm RP2350 requires the redundancy +// coprocessor (RCP) to be initialised. Usually this is done first thing by +// the bootrom, but the debugger may skip this, e.g. by resetting the cores +// and then running a NO_FLASH binary, or by reset-halting the cores before +// flash programming. +// +// The first case can be handled by a stub in the binary itself to initialise +// the RCP with dummy values if the bootrom has not already initialised it. +// (Note this case is only reachable via the debugger.) The second case +// requires the debugger itself to initialise the RCP, using this stub code: + +static const int rcp_init_code_bkpt_offset = 24; +static const uint8_t rcp_init_code[] = { + // Just enable the RCP which is fine if it already was (we assume no other + // co-processors are enabled at this point to save space) + 0x06, 0x48, // ldr r0, = PPB_BASE + M33_CPACR_OFFSET + 0x5f, 0xf4, 0x40, 0x41, // movs r1, #M33_CPACR_CP7_BITS + 0x01, 0x60, // str r1, [r0] + // Only initialize canary seeds if they haven't been (as to do so twice is a fault) + 0x30, 0xee, 0x10, 0xf7, // mrc p7, #1, r15, c0, c0, #0 + 0x04, 0xd4, // bmi 1f + // Todo should we use something random here and pass it into the algorithm? + 0x40, 0xec, 0x80, 0x07, // mcrr p7, #8, r0, r0, c0 + 0x40, 0xec, 0x81, 0x07, // mcrr p7, #8, r0, r0, c1 + // Let other core know + 0x40, 0xbf, // sev + // 1: + 0x00, 0xbe, // bkpt (end of algorithm) + 0x00, 0x00, // pad + 0x88, 0xed, 0x00, 0xe0 // PPB_BASE + M33_CPACR_OFFSET +}; + +// An algorithm stub that can be concatenated with a null-terminated list of +// (PC, SP, r0-r3) records to perform a batch of ROM calls under a single +// OpenOCD algorithm call, to save on algorithm overhead: +#define ROM_CALL_BATCH_ALGO_SIZE_BYTES 32 +static const int rp2xxx_rom_call_batch_algo_bkpt_offset = ROM_CALL_BATCH_ALGO_SIZE_BYTES - 2; +static const uint8_t rp2xxx_rom_call_batch_algo_armv6m[ROM_CALL_BATCH_ALGO_SIZE_BYTES] = { +// <_start>: + 0x07, 0xa7, // add r7, pc, #28 ; (adr r7, 20 <_args>) +// <_do_next>: + 0x10, 0xcf, // ldmia r7!, {r4} + 0x00, 0x2c, // cmp r4, #0 + 0x0a, 0xd0, // beq.n 1e <_done> + 0x20, 0xcf, // ldmia r7!, {r5} + 0xad, 0x46, // mov sp, r5 + 0x0f, 0xcf, // ldmia r7!, {r0, r1, r2, r3} + 0xa0, 0x47, // blx r4 + 0xf7, 0xe7, // b.n 2 <_do_next> + 0xc0, 0x46, // nop + 0xc0, 0x46, // nop + 0xc0, 0x46, // nop + 0xc0, 0x46, // nop + 0xc0, 0x46, // nop + 0xc0, 0x46, // nop +// <_done>: + 0x00, 0xbe, // bkpt 0x0000 +// <_args>: +}; + +// The same as rom_call_batch_algo_armv6m, but clearing stack limits before setting stack: +static const uint8_t rp2xxx_rom_call_batch_algo_armv8m[ROM_CALL_BATCH_ALGO_SIZE_BYTES] = { +// <_start>: + 0x07, 0xa7, // add r7, pc, #28 ; (adr r7, 20 <_args>) + 0x00, 0x20, // movs r0, #0 + 0x80, 0xf3, 0x0a, 0x88, // msr MSPLIM, r0 + 0x80, 0xf3, 0x0b, 0x88, // msr PSPLIM, r0 +// <_do_next>: + 0x10, 0xcf, // ldmia r7!, {r4} + 0x00, 0x2c, // cmp r4, #0 + 0x05, 0xd0, // beq.n 1e <_done> + 0x20, 0xcf, // ldmia r7!, {r5} + 0xad, 0x46, // mov sp, r5 + 0x0f, 0xcf, // ldmia r7!, {r0, r1, r2, r3} + 0xa0, 0x47, // blx r4 + 0xf7, 0xe7, // b.n c <_do_next> + 0xc0, 0x46, // nop +// <_done>: + 0x00, 0xbe, // bkpt 0x0000 +// <_args>: +}; + +// The same as rom_call_batch_algo_armv6m, but placing arguments in a0-a3 on RISC-V: +static const uint8_t rp2xxx_rom_call_batch_algo_riscv[ROM_CALL_BATCH_ALGO_SIZE_BYTES] = { +// <_start>: + 0x97, 0x04, 0x00, 0x00, // auipc s1,0 + 0x93, 0x84, 0x04, 0x02, // add s1,s1,32 # 20 <_args> +// <_do_next>: + 0x98, 0x40, // lw a4,0(s1) + 0x11, 0xcb, // beqz a4,1e <_done> + 0x03, 0xa1, 0x44, 0x00, // lw sp,4(s1) + 0x88, 0x44, // lw a0,8(s1) + 0xcc, 0x44, // lw a1,12(s1) + 0x90, 0x48, // lw a2,16(s1) + 0xd4, 0x48, // lw a3,20(s1) + 0xe1, 0x04, // add s1,s1,24 + 0x02, 0x97, // jalr a4 + 0xf5, 0xb7, // j 8 <_do_next> +// <_done>: + 0x02, 0x90, // ebreak +// <_args>: +}; + +struct rp2xxx_rom_call_batch_record { + uint32_t pc; + uint32_t sp; + uint32_t args[4]; +}; + +struct rp2xxx_flash_bank { + bool probed; /* flag indicating successful flash probe */ + uint32_t id; /* cached SYSINFO CHIP_ID */ + struct working_area *stack; /* stack used by Boot ROM calls */ + /* static code scratchpad used for RAM algorithms -- allocated in advance + so that higher-level calls can just grab all remaining workarea: */ + struct working_area *ram_algo_space; + /* function jump table populated by rp2xxx_flash_probe() */ + uint16_t jump_flash_exit_xip; + uint16_t jump_connect_internal_flash; + uint16_t jump_flash_range_erase; + uint16_t jump_flash_range_program; + uint16_t jump_flush_cache; + uint16_t jump_flash_reset_address_trans; + uint16_t jump_enter_cmd_xip; + uint16_t jump_bootrom_reset_state; + uint16_t jump_bootrom_set_varm_stack; + + char dev_name[20]; + bool size_override; + struct flash_device spi_dev; /* detected model of SPI flash */ + unsigned int sfdp_dummy, sfdp_dummy_detect; +}; + +#ifndef LOG_ROM_SYMBOL_DEBUG +#define LOG_ROM_SYMBOL_DEBUG LOG_DEBUG +#endif + +static int rp2040_lookup_rom_symbol(struct target *target, uint16_t tag, uint16_t flags, uint16_t *symbol_out) +{ + LOG_ROM_SYMBOL_DEBUG("Looking up ROM symbol '%c%c' in RP2040 table", tag & 0xff, (tag >> 8) & 0xff); + if (flags != RT_FLAG_FUNC_ARM_SEC && flags != RT_FLAG_DATA) { + /* Note RT flags do not exist on RP2040, so just sanity check that we + are asked for a type of thing that actually exists in the ROM table */ + LOG_ERROR("Only data and Secure Arm functions can be looked up in RP2040 ROM table"); + return ERROR_FAIL; + } + + uint16_t ptr_to_entry; + unsigned int offset_magic_to_table_ptr = flags == RT_FLAG_DATA ? 6 : 4; + int err = target_read_u16(target, BOOTROM_MAGIC_ADDR + offset_magic_to_table_ptr, &ptr_to_entry); + if (err != ERROR_OK) + return err; + + uint16_t entry_tag; + do { + err = target_read_u16(target, ptr_to_entry, &entry_tag); + if (err != ERROR_OK) + return err; + + if (entry_tag == tag) { + /* 16 bit symbol is next */ + err = target_read_u16(target, ptr_to_entry + 2, symbol_out); + if (err != ERROR_OK) + return err; + + LOG_ROM_SYMBOL_DEBUG(" -> found: 0x%04" PRIx16, *symbol_out); + return ERROR_OK; + } + ptr_to_entry += 4; + } while (entry_tag); + *symbol_out = 0; + return ERROR_FAIL; +} + +static int rp2350_a0_lookup_symbol(struct target *target, uint16_t tag, uint16_t flags, uint16_t *symbol_out) +{ + LOG_ROM_SYMBOL_DEBUG("Looking up ROM symbol '%c%c' in RP2350 A0 table", tag & 0xff, (tag >> 8) & 0xff); + + /* RP2350 A0 table format is the same as RP2040 except with 16 bits of + flags after each 16-bit pointer. We ignore the flags, as each symbol + only has one datum associated with it. */ + + uint32_t magic_ptr = BOOTROM_MAGIC_ADDR; + if (flags == RT_FLAG_FUNC_RISCV) { + /* RP2350 A0 used split function tables for Arm/RISC-V -- not used on + any other device or any other version of this device. There is a + well-known RISC-V table at the top of ROM, matching the well-known + Arm table at the bottom of ROM. */ + magic_ptr = 0x7decu; + } else if (flags != RT_FLAG_FUNC_ARM_SEC) { + LOG_WARNING("Ignoring non-default flags for RP2350 A0 lookup, hope you like Secure Arm functions"); + } + + uint16_t ptr_to_entry; + const unsigned int offset_magic_to_table_ptr = 4; + int err = target_read_u16(target, magic_ptr + offset_magic_to_table_ptr, &ptr_to_entry); + if (err != ERROR_OK) + return err; + + uint16_t entry_tag; + do { + err = target_read_u16(target, ptr_to_entry, &entry_tag); + if (err != ERROR_OK) + return err; + + if (entry_tag == tag) { + err = target_read_u16(target, ptr_to_entry + 2, symbol_out); + if (err != ERROR_OK) + return err; + + LOG_ROM_SYMBOL_DEBUG(" -> found: 0x%04" PRIx16, *symbol_out); + return ERROR_OK; + } + ptr_to_entry += 6; + } while (entry_tag); + *symbol_out = 0; + return ERROR_FAIL; +} + +static int rp2350_lookup_rom_symbol(struct target *target, uint32_t ptr_to_entry, + uint16_t tag, uint16_t flags, uint16_t *symbol_out) +{ + LOG_ROM_SYMBOL_DEBUG("Looking up ROM symbol '%c%c' in RP2350 A1 table", tag & 0xff, (tag >> 8) & 0xff); + + /* On RP2350 A1, Each entry has a flag bitmap identifying the type of its + contents. The entry contains one halfword of data for each set flag + bit. There may be both Arm and RISC-V entries under the same tag, or + separate Arm Secure/NonSecure entries (or all three, why not). */ + + while (true) { + uint16_t entry_tag, entry_flags; + + int err = target_read_u16(target, ptr_to_entry, &entry_tag); + if (err != ERROR_OK) + return err; + + if (entry_tag == 0) { + *symbol_out = 0; + return ERROR_FAIL; + } + ptr_to_entry += 2; + + err = target_read_u16(target, ptr_to_entry, &entry_flags); + if (err != ERROR_OK) + return err; + + ptr_to_entry += 2; + + uint16_t matching_flags = flags & entry_flags; + + if (tag == entry_tag && matching_flags != 0) { + /* This is our entry, seek to the correct data item and return it. */ + bool is_riscv_func = matching_flags & RT_FLAG_FUNC_RISCV; + while (!(matching_flags & 1)) { + if (entry_flags & 1) + ptr_to_entry += 2; + + matching_flags >>= 1; + entry_flags >>= 1; + } + if (is_riscv_func) { + /* For RISC-V, the table entry itself is the entry point -- trick + to make shared function implementations smaller */ + *symbol_out = ptr_to_entry; + return ERROR_OK; + } + err = target_read_u16(target, ptr_to_entry, symbol_out); + if (err != ERROR_OK) + return err; + + LOG_ROM_SYMBOL_DEBUG(" -> found: 0x%04" PRIx16, *symbol_out); + return ERROR_OK; + } + /* Skip past this entry */ + while (entry_flags) { + if (entry_flags & 1) + ptr_to_entry += 2; + + entry_flags >>= 1; + } + } +} + +static int rp2xxx_lookup_rom_symbol(struct target *target, uint16_t tag, uint16_t flags, uint16_t *symbol_out) +{ + uint32_t magic; + int err = target_read_u32(target, BOOTROM_MAGIC_ADDR, &magic); + if (err != ERROR_OK) + return err; + + /* Ignore version */ + magic &= BOOTROM_MAGIC_MASK; + + if (magic == BOOTROM_RP2350_MAGIC) { + /* Distinguish old-style RP2350 ROM table (A0, and earlier A1 builds) + based on position of table -- a high address means it is shared with + RISC-V, i.e. new-style. */ + uint16_t table_ptr; + err = target_read_u16(target, BOOTROM_MAGIC_ADDR + 4, &table_ptr); + if (err != ERROR_OK) + return err; + if (table_ptr < 0x7c00) + return rp2350_a0_lookup_symbol(target, tag, flags, symbol_out); + else + return rp2350_lookup_rom_symbol(target, table_ptr, tag, flags, symbol_out); + + } else if (magic == BOOTROM_RP2040_MAGIC) { + return rp2040_lookup_rom_symbol(target, tag, flags, symbol_out); + } + LOG_ERROR("RP2040/RP2350 BOOT ROM not found"); + return ERROR_FAIL; +} + +static int rp2xxx_populate_rom_pointer_cache(struct target *target, struct rp2xxx_flash_bank *priv) +{ + uint16_t symtype_func = is_arm(target_to_arm(target)) + ? RT_FLAG_FUNC_ARM_SEC : RT_FLAG_FUNC_RISCV; + int err; + err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_EXIT_XIP, + symtype_func, &priv->jump_flash_exit_xip); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_FLASH_EXIT_XIP not found in RP2xxx ROM"); + return err; + } + + err = rp2xxx_lookup_rom_symbol(target, FUNC_CONNECT_INTERNAL_FLASH, + symtype_func, &priv->jump_connect_internal_flash); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_CONNECT_INTERNAL_FLASH not found in RP2xxx ROM"); + return err; + } + + err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_RANGE_ERASE, symtype_func, &priv->jump_flash_range_erase); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_FLASH_RANGE_ERASE not found in RP2xxx ROM"); + return err; + } + + err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_RANGE_PROGRAM, symtype_func, &priv->jump_flash_range_program); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_FLASH_RANGE_PROGRAM not found in RP2xxx ROM"); + return err; + } + + err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_FLUSH_CACHE, symtype_func, &priv->jump_flush_cache); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_FLASH_FLUSH_CACHE not found in RP2xxx ROM"); + return err; + } + + err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_ENTER_CMD_XIP, symtype_func, &priv->jump_enter_cmd_xip); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_FLASH_ENTER_CMD_XIP not found in RP2xxx ROM"); + return err; + } + + // From this point are optional functions which do not exist on e.g. RP2040 + // or pre-production RP2350 ROM versions: + if (IS_RP2040(priv->id)) { + priv->jump_bootrom_reset_state = 0; + priv->jump_flash_reset_address_trans = 0; + return ERROR_OK; + } + + err = rp2xxx_lookup_rom_symbol(target, FUNC_BOOTROM_STATE_RESET, symtype_func, &priv->jump_bootrom_reset_state); + if (err != ERROR_OK) { + priv->jump_bootrom_reset_state = 0; + LOG_WARNING("Function FUNC_BOOTROM_STATE_RESET not found in RP2xxx ROM. (probably an RP2350 A0)"); + } + + if (!is_arm(target_to_arm(target))) { + err = rp2xxx_lookup_rom_symbol(target, FUNC_BOOTROM_SET_STACK, symtype_func, + &priv->jump_bootrom_set_varm_stack); + if (err != ERROR_OK) { + priv->jump_bootrom_set_varm_stack = 0; + LOG_WARNING("Function FUNC_BOOTROM_SET_STACK not found in RP2xxx ROM. (probably an RP2350 A0)"); + } + } + + err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_RESET_ADDRESS_TRANS, + symtype_func, &priv->jump_flash_reset_address_trans); + if (err != ERROR_OK) { + priv->jump_flash_reset_address_trans = 0; + LOG_WARNING("Function FUNC_FLASH_RESET_ADDRESS_TRANS not found in RP2xxx ROM. (probably an RP2350 A0)"); + } + return ERROR_OK; +} + +// Call a list of PC + SP + r0-r3 function call tuples with a single OpenOCD +// algorithm invocation, to amortise the algorithm overhead over multiple calls: +static int rp2xxx_call_rom_func_batch(struct target *target, struct rp2xxx_flash_bank *priv, + struct rp2xxx_rom_call_batch_record *calls, unsigned int n_calls) +{ + // Note + sizeof(uint32_t) is for the null terminator + unsigned int batch_size = ROM_CALL_BATCH_ALGO_SIZE_BYTES + + n_calls * sizeof(struct rp2xxx_rom_call_batch_record) + + sizeof(uint32_t); + + if (!priv->ram_algo_space) { + LOG_ERROR("No RAM code space allocated for ROM call"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + if (priv->ram_algo_space->size < batch_size) { + LOG_ERROR("RAM code space too small for call batch size of %u", n_calls); + return ERROR_BUF_TOO_SMALL; + } + + LOG_TARGET_DEBUG(target, "Calling batch of %u ROM functions:", n_calls); + for (unsigned int i = 0; i < n_calls; ++i) { + LOG_DEBUG(" func @ %" PRIx32, calls[i].pc); + LOG_DEBUG(" sp = %" PRIx32, calls[i].sp); + for (unsigned int j = 0; j < 4; ++j) + LOG_DEBUG(" a%u = %" PRIx32, j, calls[i].args[j]); + } + + if (n_calls <= 0) { + LOG_DEBUG("Returning early from call of 0 ROM functions"); + return ERROR_OK; + } + + const uint8_t *algo_code; + if (is_arm(target_to_arm(target))) { + if (target_to_arm(target)->arch == ARM_ARCH_V8M) { + LOG_DEBUG("Using algo: rp2xxx_rom_call_batch_algo_armv8m"); + algo_code = rp2xxx_rom_call_batch_algo_armv8m; + } else { + LOG_DEBUG("Using algo: rp2xxx_rom_call_batch_algo_armv6m"); + algo_code = rp2xxx_rom_call_batch_algo_armv6m; + } + } else { + LOG_DEBUG("Using algo: rp2xxx_rom_call_batch_algo_riscv"); + algo_code = rp2xxx_rom_call_batch_algo_riscv; + } + + uint8_t *batch_bf = malloc(batch_size); + if (!batch_bf) { + LOG_ERROR("No memory for batch buffer"); + return ERROR_FAIL; + } + memcpy(batch_bf, algo_code, ROM_CALL_BATCH_ALGO_SIZE_BYTES); + unsigned int words = n_calls * sizeof(struct rp2xxx_rom_call_batch_record) + / sizeof(uint32_t); + target_buffer_set_u32_array(target, + &batch_bf[ROM_CALL_BATCH_ALGO_SIZE_BYTES], words, + (const uint32_t *)calls); + /* Null terminator */ + target_buffer_set_u32(target, &batch_bf[batch_size - sizeof(uint32_t)], 0); + + int err = target_write_buffer(target, + priv->ram_algo_space->address, + batch_size, + batch_bf + ); + free(batch_bf); + + if (err != ERROR_OK) { + LOG_ERROR("Failed to write ROM batch algorithm to RAM code space"); + return err; + } + + // Call into the ROM batch algorithm -- this will in turn call each ROM + // call specified by the batch records. + target_addr_t algo_start_addr = priv->ram_algo_space->address; + target_addr_t algo_end_addr = priv->ram_algo_space->address + rp2xxx_rom_call_batch_algo_bkpt_offset; + unsigned int algo_timeout_ms = 3000; + if (is_arm(target_to_arm(target))) { + struct armv7m_algorithm alg_info; + alg_info.common_magic = ARMV7M_COMMON_MAGIC; + alg_info.core_mode = ARM_MODE_THREAD; + err = target_run_algorithm(target, + 0, NULL, /* No memory arguments */ + 0, NULL, /* No register arguments */ + algo_start_addr, algo_end_addr, + algo_timeout_ms, + &alg_info + ); + } else { + // Presumed RISC-V -- there is no RISCV_COMMON_MAGIC on older OpenOCD + err = target_run_algorithm(target, + 0, NULL, /* No memory arguments */ + 0, NULL, /* No register arguments */ + algo_start_addr, algo_end_addr, + algo_timeout_ms, + NULL /* Currently no RISC-V-specific algorithm info */ + ); + } + if (err != ERROR_OK) { + LOG_ERROR("Failed to call ROM function batch"); + /* This case is hit when loading new ROM images on FPGA, but can also be hit on real + hardware if you swap two devices with different ROM versions without restarting OpenOCD: */ + LOG_ROM_SYMBOL_DEBUG("Repopulating ROM address cache after failed ROM call"); + /* We ignore the error on this next call because we have already failed, this is just + recovery for the next attempt. */ + (void)rp2xxx_populate_rom_pointer_cache(target, priv); + return err; + } + return ERROR_OK; +} + +// Call a single ROM function, using the default algorithm stack. +static int rp2xxx_call_rom_func(struct target *target, struct rp2xxx_flash_bank *priv, + uint16_t func_offset, uint32_t argdata[], unsigned int n_args) +{ + assert(n_args <= 4); /* only allow register arguments -- capped at just 4 on Arm */ + + if (!priv->stack) { + LOG_ERROR("no stack for flash programming code"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + target_addr_t stacktop = priv->stack->address + priv->stack->size; + + struct rp2xxx_rom_call_batch_record call = { + .pc = func_offset, + .sp = stacktop + }; + for (unsigned int i = 0; i < n_args; ++i) + call.args[i] = argdata[i]; + + return rp2xxx_call_rom_func_batch(target, priv, &call, 1); +} + +static int rp2350_init_accessctrl(struct target *target) +{ + // Attempt to reset ACCESSCTRL, in case Secure access to SRAM has been + // blocked, which will stop us from loading/running algorithms such as RCP + // init. (Also ROM, QMI regs are needed later) + uint32_t accessctrl_lock_reg; + if (target_read_u32(target, ACCESSCTRL_LOCK_OFFSET, &accessctrl_lock_reg) != ERROR_OK) { + LOG_ERROR("Failed to read ACCESSCTRL lock register"); + // Failed to read an APB register which should always be readable from + // any security/privilege level. Something fundamental is wrong. E.g.: + // + // - The debugger is attempting to perform Secure bus accesses on a + // system where Secure debug has been disabled + // - clk_sys or busfabric clock are stopped (try doing a rescue reset) + return ERROR_FAIL; + } + if (accessctrl_lock_reg & ACCESSCTRL_LOCK_DEBUG_BITS) { + LOG_ERROR("ACCESSCTRL is locked, so can't reset permissions. Following steps might fail"); + } else { + LOG_DEBUG("Reset ACCESSCTRL permissions via CFGRESET"); + return target_write_u32(target, ACCESSCTRL_CFGRESET_OFFSET, ACCESSCTRL_WRITE_PASSWORD | 1u); + } + return ERROR_OK; +} + +static int rp2350_init_arm_core0(struct target *target, struct rp2xxx_flash_bank *priv) +{ + // Flash algorithms (and the RCP init stub called by this function) must + // run in the Secure state, so flip the state now before attempting to + // execute any code on the core. + int retval; + uint32_t dscsr; + retval = target_read_u32(target, DCB_DSCSR, &dscsr); + if (retval != ERROR_OK) { + LOG_ERROR("RP2350 init ARM core: DSCSR read failed"); + return retval; + } + + LOG_DEBUG("DSCSR: 0x%08" PRIx32, dscsr); + if (!(dscsr & DSCSR_CDS)) { + LOG_DEBUG("Setting Current Domain Secure in DSCSR"); + retval = target_write_u32(target, DCB_DSCSR, (dscsr & ~DSCSR_CDSKEY) | DSCSR_CDS); + if (retval != ERROR_OK) { + LOG_ERROR("RP2350 init ARM core: DSCSR read failed"); + return retval; + } + } + + if (!priv->stack) { + LOG_ERROR("No stack for flash programming code"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + if (!priv->ram_algo_space || priv->ram_algo_space->size < sizeof(rcp_init_code)) { + LOG_ERROR("No algorithm space for rcp_init code"); + return ERROR_BUF_TOO_SMALL; + } + + int err = target_write_memory(target, + priv->ram_algo_space->address, + 1, + sizeof(rcp_init_code), + rcp_init_code + ); + if (err != ERROR_OK) { + LOG_ERROR("Failed to load rcp_init algorithm into RAM"); + return ERROR_FAIL; + } + + LOG_TARGET_DEBUG(target, "Calling rcp_init, code at " TARGET_ADDR_FMT, + priv->ram_algo_space->address); + + /* Actually call the function */ + struct armv7m_algorithm alg_info; + alg_info.common_magic = ARMV7M_COMMON_MAGIC; + alg_info.core_mode = ARM_MODE_THREAD; + err = target_run_algorithm(target, + 0, NULL, /* No memory arguments */ + 0, NULL, /* No register arguments */ + priv->ram_algo_space->address, + priv->ram_algo_space->address + rcp_init_code_bkpt_offset, + 1000, /* 1s timeout */ + &alg_info + ); + if (err != ERROR_OK) { + LOG_ERROR("Failed to invoke rcp_init"); + return err; + } + + return err; +} + +static int setup_for_raw_flash_cmd(struct target *target, struct rp2xxx_flash_bank *priv) +{ + int err = ERROR_OK; + + if (!priv->stack) { + /* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */ + err = target_alloc_working_area(target, RP2XXX_MAX_ALGO_STACK_USAGE, &priv->stack); + if (err != ERROR_OK) { + LOG_ERROR("Could not allocate stack for flash programming code -- insufficient space"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + } + + if (!priv->ram_algo_space) { + err = target_alloc_working_area(target, RP2XXX_MAX_RAM_ALGO_SIZE, &priv->ram_algo_space); + if (err != ERROR_OK) { + LOG_ERROR("Could not allocate RAM code space for ROM calls -- insufficient space"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + } + + if (IS_RP2350(priv->id)) { + err = rp2350_init_accessctrl(target); + if (err != ERROR_OK) { + LOG_ERROR("Failed to init ACCESSCTRL before ROM call"); + return err; + } + if (is_arm(target_to_arm(target))) { + err = rp2350_init_arm_core0(target, priv); + if (err != ERROR_OK) { + LOG_ERROR("Failed to init Arm core 0 before ROM call"); + return err; + } + } + uint32_t reset_args[1] = { + BOOTROM_STATE_RESET_CURRENT_CORE + }; + if (!priv->jump_bootrom_reset_state) { + LOG_WARNING("RP2350 flash: no bootrom_reset_method"); + } else { + /* This is mainly required to clear varmulet_enclosing_cpu pointers on RISC-V, in case + an Arm -> RISC-V call has been interrupted (these pointers are used to handle + reentrant calls to the ROM emulator) */ + LOG_DEBUG("Clearing core 0 ROM state"); + err = rp2xxx_call_rom_func(target, priv, priv->jump_bootrom_reset_state, + reset_args, ARRAY_SIZE(reset_args)); + if (err != ERROR_OK) { + LOG_ERROR("RP2350 flash: failed to call reset core state"); + return err; + } + } + if (!is_arm(target_to_arm(target)) && priv->jump_bootrom_set_varm_stack) { + /* Pass {0, 0} to set_varmulet_user_stack() to enable automatic emulation of Arm APIs + using the ROM's default stacks. Usually the bootrom does this before exiting to user + code, but it needs to be done manually when the USB bootloader has been interrupted. */ + LOG_DEBUG("Enabling default Arm emulator stacks for RISC-V ROM calls"); + struct working_area *set_stack_mem_args; + err = target_alloc_working_area(target, 2 * sizeof(uint32_t), &set_stack_mem_args); + if (err != ERROR_OK) { + LOG_ERROR("Failed to allocate memory for arguments to set_varmulet_user_stack()"); + return err; + } + + err = target_write_u32(target, set_stack_mem_args->address, 0); + if (err == ERROR_OK) + err = target_write_u32(target, set_stack_mem_args->address + 4, 0); + + if (err != ERROR_OK) { + LOG_ERROR("Failed to initialise memory arguments for set_varmulet_user_stack()"); + target_free_working_area(target, set_stack_mem_args); + return err; + } + + uint32_t set_stack_register_args[1] = { + set_stack_mem_args->address + }; + err = rp2xxx_call_rom_func(target, priv, priv->jump_bootrom_set_varm_stack, + set_stack_register_args, ARRAY_SIZE(set_stack_register_args)); + target_free_working_area(target, set_stack_mem_args); + if (err != ERROR_OK) { + LOG_ERROR("Failed to initialise Arm emulation stacks for RISC-V"); + return err; + } + } + } + + LOG_DEBUG("Connecting flash IOs and issuing XIP exit sequence to flash"); + struct rp2xxx_rom_call_batch_record calls[2] = { + { + .pc = priv->jump_connect_internal_flash, + .sp = priv->stack->address + priv->stack->size + }, + { + .pc = priv->jump_flash_exit_xip, + .sp = priv->stack->address + priv->stack->size + } + }; + err = rp2xxx_call_rom_func_batch(target, priv, calls, 2); + if (err != ERROR_OK) { + LOG_ERROR("RP2xxx flash: failed to exit flash XIP mode"); + return err; + } + + return ERROR_OK; +} + +static int rp2xxx_invalidate_cache_restore_xip(struct target *target, struct rp2xxx_flash_bank *priv) +{ + // Flash content has changed. We can now do a bit of poking to make + // the new flash contents visible to us via memory-mapped (XIP) interface + // in the 0x1... memory region. + + LOG_DEBUG("Flushing flash cache after write behind"); + + struct rp2xxx_rom_call_batch_record finishing_calls[2] = { + { + .pc = priv->jump_flush_cache, + .sp = priv->stack->address + priv->stack->size + }, + { + .sp = priv->stack->address + priv->stack->size + }, + }; + + int num_finishing_calls = 1; + // Note on RP2350 it's not *required* to call flash_enter_cmd_xip, since + // the ROM leaves flash XIPable by default in between direct-mode + // accesses + if (IS_RP2040(priv->id)) { + finishing_calls[num_finishing_calls++].pc = priv->jump_enter_cmd_xip; + } else if (priv->jump_flash_reset_address_trans) { + // Note flash_reset_address_trans function does not exist on older devices + finishing_calls[num_finishing_calls++].pc = priv->jump_flash_reset_address_trans; + } + + int retval = rp2xxx_call_rom_func_batch(target, priv, finishing_calls, num_finishing_calls); + if (retval != ERROR_OK) + LOG_ERROR("RP2xxx: failed to flush flash cache/restore XIP"); + + return retval; +} + +static void cleanup_after_raw_flash_cmd(struct target *target, struct rp2xxx_flash_bank *priv) +{ + /* OpenOCD is prone to trashing work-area allocations on target state + transitions, which leaves us with stale work area pointers in our + driver state. Best to clean up our allocations manually after + completing each flash call, so we know to make fresh ones next time. */ + LOG_DEBUG("Cleaning up after flash operations"); + if (priv->stack) { + target_free_working_area(target, priv->stack); + priv->stack = 0; + } + if (priv->ram_algo_space) { + target_free_working_area(target, priv->ram_algo_space); + priv->ram_algo_space = 0; + } +} + +static int rp2xxx_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) +{ + LOG_DEBUG("Writing %" PRIu32 " bytes starting at 0x%" PRIx32, count, offset); + + struct rp2xxx_flash_bank *priv = bank->driver_priv; + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + struct working_area *bounce = NULL; + + int err = setup_for_raw_flash_cmd(target, priv); + if (err != ERROR_OK) + goto cleanup_and_return; + + unsigned int avail_pages = target_get_working_area_avail(target) / RP2XXX_ROM_API_FIXED_FLASH_PAGE; + /* We try to allocate working area rounded down to device page size, + * al least 1 page, at most the write data size */ + unsigned int chunk_size = MIN(MAX(avail_pages, 1) * RP2XXX_ROM_API_FIXED_FLASH_PAGE, count); + err = target_alloc_working_area(target, chunk_size, &bounce); + if (err != ERROR_OK) { + LOG_ERROR("Could not allocate bounce buffer for flash programming. Can't continue"); + goto cleanup_and_return; + } + + LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, bounce->address); + + while (count > 0) { + uint32_t write_size = count > chunk_size ? chunk_size : count; + LOG_DEBUG("Writing %" PRIu32 " bytes to offset 0x%" PRIx32, + write_size, offset); + err = target_write_buffer(target, bounce->address, write_size, buffer); + if (err != ERROR_OK) { + LOG_ERROR("Could not load data into target bounce buffer"); + break; + } + uint32_t args[3] = { + offset, /* addr */ + bounce->address, /* data */ + write_size /* count */ + }; + err = rp2xxx_call_rom_func(target, priv, priv->jump_flash_range_program, + args, ARRAY_SIZE(args)); + keep_alive(); + if (err != ERROR_OK) { + LOG_ERROR("Failed to invoke flash programming code on target"); + break; + } + + buffer += write_size; + offset += write_size; + count -= write_size; + } + +cleanup_and_return: + target_free_working_area(target, bounce); + + /* Don't propagate error or user gets fooled the flash write failed */ + (void)rp2xxx_invalidate_cache_restore_xip(target, priv); + + cleanup_after_raw_flash_cmd(target, priv); + return err; +} + +static int rp2xxx_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last) +{ + struct rp2xxx_flash_bank *priv = bank->driver_priv; + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + uint32_t offset_start = bank->sectors[first].offset; + uint32_t offset_last = bank->sectors[last].offset + bank->sectors[last].size; + uint32_t length = offset_last - offset_start; + LOG_DEBUG("erase %" PRIu32 " bytes starting at 0x%" PRIx32, + length, offset_start); + + int err = setup_for_raw_flash_cmd(target, priv); + if (err != ERROR_OK) + goto cleanup_and_return; + + uint32_t offset_next = offset_start; + + /* Break erase into multiple calls to avoid timeout on large erase. Choose 128k chunk which has + fairly low ROM call overhead and empirically seems to avoid the default keep_alive() limit + as well as our ROM call timeout. */ + const uint32_t erase_chunk_size = 128 * 1024; + + /* Promote log level for long erases to provide feedback */ + bool requires_loud_prints = offset_last - offset_next >= 2 * erase_chunk_size; + enum log_levels chunk_log_level = requires_loud_prints ? LOG_LVL_INFO : LOG_LVL_DEBUG; + + while (offset_next < offset_last) { + uint32_t remaining = offset_last - offset_next; + uint32_t call_size = remaining < erase_chunk_size ? remaining : erase_chunk_size; + /* Shorten the first call of a large erase if necessary to align subsequent calls */ + if (offset_next % erase_chunk_size != 0 && call_size == erase_chunk_size) + call_size = erase_chunk_size - offset_next % erase_chunk_size; + + LOG_CUSTOM_LEVEL(chunk_log_level, + " Erase chunk: 0x%08" PRIx32 " -> 0x%08" PRIx32, + offset_next, + offset_next + call_size - 1 + ); + + /* This ROM function uses the optimal mixture of 4k 20h and 64k D8h erases, without + over-erase. This is why we force the flash_bank sector size attribute to 4k even if + OpenOCD prefers to give the block size instead. */ + uint32_t args[4] = { + offset_next, + call_size, + 65536, /* block_size */ + 0xd8 /* block_cmd */ + }; + + err = rp2xxx_call_rom_func(target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args)); + keep_alive(); + + if (err != ERROR_OK) + break; + + offset_next += call_size; + } + + +cleanup_and_return: + /* Don't propagate error or user gets fooled the flash erase failed */ + (void)rp2xxx_invalidate_cache_restore_xip(target, priv); + + cleanup_after_raw_flash_cmd(target, priv); + return err; +} + +/* ----------------------------------------------------------------------------- + Driver probing etc */ + + +static int rp2040_ssel_active(struct target *target, bool active) +{ + uint32_t state = active ? RP2040_QSPI_CTRL_OUTOVER_LOW : RP2040_QSPI_CTRL_OUTOVER_HIGH; + uint32_t val; + + int err = target_read_u32(target, RP2040_QSPI_CTRL, &val); + if (err != ERROR_OK) + return err; + + val = (val & ~RP2040_QSPI_CTRL_OUTOVER_MASK) | state; + + err = target_write_u32(target, RP2040_QSPI_CTRL, val); + if (err != ERROR_OK) + return err; + + return ERROR_OK; +} + +static int rp2040_spi_tx_rx(struct target *target, + const uint8_t *tx, unsigned int tx_len, + unsigned int dummy_len, + uint8_t *rx, unsigned int rx_len) +{ + int retval, retval2; + + retval = rp2040_ssel_active(target, true); + if (retval != ERROR_OK) { + LOG_ERROR("QSPI select failed"); + goto deselect; + } + + unsigned int tx_cnt = 0; + unsigned int rx_cnt = 0; + unsigned int xfer_len = tx_len + dummy_len + rx_len; + while (rx_cnt < xfer_len) { + int in_flight = tx_cnt - rx_cnt; + if (tx_cnt < xfer_len && in_flight < 14) { + uint32_t dr = tx_cnt < tx_len ? tx[tx_cnt] : 0; + retval = target_write_u32(target, RP2040_SSI_DR0, dr); + if (retval != ERROR_OK) + break; + + tx_cnt++; + continue; + } + uint32_t dr; + retval = target_read_u32(target, RP2040_SSI_DR0, &dr); + if (retval != ERROR_OK) + break; + + if (rx_cnt >= tx_len + dummy_len) + rx[rx_cnt - tx_len - dummy_len] = (uint8_t)dr; + + rx_cnt++; + } + +deselect: + retval2 = rp2040_ssel_active(target, false); + + if (retval != ERROR_OK) { + LOG_ERROR("QSPI Tx/Rx failed"); + return retval; + } + if (retval2 != ERROR_OK) + LOG_ERROR("QSPI deselect failed"); + + return retval2; +} + +static int rp2350_spi_tx_rx(struct target *target, + const uint8_t *tx, unsigned int tx_len, + unsigned int dummy_len, + uint8_t *rx, unsigned int rx_len) +{ + uint32_t direct_csr; + int retval = target_read_u32(target, RP2350_QMI_DIRECT_CSR, &direct_csr); + if (retval != ERROR_OK) { + LOG_ERROR("QMI DIRECT_CSR read failed"); + return retval; + } + direct_csr |= RP2350_QMI_DIRECT_CSR_EN | RP2350_QMI_DIRECT_CSR_ASSERT_CS0N; + retval = target_write_u32(target, RP2350_QMI_DIRECT_CSR, direct_csr); + if (retval != ERROR_OK) { + LOG_ERROR("QMI DIRECT mode enable failed"); + goto deselect; + } + + unsigned int tx_cnt = 0; + unsigned int rx_cnt = 0; + unsigned int xfer_len = tx_len + dummy_len + rx_len; + while (tx_cnt < xfer_len || rx_cnt < rx_len) { + int in_flight = tx_cnt - tx_len - dummy_len - rx_cnt; + if (tx_cnt < xfer_len && in_flight < 4) { + uint32_t tx_cmd; + if (tx_cnt < tx_len) + tx_cmd = tx[tx_cnt] | RP2350_QMI_DIRECT_TX_NOPUSH | RP2350_QMI_DIRECT_TX_OE; + else if (tx_cnt < tx_len + dummy_len) + tx_cmd = RP2350_QMI_DIRECT_TX_NOPUSH; + else + tx_cmd = 0; + + retval = target_write_u32(target, RP2350_QMI_DIRECT_TX, tx_cmd); + if (retval != ERROR_OK) + break; + + tx_cnt++; + continue; + } + if (rx_cnt < rx_len) { + uint32_t dr; + retval = target_read_u32(target, RP2350_QMI_DIRECT_RX, &dr); + if (retval != ERROR_OK) + break; + + rx[rx_cnt] = (uint8_t)dr; + rx_cnt++; + } + } + +deselect: + direct_csr &= ~(RP2350_QMI_DIRECT_CSR_EN | RP2350_QMI_DIRECT_CSR_ASSERT_CS0N); + int retval2 = target_write_u32(target, RP2350_QMI_DIRECT_CSR, direct_csr); + + if (retval != ERROR_OK) { + LOG_ERROR("QSPI Tx/Rx failed"); + return retval; + } + if (retval2 != ERROR_OK) + LOG_ERROR("QMI DIRECT mode disable failed"); + + return retval2; +} + +static int rp2xxx_spi_tx_rx(struct flash_bank *bank, + const uint8_t *tx, unsigned int tx_len, + unsigned int dummy_len, + uint8_t *rx, unsigned int rx_len) +{ + struct rp2xxx_flash_bank *priv = bank->driver_priv; + struct target *target = bank->target; + + if (IS_RP2040(priv->id)) + return rp2040_spi_tx_rx(target, tx, tx_len, dummy_len, rx, rx_len); + else if (IS_RP2350(priv->id)) + return rp2350_spi_tx_rx(target, tx, tx_len, dummy_len, rx, rx_len); + else + return ERROR_FAIL; +} + +static int rp2xxx_read_sfdp_block(struct flash_bank *bank, uint32_t addr, + unsigned int words, uint32_t *buffer) +{ + struct rp2xxx_flash_bank *priv = bank->driver_priv; + + uint8_t cmd[4] = { SPIFLASH_READ_SFDP }; + uint8_t data[4 * words + priv->sfdp_dummy_detect]; + + h_u24_to_be(&cmd[1], addr); + + int retval = rp2xxx_spi_tx_rx(bank, cmd, sizeof(cmd), priv->sfdp_dummy, + data, 4 * words + priv->sfdp_dummy_detect); + if (retval != ERROR_OK) + return retval; + + if (priv->sfdp_dummy_detect) { + for (unsigned int i = 0; i < priv->sfdp_dummy_detect; i++) + if (le_to_h_u32(&data[i]) == SFDP_MAGIC) { + priv->sfdp_dummy_detect = 0; + priv->sfdp_dummy = i; + break; + } + for (unsigned int i = 0; i < words; i++) + buffer[i] = le_to_h_u32(&data[4 * i + priv->sfdp_dummy]); + } else { + for (unsigned int i = 0; i < words; i++) + buffer[i] = le_to_h_u32(&data[4 * i]); + } + return retval; +} + +static int rp2xxx_flash_probe(struct flash_bank *bank) +{ + struct rp2xxx_flash_bank *priv = bank->driver_priv; + struct target *target = bank->target; + + int retval = target_read_u32(target, RP2XXX_SYSINFO_CHIP_ID, &priv->id); + if (retval != ERROR_OK) { + LOG_ERROR("SYSINFO CHIP_ID read failed"); + return retval; + } + if (!IS_RP2040(priv->id) && !IS_RP2350(priv->id)) { + LOG_ERROR("Unknown SYSINFO CHIP_ID 0x%08" PRIx32, priv->id); + return ERROR_FLASH_BANK_INVALID; + } + + retval = rp2xxx_populate_rom_pointer_cache(target, priv); + if (retval != ERROR_OK) + return retval; + + /* the Boot ROM flash_range_program() routine requires page alignment */ + bank->write_start_alignment = RP2XXX_ROM_API_FIXED_FLASH_PAGE; + bank->write_end_alignment = RP2XXX_ROM_API_FIXED_FLASH_PAGE; + + uint32_t flash_id = 0; + if (priv->size_override) { + priv->spi_dev.name = "size override"; + LOG_DEBUG("SPI flash autodetection disabled, using configured size"); + } else { + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + bank->size = 0; + + (void)setup_for_raw_flash_cmd(target, priv); + /* ignore error, flash size detection could work anyway */ + + const uint8_t cmd[] = { SPIFLASH_READ_ID }; + uint8_t data[3]; + retval = rp2xxx_spi_tx_rx(bank, cmd, sizeof(cmd), 0, data, sizeof(data)); + if (retval == ERROR_OK) { + flash_id = le_to_h_u24(data); + + /* search for a SPI flash Device ID match */ + for (const struct flash_device *p = flash_devices; p->name ; p++) { + if (p->device_id == flash_id) { + priv->spi_dev = *p; + bank->size = p->size_in_bytes; + break; + } + } + } + + if (bank->size == 0) { + priv->sfdp_dummy_detect = 8; + priv->sfdp_dummy = 0; + retval = spi_sfdp(bank, &priv->spi_dev, &rp2xxx_read_sfdp_block); + if (retval == ERROR_OK) + bank->size = priv->spi_dev.size_in_bytes; + } + + cleanup_after_raw_flash_cmd(target, priv); + } + + snprintf(priv->dev_name, sizeof(priv->dev_name), "%s rev %u", + IS_RP2350(priv->id) ? "RP2350" : "RP2040", + RP2XXX_CHIP_ID_REVISION(priv->id)); + + if (bank->size == 0) { + LOG_ERROR("%s, QSPI Flash id = 0x%06" PRIx32 " not recognised", + priv->dev_name, flash_id); + return ERROR_FLASH_BANK_INVALID; + } + + bank->num_sectors = bank->size / RP2XXX_ROM_API_FIXED_FLASH_SECTOR; + + if (priv->size_override) { + LOG_INFO("%s, QSPI Flash size override = %u KiB in %u sectors", + priv->dev_name, bank->size / 1024, bank->num_sectors); + } else { + LOG_INFO("%s, QSPI Flash %s id = 0x%06" PRIx32 " size = %u KiB in %u sectors", + priv->dev_name, priv->spi_dev.name, flash_id, + bank->size / 1024, bank->num_sectors); + } + + free(bank->sectors); + bank->sectors = alloc_block_array(0, RP2XXX_ROM_API_FIXED_FLASH_SECTOR, bank->num_sectors); + if (!bank->sectors) + return ERROR_FAIL; + + priv->probed = true; + + return ERROR_OK; +} + +static int rp2xxx_flash_auto_probe(struct flash_bank *bank) +{ + struct rp2xxx_flash_bank *priv = bank->driver_priv; + + if (priv->probed) + return ERROR_OK; + + return rp2xxx_flash_probe(bank); +} + +/* ----------------------------------------------------------------------------- + Driver boilerplate */ + +FLASH_BANK_COMMAND_HANDLER(rp2xxx_flash_bank_command) +{ + struct rp2xxx_flash_bank *priv; + priv = calloc(1, sizeof(struct rp2xxx_flash_bank)); + priv->size_override = bank->size != 0; + + /* Set up driver_priv */ + bank->driver_priv = priv; + + return ERROR_OK; +} + + +COMMAND_HANDLER(rp2xxx_rom_api_call_handler) +{ + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD->ctx); + + struct flash_bank *bank; + for (bank = flash_bank_list(); bank; bank = bank->next) { + if (bank->driver != &rp2xxx_flash) + continue; + + if (bank->target == target) + break; + } + + if (!bank) { + command_print(CMD, "[%s] No associated RP2xxx flash bank found", + target_name(target)); + return ERROR_FAIL; + } + + int retval = rp2xxx_flash_auto_probe(bank); + if (retval != ERROR_OK) { + command_print(CMD, "auto_probe failed"); + return retval; + } + + uint16_t tag = MAKE_TAG(CMD_ARGV[0][0], CMD_ARGV[0][1]); + + uint32_t args[4] = { 0 }; + for (unsigned int i = 0; i + 1 < CMD_ARGC && i < ARRAY_SIZE(args); i++) + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i + 1], args[i]); + + if (target->state != TARGET_HALTED) { + command_print(CMD, "Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + struct rp2xxx_flash_bank *priv = bank->driver_priv; + retval = setup_for_raw_flash_cmd(target, priv); + if (retval != ERROR_OK) + goto cleanup_and_return; + + uint16_t symtype_func = is_arm(target_to_arm(target)) + ? RT_FLAG_FUNC_ARM_SEC : RT_FLAG_FUNC_RISCV; + + uint16_t fc; + retval = rp2xxx_lookup_rom_symbol(target, tag, symtype_func, &fc); + if (retval != ERROR_OK) { + command_print(CMD, "Function %.2s not found in RP2xxx ROM", + CMD_ARGV[0]); + goto cleanup_and_return; + } + + /* command_print() output gets lost if the command is called + * in an event handler, use LOG_INFO instead */ + LOG_INFO("RP2xxx ROM API function %.2s @ %04" PRIx16, CMD_ARGV[0], fc); + + retval = rp2xxx_call_rom_func(target, priv, fc, args, ARRAY_SIZE(args)); + if (retval != ERROR_OK) + command_print(CMD, "RP2xxx ROM API call failed"); + +cleanup_and_return: + cleanup_after_raw_flash_cmd(target, priv); + return retval; +} + +COMMAND_HANDLER(rp2xxx_switch_target_handler) +{ + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *old_target = get_target(CMD_ARGV[0]); + if (!old_target) { + command_print(CMD, "Unrecognised old target %s", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + struct target *new_target = get_target(CMD_ARGV[1]); + if (!new_target) { + command_print(CMD, "Unrecognised new target %s", CMD_ARGV[1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + struct flash_bank *bank; + for (bank = flash_bank_list(); bank; bank = bank->next) { + if (bank->driver == &rp2xxx_flash) { + if (bank->target == old_target) { + bank->target = new_target; + struct rp2xxx_flash_bank *priv = bank->driver_priv; + priv->probed = false; + return ERROR_OK; + } else if (bank->target == new_target) { + return ERROR_OK; + } + } + } + + command_print(CMD, "Neither old nor new target %s found in flash bank list", + CMD_ARGV[0]); + return ERROR_FAIL; +} + +static const struct command_registration rp2xxx_exec_command_handlers[] = { + { + .name = "rom_api_call", + .mode = COMMAND_EXEC, + .help = "arbitrary ROM API call", + .usage = "fc [p0 [p1 [p2 [p3]]]]", + .handler = rp2xxx_rom_api_call_handler, + }, + { + .name = "_switch_target", + .mode = COMMAND_EXEC, + .help = "internal use", + .usage = "old_target new_target", + .handler = rp2xxx_switch_target_handler, + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration rp2xxx_command_handler[] = { + { + .name = "rp2xxx", + .mode = COMMAND_ANY, + .help = "rp2xxx flash controller commands", + .usage = "", + .chain = rp2xxx_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +const struct flash_driver rp2xxx_flash = { + .name = "rp2xxx", + .commands = rp2xxx_command_handler, + .flash_bank_command = rp2xxx_flash_bank_command, + .erase = rp2xxx_flash_erase, + .write = rp2xxx_flash_write, + .read = default_flash_read, + .probe = rp2xxx_flash_probe, + .auto_probe = rp2xxx_flash_auto_probe, + .erase_check = default_flash_blank_check, + .free_driver_priv = default_flash_free_driver_priv +}; diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c index 1f53b2f..f7dcc6f 100644 --- a/src/flash/nor/stellaris.c +++ b/src/flash/nor/stellaris.c @@ -1342,7 +1342,7 @@ COMMAND_HANDLER(stellaris_handle_recover_command) * cycle to recover. */ - Jim_Eval_Named(CMD_CTX->interp, "catch { hla_command \"debug unlock\" }", NULL, 0); + Jim_Eval_Named(CMD_CTX->interp, "catch { hla command \"debug unlock\" }", NULL, 0); if (!strcmp(Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL), "0")) { retval = ERROR_OK; goto user_action; diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index fa57db8..f163332 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -303,10 +303,18 @@ static const struct stm32l4_rev stm32c03xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, }; +static const struct stm32l4_rev stm32c05xx_revs[] = { + { 0x1000, "A" }, +}; + static const struct stm32l4_rev stm32c071xx_revs[] = { { 0x1001, "Z" }, }; +static const struct stm32l4_rev stm32c09xx_revs[] = { + { 0x1000, "A" }, +}; + static const struct stm32l4_rev stm32g05_g06xx_revs[] = { { 0x1000, "A" }, }; @@ -451,6 +459,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { + .id = DEVID_STM32C05XX, + .revs = stm32c05xx_revs, + .num_revs = ARRAY_SIZE(stm32c05xx_revs), + .device_str = "STM32C05xx", + .max_flash_size_kb = 64, + .flags = F_NONE, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75A0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, + }, + { .id = DEVID_STM32C071XX, .revs = stm32c071xx_revs, .num_revs = ARRAY_SIZE(stm32c071xx_revs), @@ -463,6 +483,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { + .id = DEVID_STM32C09XX, + .revs = stm32c09xx_revs, + .num_revs = ARRAY_SIZE(stm32c09xx_revs), + .device_str = "STM32C09xx", + .max_flash_size_kb = 256, + .flags = F_NONE, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75A0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, + }, + { .id = DEVID_STM32U53_U54XX, .revs = stm32u53_u54xx_revs, .num_revs = ARRAY_SIZE(stm32u53_u54xx_revs), @@ -2021,7 +2053,9 @@ static int stm32l4_probe(struct flash_bank *bank) case DEVID_STM32L43_L44XX: case DEVID_STM32C01XX: case DEVID_STM32C03XX: + case DEVID_STM32C05XX: case DEVID_STM32C071XX: + case DEVID_STM32C09XX: case DEVID_STM32G05_G06XX: case DEVID_STM32G07_G08XX: case DEVID_STM32U031XX: diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h index 3199d4f..07b3615 100644 --- a/src/flash/nor/stm32l4x.h +++ b/src/flash/nor/stm32l4x.h @@ -88,6 +88,8 @@ #define DEVID_STM32L47_L48XX 0x415 #define DEVID_STM32L43_L44XX 0x435 #define DEVID_STM32C01XX 0x443 +#define DEVID_STM32C05XX 0x44C +#define DEVID_STM32C09XX 0x44D #define DEVID_STM32C03XX 0x453 #define DEVID_STM32U53_U54XX 0x455 #define DEVID_STM32G05_G06XX 0x456 diff --git a/src/helper/command.c b/src/helper/command.c index 3d4379d..218f058 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -31,8 +31,7 @@ #define __THIS__FILE__ "command.c" struct log_capture_state { - Jim_Interp *interp; - Jim_Obj *output; + char *output; }; static int unregister_command(struct command_context *context, @@ -59,73 +58,6 @@ void *jimcmd_privdata(Jim_Cmd *cmd) return cmd->isproc ? NULL : cmd->u.native.privData; } -static void tcl_output(void *privData, const char *file, unsigned int line, - const char *function, const char *string) -{ - struct log_capture_state *state = privData; - Jim_AppendString(state->interp, state->output, string, strlen(string)); -} - -static struct log_capture_state *command_log_capture_start(Jim_Interp *interp) -{ - /* capture log output and return it. A garbage collect can - * happen, so we need a reference count to this object */ - Jim_Obj *jim_output = Jim_NewStringObj(interp, "", 0); - if (!jim_output) - return NULL; - - Jim_IncrRefCount(jim_output); - - struct log_capture_state *state = malloc(sizeof(*state)); - if (!state) { - LOG_ERROR("Out of memory"); - Jim_DecrRefCount(interp, jim_output); - return NULL; - } - - state->interp = interp; - state->output = jim_output; - - log_add_callback(tcl_output, state); - - return state; -} - -/* Classic openocd commands provide progress output which we - * will capture and return as a Tcl return value. - * - * However, if a non-openocd command has been invoked, then it - * makes sense to return the tcl return value from that command. - * - * The tcl return value is empty for openocd commands that provide - * progress output. - * - * For other commands, we prepend the logs to the tcl return value. - */ -static void command_log_capture_finish(struct log_capture_state *state) -{ - if (!state) - return; - - log_remove_callback(tcl_output, state); - - int loglen; - const char *log_result = Jim_GetString(state->output, &loglen); - int reslen; - const char *cmd_result = Jim_GetString(Jim_GetResult(state->interp), &reslen); - - // Just in case the log doesn't end with a newline, we add it - if (loglen != 0 && reslen != 0 && log_result[loglen - 1] != '\n') - Jim_AppendString(state->interp, state->output, "\n", 1); - - Jim_AppendString(state->interp, state->output, cmd_result, reslen); - - Jim_SetResult(state->interp, state->output); - Jim_DecrRefCount(state->interp, state->output); - - free(state); -} - static int command_retval_set(Jim_Interp *interp, int retval) { int *return_retval = Jim_GetAssocData(interp, "retval"); @@ -680,15 +612,28 @@ COMMAND_HANDLER(handle_echo) return ERROR_OK; } -/* Return both the progress output (LOG_INFO and higher) +static void tcl_output(void *privData, const char *file, unsigned int line, + const char *function, const char *string) +{ + struct log_capture_state *state = privData; + char *old = state->output; + + state->output = alloc_printf("%s%s", old ? old : "", string); + free(old); + if (!state->output) + LOG_ERROR("Out of memory"); +} + +/* + * Return both the progress output (LOG_INFO and higher) * and the tcl return value of a command. */ -static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_command_capture) { - if (argc != 2) - return JIM_ERR; + struct log_capture_state state = {NULL}; - struct log_capture_state *state = command_log_capture_start(interp); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; /* disable polling during capture. This avoids capturing output * from polling. @@ -698,14 +643,24 @@ static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv) */ bool save_poll_mask = jtag_poll_mask(); - const char *str = Jim_GetString(argv[1], NULL); - int retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__); + log_add_callback(tcl_output, &state); + + int jimretval = Jim_EvalObj(CMD_CTX->interp, CMD_JIMTCL_ARGV[0]); + const char *cmd_result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL); + + log_remove_callback(tcl_output, &state); jtag_poll_unmask(save_poll_mask); - command_log_capture_finish(state); + if (state.output && *state.output) + command_print(CMD, "%s", state.output); + + if (cmd_result && *cmd_result) + command_print(CMD, "%s", cmd_result); - return retcode; + free(state.output); + + return (jimretval == JIM_OK) ? ERROR_OK : ERROR_FAIL; } struct help_entry { @@ -843,22 +798,19 @@ COMMAND_HANDLER(handle_help_command) return retval; } -static char *alloc_concatenate_strings(int argc, Jim_Obj * const *argv) +static char *alloc_concatenate_strings(int argc, const char **argv) { - char *prev, *all; - int i; - assert(argc >= 1); - all = strdup(Jim_GetString(argv[0], NULL)); + char *all = strdup(argv[0]); if (!all) { LOG_ERROR("Out of memory"); return NULL; } - for (i = 1; i < argc; ++i) { - prev = all; - all = alloc_printf("%s %s", all, Jim_GetString(argv[i], NULL)); + for (int i = 1; i < argc; ++i) { + char *prev = all; + all = alloc_printf("%s %s", all, argv[i]); free(prev); if (!all) { LOG_ERROR("Out of memory"); @@ -944,17 +896,16 @@ static enum command_mode get_command_mode(Jim_Interp *interp, const char *cmd_na return c->mode; } -static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_command_mode) { - struct command_context *cmd_ctx = current_command_context(interp); - enum command_mode mode = cmd_ctx->mode; + enum command_mode mode = CMD_CTX->mode; - if (argc > 1) { - char *full_name = alloc_concatenate_strings(argc - 1, argv + 1); + if (CMD_ARGC) { + char *full_name = alloc_concatenate_strings(CMD_ARGC, CMD_ARGV); if (!full_name) - return JIM_ERR; + return ERROR_FAIL; - mode = get_command_mode(interp, full_name); + mode = get_command_mode(CMD_CTX->interp, full_name); free(full_name); } @@ -975,8 +926,8 @@ static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv) mode_str = "unknown"; break; } - Jim_SetResultString(interp, mode_str, -1); - return JIM_OK; + command_print(CMD, "%s", mode_str); + return ERROR_OK; } int help_del_all_commands(struct command_context *cmd_ctx) @@ -1115,7 +1066,7 @@ static const struct command_registration command_subcommand_handlers[] = { { .name = "mode", .mode = COMMAND_ANY, - .jim_handler = jim_command_mode, + .handler = handle_command_mode, .usage = "[command_name ...]", .help = "Returns the command modes allowed by a command: " "'any', 'config', or 'exec'. If no command is " @@ -1137,7 +1088,7 @@ static const struct command_registration command_builtin_handlers[] = { { .name = "capture", .mode = COMMAND_ANY, - .jim_handler = jim_capture, + .handler = handle_command_capture, .help = "Capture progress output and return as tcl return value. If the " "progress output was empty, return tcl return value.", .usage = "command", diff --git a/src/helper/list.h b/src/helper/list.h index ba07f15..89b8468 100644 --- a/src/helper/list.h +++ b/src/helper/list.h @@ -35,6 +35,7 @@ /* begin OpenOCD changes */ +#include <assert.h> #include <stddef.h> struct list_head { @@ -109,6 +110,9 @@ static inline void linux_list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { + assert(next); + assert(prev); + next->prev = new; new->next = next; new->prev = prev; diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c index 2fcbd60..6785a74 100644 --- a/src/jtag/adapter.c +++ b/src/jtag/adapter.c @@ -16,6 +16,7 @@ #include "minidriver.h" #include "interface.h" #include "interfaces.h" +#include <helper/bits.h> #include <transport/transport.h> /** @@ -24,7 +25,6 @@ */ struct adapter_driver *adapter_driver; -const char * const jtag_only[] = { "jtag", NULL }; enum adapter_clk_mode { CLOCK_MODE_UNSELECTED = 0, @@ -187,7 +187,6 @@ int adapter_init(struct command_context *cmd_ctx) int adapter_quit(void) { if (is_adapter_initialized() && adapter_driver->quit) { - /* close the JTAG interface */ int result = adapter_driver->quit(); if (result != ERROR_OK) LOG_ERROR("failed: %d", result); @@ -380,7 +379,7 @@ done: COMMAND_HANDLER(handle_adapter_name) { - /* return the name of the interface */ + /* return the name of the adapter driver */ /* TCL code might need to know the exact type... */ /* FUTURE: we allow this as a means to "set" the interface. */ @@ -394,9 +393,22 @@ COMMAND_HANDLER(handle_adapter_name) COMMAND_HANDLER(dump_adapter_driver_list) { + int max_len = 0; + for (unsigned int i = 0; adapter_drivers[i]; i++) { + int len = strlen(adapter_drivers[i]->name); + if (max_len < len) + max_len = len; + } + for (unsigned int i = 0; adapter_drivers[i]; i++) { const char *name = adapter_drivers[i]->name; - command_print(CMD, "%u: %s", i + 1, name); + unsigned int transport_ids = adapter_drivers[i]->transport_ids; + + command_print_sameline(CMD, "%-*s {", max_len, name); + for (unsigned int j = BIT(0); j & TRANSPORT_VALID_MASK; j <<= 1) + if (j & transport_ids) + command_print_sameline(CMD, " %s", transport_name(j)); + command_print(CMD, " }"); } return ERROR_OK; @@ -414,14 +426,14 @@ COMMAND_HANDLER(handle_adapter_driver_command) { int retval; - /* check whether the interface is already configured */ + /* check whether the adapter driver is already configured */ if (adapter_driver) { - LOG_WARNING("Interface already configured, ignoring"); + LOG_WARNING("Adapter driver already configured, ignoring"); return ERROR_OK; } - /* interface name is a mandatory argument */ - if (CMD_ARGC != 1 || CMD_ARGV[0][0] == '\0') + /* adapter driver name is a mandatory argument */ + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; for (unsigned int i = 0; adapter_drivers[i]; i++) { @@ -436,13 +448,14 @@ COMMAND_HANDLER(handle_adapter_driver_command) adapter_driver = adapter_drivers[i]; - return allow_transports(CMD_CTX, adapter_driver->transports); + return allow_transports(CMD_CTX, adapter_driver->transport_ids, + adapter_driver->transport_preferred_id); } - /* no valid interface was found (i.e. the configuration option, - * didn't match one of the compiled-in interfaces + /* no valid adapter driver was found (i.e. the configuration option, + * didn't match one of the compiled-in drivers */ - LOG_ERROR("The specified debug interface was not found (%s)", + LOG_ERROR("The specified adapter driver was not found (%s)", CMD_ARGV[0]); command_print(CMD, "The following adapter drivers are available:"); CALL_COMMAND_HANDLER(dump_adapter_driver_list); diff --git a/src/jtag/core.c b/src/jtag/core.c index 030c173..6dd2144 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -1823,7 +1823,7 @@ static int jtag_select(struct command_context *ctx) } static struct transport jtag_transport = { - .name = "jtag", + .id = TRANSPORT_JTAG, .select = jtag_select, .init = jtag_init, }; @@ -1868,7 +1868,7 @@ int adapter_resets(int trst, int srst) transport_is_swim()) { if (trst == TRST_ASSERT) { LOG_ERROR("transport %s has no trst signal", - get_current_transport()->name); + get_current_transport_name()); return ERROR_FAIL; } @@ -1884,7 +1884,7 @@ int adapter_resets(int trst, int srst) return ERROR_OK; LOG_ERROR("reset is not supported on transport %s", - get_current_transport()->name); + get_current_transport_name()); return ERROR_FAIL; } @@ -1903,7 +1903,7 @@ int adapter_assert_reset(void) return adapter_system_reset(1); else if (get_current_transport()) LOG_ERROR("reset is not supported on %s", - get_current_transport()->name); + get_current_transport_name()); else LOG_ERROR("transport is not selected"); return ERROR_FAIL; @@ -1920,7 +1920,7 @@ int adapter_deassert_reset(void) return adapter_system_reset(0); else if (get_current_transport()) LOG_ERROR("reset is not supported on %s", - get_current_transport()->name); + get_current_transport_name()); else LOG_ERROR("transport is not selected"); return ERROR_FAIL; diff --git a/src/jtag/drivers/am335xgpio.c b/src/jtag/drivers/am335xgpio.c index cacf4e7..a4727cc 100644 --- a/src/jtag/drivers/am335xgpio.c +++ b/src/jtag/drivers/am335xgpio.c @@ -350,8 +350,6 @@ static const struct command_registration am335xgpio_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -static const char * const am335xgpio_transports[] = { "jtag", "swd", NULL }; - static struct jtag_interface am335xgpio_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, @@ -494,7 +492,8 @@ static int am335xgpio_quit(void) struct adapter_driver am335xgpio_adapter_driver = { .name = "am335xgpio", - .transports = am335xgpio_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = am335xgpio_command_handlers, .init = am335xgpio_init, diff --git a/src/jtag/drivers/amt_jtagaccel.c b/src/jtag/drivers/amt_jtagaccel.c index 80254ff..633c204 100644 --- a/src/jtag/drivers/amt_jtagaccel.c +++ b/src/jtag/drivers/amt_jtagaccel.c @@ -579,7 +579,8 @@ static struct jtag_interface amt_jtagaccel_interface = { struct adapter_driver amt_jtagaccel_adapter_driver = { .name = "amt_jtagaccel", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = amtjtagaccel_command_handlers, .init = amt_jtagaccel_init, diff --git a/src/jtag/drivers/angie.c b/src/jtag/drivers/angie.c index 46a4c82..56a118e 100644 --- a/src/jtag/drivers/angie.c +++ b/src/jtag/drivers/angie.c @@ -2388,7 +2388,8 @@ static struct jtag_interface angie_interface = { struct adapter_driver angie_adapter_driver = { .name = "angie", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .init = angie_init, .quit = angie_quit, diff --git a/src/jtag/drivers/arm-jtag-ew.c b/src/jtag/drivers/arm-jtag-ew.c index 45e0384..9d8c592 100644 --- a/src/jtag/drivers/arm-jtag-ew.c +++ b/src/jtag/drivers/arm-jtag-ew.c @@ -486,7 +486,8 @@ static struct jtag_interface armjtagew_interface = { struct adapter_driver armjtagew_adapter_driver = { .name = "arm-jtag-ew", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = armjtagew_command_handlers, .init = armjtagew_init, diff --git a/src/jtag/drivers/at91rm9200.c b/src/jtag/drivers/at91rm9200.c index a77e29a..ddcf857 100644 --- a/src/jtag/drivers/at91rm9200.c +++ b/src/jtag/drivers/at91rm9200.c @@ -186,7 +186,8 @@ static struct jtag_interface at91rm9200_interface = { struct adapter_driver at91rm9200_adapter_driver = { .name = "at91rm9200", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = at91rm9200_command_handlers, .init = at91rm9200_init, diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index e8689aa..1a105aa 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -590,15 +590,14 @@ static int bcm2835gpio_quit(void) } -static const char * const bcm2835_transports[] = { "jtag", "swd", NULL }; - static struct jtag_interface bcm2835gpio_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, }; struct adapter_driver bcm2835gpio_adapter_driver = { .name = "bcm2835gpio", - .transports = bcm2835_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = bcm2835gpio_command_handlers, .init = bcm2835gpio_init, diff --git a/src/jtag/drivers/buspirate.c b/src/jtag/drivers/buspirate.c index 93f0ba3..4283616 100644 --- a/src/jtag/drivers/buspirate.c +++ b/src/jtag/drivers/buspirate.c @@ -534,15 +534,14 @@ static const struct swd_driver buspirate_swd = { .run = buspirate_swd_run_queue, }; -static const char * const buspirate_transports[] = { "jtag", "swd", NULL }; - static struct jtag_interface buspirate_interface = { .execute_queue = buspirate_execute_queue, }; struct adapter_driver buspirate_adapter_driver = { .name = "buspirate", - .transports = buspirate_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = buspirate_command_handlers, .init = buspirate_init, diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c index be9ebae..2bfcfcc 100644 --- a/src/jtag/drivers/cmsis_dap.c +++ b/src/jtag/drivers/cmsis_dap.c @@ -2314,8 +2314,6 @@ static const struct swd_driver cmsis_dap_swd_driver = { .run = cmsis_dap_swd_run_queue, }; -static const char * const cmsis_dap_transport[] = { "swd", "jtag", NULL }; - static struct jtag_interface cmsis_dap_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = cmsis_dap_execute_queue, @@ -2323,7 +2321,8 @@ static struct jtag_interface cmsis_dap_interface = { struct adapter_driver cmsis_dap_adapter_driver = { .name = "cmsis-dap", - .transports = cmsis_dap_transport, + .transport_ids = TRANSPORT_SWD | TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_SWD, .commands = cmsis_dap_command_handlers, .init = cmsis_dap_init, diff --git a/src/jtag/drivers/dmem.c b/src/jtag/drivers/dmem.c index 4dc5821..e50e84a 100644 --- a/src/jtag/drivers/dmem.c +++ b/src/jtag/drivers/dmem.c @@ -604,11 +604,10 @@ static const struct dap_ops dmem_dap_ops = { .run = dmem_dp_run, }; -static const char *const dmem_dap_transport[] = { "dapdirect_swd", NULL }; - struct adapter_driver dmem_dap_adapter_driver = { .name = "dmem", - .transports = dmem_dap_transport, + .transport_ids = TRANSPORT_DAPDIRECT_SWD, + .transport_preferred_id = TRANSPORT_DAPDIRECT_SWD, .commands = dmem_dap_command_handlers, .init = dmem_dap_init, diff --git a/src/jtag/drivers/dummy.c b/src/jtag/drivers/dummy.c index 79b29fb..471668c 100644 --- a/src/jtag/drivers/dummy.c +++ b/src/jtag/drivers/dummy.c @@ -140,7 +140,8 @@ static struct jtag_interface dummy_interface = { struct adapter_driver dummy_adapter_driver = { .name = "dummy", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = dummy_command_handlers, .init = &dummy_init, diff --git a/src/jtag/drivers/ep93xx.c b/src/jtag/drivers/ep93xx.c index ea9faf1..f3e1676 100644 --- a/src/jtag/drivers/ep93xx.c +++ b/src/jtag/drivers/ep93xx.c @@ -46,7 +46,8 @@ static struct jtag_interface ep93xx_interface = { struct adapter_driver ep93xx_adapter_driver = { .name = "ep93xx", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .init = ep93xx_init, .quit = ep93xx_quit, diff --git a/src/jtag/drivers/esp_usb_jtag.c b/src/jtag/drivers/esp_usb_jtag.c index 9504059..a133035 100644 --- a/src/jtag/drivers/esp_usb_jtag.c +++ b/src/jtag/drivers/esp_usb_jtag.c @@ -784,7 +784,8 @@ static struct jtag_interface esp_usb_jtag_interface = { struct adapter_driver esp_usb_adapter_driver = { .name = "esp_usb_jtag", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = esp_usb_jtag_commands, .init = esp_usb_jtag_init, diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c index f4e5af4..f88e4b9 100644 --- a/src/jtag/drivers/ft232r.c +++ b/src/jtag/drivers/ft232r.c @@ -900,7 +900,8 @@ static struct jtag_interface ft232r_interface = { struct adapter_driver ft232r_adapter_driver = { .name = "ft232r", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = ft232r_command_handlers, .init = ft232r_init, diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index f56a517..2c3339e 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -1665,8 +1665,6 @@ static const struct swd_driver ftdi_swd = { .run = ftdi_swd_run_queue, }; -static const char * const ftdi_transports[] = { "jtag", "swd", NULL }; - static struct jtag_interface ftdi_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = ftdi_execute_queue, @@ -1674,7 +1672,8 @@ static struct jtag_interface ftdi_interface = { struct adapter_driver ftdi_adapter_driver = { .name = "ftdi", - .transports = ftdi_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = ftdi_command_handlers, .init = ftdi_initialize, diff --git a/src/jtag/drivers/gw16012.c b/src/jtag/drivers/gw16012.c index 7200e75..805065f 100644 --- a/src/jtag/drivers/gw16012.c +++ b/src/jtag/drivers/gw16012.c @@ -514,7 +514,8 @@ static struct jtag_interface gw16012_interface = { struct adapter_driver gw16012_adapter_driver = { .name = "gw16012", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = gw16012_command_handlers, .init = gw16012_init, diff --git a/src/jtag/drivers/imx_gpio.c b/src/jtag/drivers/imx_gpio.c index 18dc2dd..a4a76ca 100644 --- a/src/jtag/drivers/imx_gpio.c +++ b/src/jtag/drivers/imx_gpio.c @@ -417,8 +417,6 @@ static const struct command_registration imx_gpio_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -static const char * const imx_gpio_transports[] = { "jtag", "swd", NULL }; - static struct jtag_interface imx_gpio_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, @@ -426,7 +424,8 @@ static struct jtag_interface imx_gpio_interface = { struct adapter_driver imx_gpio_adapter_driver = { .name = "imx_gpio", - .transports = imx_gpio_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = imx_gpio_command_handlers, .init = imx_gpio_init, diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 4d15cf5..9caf37f 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -2264,15 +2264,14 @@ static const struct swd_driver jlink_swd = { .run = &jlink_swd_run_queue, }; -static const char * const jlink_transports[] = { "jtag", "swd", NULL }; - static struct jtag_interface jlink_interface = { .execute_queue = &jlink_execute_queue, }; struct adapter_driver jlink_adapter_driver = { .name = "jlink", - .transports = jlink_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = jlink_command_handlers, .init = &jlink_init, diff --git a/src/jtag/drivers/jtag_dpi.c b/src/jtag/drivers/jtag_dpi.c index 046186a..d6418d3 100644 --- a/src/jtag/drivers/jtag_dpi.c +++ b/src/jtag/drivers/jtag_dpi.c @@ -398,7 +398,8 @@ static struct jtag_interface jtag_dpi_interface = { struct adapter_driver jtag_dpi_adapter_driver = { .name = "jtag_dpi", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = jtag_dpi_command_handlers, .init = jtag_dpi_init, .quit = jtag_dpi_quit, diff --git a/src/jtag/drivers/jtag_vpi.c b/src/jtag/drivers/jtag_vpi.c index f6cb3de..fac27b3 100644 --- a/src/jtag/drivers/jtag_vpi.c +++ b/src/jtag/drivers/jtag_vpi.c @@ -666,7 +666,8 @@ static struct jtag_interface jtag_vpi_interface = { struct adapter_driver jtag_vpi_adapter_driver = { .name = "jtag_vpi", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = jtag_vpi_command_handlers, .init = jtag_vpi_init, diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c index 98b0d16..88e301c 100644 --- a/src/jtag/drivers/kitprog.c +++ b/src/jtag/drivers/kitprog.c @@ -908,11 +908,10 @@ static const struct swd_driver kitprog_swd = { .run = kitprog_swd_run_queue, }; -static const char * const kitprog_transports[] = { "swd", NULL }; - struct adapter_driver kitprog_adapter_driver = { .name = "kitprog", - .transports = kitprog_transports, + .transport_ids = TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_SWD, .commands = kitprog_command_handlers, .init = kitprog_init, diff --git a/src/jtag/drivers/linuxgpiod.c b/src/jtag/drivers/linuxgpiod.c index eda7b1a..36c7e04 100644 --- a/src/jtag/drivers/linuxgpiod.c +++ b/src/jtag/drivers/linuxgpiod.c @@ -425,8 +425,6 @@ out_error: return ERROR_JTAG_INIT_FAILED; } -static const char *const linuxgpiod_transport[] = { "swd", "jtag", NULL }; - static struct jtag_interface linuxgpiod_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, @@ -434,7 +432,8 @@ static struct jtag_interface linuxgpiod_interface = { struct adapter_driver linuxgpiod_adapter_driver = { .name = "linuxgpiod", - .transports = linuxgpiod_transport, + .transport_ids = TRANSPORT_SWD | TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_SWD, .init = linuxgpiod_init, .quit = linuxgpiod_quit, diff --git a/src/jtag/drivers/linuxspidev.c b/src/jtag/drivers/linuxspidev.c index 18abdc7..396f1a1 100644 --- a/src/jtag/drivers/linuxspidev.c +++ b/src/jtag/drivers/linuxspidev.c @@ -616,12 +616,10 @@ static const struct command_registration spidev_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -// Only SWD transport supported -static const char *const spidev_transports[] = { "swd", NULL }; - struct adapter_driver linuxspidev_adapter_driver = { .name = "linuxspidev", - .transports = spidev_transports, + .transport_ids = TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_SWD, .commands = spidev_command_handlers, .init = spidev_init, diff --git a/src/jtag/drivers/opendous.c b/src/jtag/drivers/opendous.c index 999afb3..04626cb 100644 --- a/src/jtag/drivers/opendous.c +++ b/src/jtag/drivers/opendous.c @@ -229,7 +229,8 @@ static struct jtag_interface opendous_interface = { struct adapter_driver opendous_adapter_driver = { .name = "opendous", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = opendous_command_handlers, .init = opendous_init, diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c index 14bcc17..943ad85 100644 --- a/src/jtag/drivers/openjtag.c +++ b/src/jtag/drivers/openjtag.c @@ -931,7 +931,8 @@ static struct jtag_interface openjtag_interface = { struct adapter_driver openjtag_adapter_driver = { .name = "openjtag", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = openjtag_command_handlers, .init = openjtag_init, diff --git a/src/jtag/drivers/osbdm.c b/src/jtag/drivers/osbdm.c index 80f66d1..de2e1f8 100644 --- a/src/jtag/drivers/osbdm.c +++ b/src/jtag/drivers/osbdm.c @@ -684,7 +684,8 @@ static struct jtag_interface osbdm_interface = { struct adapter_driver osbdm_adapter_driver = { .name = "osbdm", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .init = osbdm_init, .quit = osbdm_quit, diff --git a/src/jtag/drivers/parport.c b/src/jtag/drivers/parport.c index 3b20fe2..143f3bd 100644 --- a/src/jtag/drivers/parport.c +++ b/src/jtag/drivers/parport.c @@ -533,7 +533,8 @@ static struct jtag_interface parport_interface = { struct adapter_driver parport_adapter_driver = { .name = "parport", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = parport_command_handlers, .init = parport_init, diff --git a/src/jtag/drivers/presto.c b/src/jtag/drivers/presto.c index f6e13f7..84b881c 100644 --- a/src/jtag/drivers/presto.c +++ b/src/jtag/drivers/presto.c @@ -528,7 +528,8 @@ static struct jtag_interface presto_interface = { struct adapter_driver presto_adapter_driver = { .name = "presto", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .init = presto_jtag_init, .quit = presto_jtag_quit, diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c index bb608ba..449c616 100644 --- a/src/jtag/drivers/remote_bitbang.c +++ b/src/jtag/drivers/remote_bitbang.c @@ -412,8 +412,6 @@ COMMAND_HANDLER(remote_bitbang_handle_remote_bitbang_host_command) return ERROR_COMMAND_SYNTAX_ERROR; } -static const char * const remote_bitbang_transports[] = { "jtag", "swd", NULL }; - COMMAND_HANDLER(remote_bitbang_handle_remote_bitbang_use_remote_sleep_command) { if (CMD_ARGC != 1) @@ -484,7 +482,8 @@ static struct jtag_interface remote_bitbang_interface = { struct adapter_driver remote_bitbang_adapter_driver = { .name = "remote_bitbang", - .transports = remote_bitbang_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = remote_bitbang_command_handlers, .init = &remote_bitbang_init, diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c index 6ea3729..a818996 100644 --- a/src/jtag/drivers/rlink.c +++ b/src/jtag/drivers/rlink.c @@ -1675,7 +1675,8 @@ static struct jtag_interface rlink_interface = { struct adapter_driver rlink_adapter_driver = { .name = "rlink", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .init = rlink_init, .quit = rlink_quit, diff --git a/src/jtag/drivers/rshim.c b/src/jtag/drivers/rshim.c index b37fe8c..89bdadd 100644 --- a/src/jtag/drivers/rshim.c +++ b/src/jtag/drivers/rshim.c @@ -508,11 +508,10 @@ static const struct dap_ops rshim_dap_ops = { .quit = rshim_disconnect, }; -static const char *const rshim_dap_transport[] = { "dapdirect_swd", NULL }; - struct adapter_driver rshim_dap_adapter_driver = { .name = "rshim", - .transports = rshim_dap_transport, + .transport_ids = TRANSPORT_DAPDIRECT_SWD, + .transport_preferred_id = TRANSPORT_DAPDIRECT_SWD, .commands = rshim_dap_command_handlers, .init = rshim_dap_init, diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index d77f28b..5ee1f85 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -5143,7 +5143,12 @@ static int stlink_dap_init(void) if ((mode != STLINK_MODE_DEBUG_SWIM) && !(stlink_dap_handle->version.flags & STLINK_F_HAS_DAP_REG)) { - LOG_ERROR("ST-Link version does not support DAP direct transport"); + LOG_ERROR("The firmware in the ST-Link adapter only supports deprecated HLA."); + LOG_ERROR("Please consider updating the ST-Link firmware with a version"); + LOG_ERROR("newer that V2J24 (2015), available for downloading on ST website:"); + LOG_ERROR(" https://www.st.com/en/development-tools/stsw-link007.html"); + LOG_ERROR("In mean time, you can re-run OpenOCD for ST-Link HLA as:"); + LOG_ERROR(" openocd -f interface/stlink-hla.cfg ..."); return ERROR_FAIL; } return ERROR_OK; @@ -5217,11 +5222,10 @@ static const struct swim_driver stlink_swim_ops = { .reconnect = stlink_swim_op_reconnect, }; -static const char *const stlink_dap_transport[] = { "dapdirect_swd", "dapdirect_jtag", "swim", NULL }; - struct adapter_driver stlink_dap_adapter_driver = { .name = "st-link", - .transports = stlink_dap_transport, + .transport_ids = TRANSPORT_DAPDIRECT_SWD | TRANSPORT_DAPDIRECT_JTAG | TRANSPORT_SWIM, + .transport_preferred_id = TRANSPORT_DAPDIRECT_SWD, .commands = stlink_dap_command_handlers, .init = stlink_dap_init, diff --git a/src/jtag/drivers/sysfsgpio.c b/src/jtag/drivers/sysfsgpio.c index ccd3974..279b353 100644 --- a/src/jtag/drivers/sysfsgpio.c +++ b/src/jtag/drivers/sysfsgpio.c @@ -545,8 +545,6 @@ static const struct command_registration sysfsgpio_command_handlers[] = { static int sysfsgpio_init(void); static int sysfsgpio_quit(void); -static const char * const sysfsgpio_transports[] = { "jtag", "swd", NULL }; - static struct jtag_interface sysfsgpio_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, @@ -554,7 +552,8 @@ static struct jtag_interface sysfsgpio_interface = { struct adapter_driver sysfsgpio_adapter_driver = { .name = "sysfsgpio", - .transports = sysfsgpio_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = sysfsgpio_command_handlers, .init = sysfsgpio_init, diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index 0a13bf6..417d560 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -2271,7 +2271,8 @@ static struct jtag_interface ulink_interface = { struct adapter_driver ulink_adapter_driver = { .name = "ulink", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = ulink_command_handlers, .init = ulink_init, diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c b/src/jtag/drivers/usb_blaster/usb_blaster.c index 1782cc4..8134466 100644 --- a/src/jtag/drivers/usb_blaster/usb_blaster.c +++ b/src/jtag/drivers/usb_blaster/usb_blaster.c @@ -1057,7 +1057,8 @@ static struct jtag_interface usb_blaster_interface = { struct adapter_driver usb_blaster_adapter_driver = { .name = "usb_blaster", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = ublast_command_handlers, .init = ublast_init, diff --git a/src/jtag/drivers/usbprog.c b/src/jtag/drivers/usbprog.c index 24407f0..264b45f 100644 --- a/src/jtag/drivers/usbprog.c +++ b/src/jtag/drivers/usbprog.c @@ -590,7 +590,8 @@ static struct jtag_interface usbprog_interface = { struct adapter_driver usbprog_adapter_driver = { .name = "usbprog", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .init = usbprog_init, .quit = usbprog_quit, diff --git a/src/jtag/drivers/vdebug.c b/src/jtag/drivers/vdebug.c index fd1e6a7..3868595 100644 --- a/src/jtag/drivers/vdebug.c +++ b/src/jtag/drivers/vdebug.c @@ -1342,11 +1342,10 @@ static const struct dap_ops vdebug_dap_ops = { .quit = NULL, /* optional */ }; -static const char *const vdebug_transports[] = { "jtag", "dapdirect_swd", NULL }; - struct adapter_driver vdebug_adapter_driver = { .name = "vdebug", - .transports = vdebug_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_DAPDIRECT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .speed = vdebug_jtag_speed, .khz = vdebug_jtag_khz, .speed_div = vdebug_jtag_div, diff --git a/src/jtag/drivers/vsllink.c b/src/jtag/drivers/vsllink.c index c10ed13..145f068 100644 --- a/src/jtag/drivers/vsllink.c +++ b/src/jtag/drivers/vsllink.c @@ -913,8 +913,6 @@ static const struct command_registration vsllink_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -static const char * const vsllink_transports[] = {"jtag", "swd", NULL}; - static const struct swd_driver vsllink_swd_driver = { .init = vsllink_swd_init, .switch_seq = vsllink_swd_switch_seq, @@ -930,7 +928,8 @@ static struct jtag_interface vsllink_interface = { struct adapter_driver vsllink_adapter_driver = { .name = "vsllink", - .transports = vsllink_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = vsllink_command_handlers, .init = vsllink_init, diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c index c843710..d1bb705 100644 --- a/src/jtag/drivers/xds110.c +++ b/src/jtag/drivers/xds110.c @@ -2058,15 +2058,14 @@ static const struct swd_driver xds110_swd_driver = { .run = xds110_swd_run_queue, }; -static const char * const xds110_transport[] = { "swd", "jtag", NULL }; - static struct jtag_interface xds110_interface = { .execute_queue = xds110_execute_queue, }; struct adapter_driver xds110_adapter_driver = { .name = "xds110", - .transports = xds110_transport, + .transport_ids = TRANSPORT_SWD | TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_SWD, .commands = xds110_command_handlers, .init = xds110_init, diff --git a/src/jtag/drivers/xlnx-pcie-xvc.c b/src/jtag/drivers/xlnx-pcie-xvc.c index 37c6777..3baa183 100644 --- a/src/jtag/drivers/xlnx-pcie-xvc.c +++ b/src/jtag/drivers/xlnx-pcie-xvc.c @@ -690,11 +690,10 @@ static const struct swd_driver xlnx_pcie_xvc_swd_ops = { .run = xlnx_pcie_xvc_swd_run_queue, }; -static const char * const xlnx_pcie_xvc_transports[] = { "jtag", "swd", NULL }; - struct adapter_driver xlnx_pcie_xvc_adapter_driver = { .name = "xlnx_pcie_xvc", - .transports = xlnx_pcie_xvc_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = xlnx_pcie_xvc_command_handlers, .init = &xlnx_pcie_xvc_init, diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c index 96862b0..a9d196c 100644 --- a/src/jtag/hla/hla_interface.c +++ b/src/jtag/hla/hla_interface.c @@ -367,7 +367,8 @@ static const struct command_registration hl_interface_command_handlers[] = { struct adapter_driver hl_adapter_driver = { .name = "hla", - .transports = hl_transports, + .transport_ids = TRANSPORT_HLA_SWD | TRANSPORT_HLA_JTAG, + .transport_preferred_id = TRANSPORT_HLA_SWD, .commands = hl_interface_command_handlers, .init = hl_interface_init, diff --git a/src/jtag/hla/hla_interface.h b/src/jtag/hla/hla_interface.h index f1550d9..c0ee054 100644 --- a/src/jtag/hla/hla_interface.h +++ b/src/jtag/hla/hla_interface.h @@ -15,8 +15,6 @@ struct target; /** */ enum e_hl_transports; -/** */ -extern const char *hl_transports[]; #define HLA_MAX_USB_IDS 16 diff --git a/src/jtag/hla/hla_transport.c b/src/jtag/hla/hla_transport.c index b826eb0..d8ece07 100644 --- a/src/jtag/hla/hla_transport.c +++ b/src/jtag/hla/hla_transport.c @@ -177,15 +177,20 @@ static int hl_transport_init(struct command_context *cmd_ctx) return ERROR_FAIL; } - LOG_DEBUG("current transport %s", transport->name); + LOG_DEBUG("current transport %s", get_current_transport_name()); /* get selected transport as enum */ - tr = HL_TRANSPORT_UNKNOWN; - - if (strcmp(transport->name, "hla_swd") == 0) + switch (transport->id) { + case TRANSPORT_HLA_SWD: tr = HL_TRANSPORT_SWD; - else if (strcmp(transport->name, "hla_jtag") == 0) + break; + case TRANSPORT_HLA_JTAG: tr = HL_TRANSPORT_JTAG; + break; + default: + tr = HL_TRANSPORT_UNKNOWN; + break; + } int retval = hl_interface_open(tr); @@ -213,21 +218,19 @@ static int hl_swd_transport_select(struct command_context *cmd_ctx) } static struct transport hl_swd_transport = { - .name = "hla_swd", + .id = TRANSPORT_HLA_SWD, .select = hl_swd_transport_select, .init = hl_transport_init, .override_target = hl_interface_override_target, }; static struct transport hl_jtag_transport = { - .name = "hla_jtag", + .id = TRANSPORT_HLA_JTAG, .select = hl_jtag_transport_select, .init = hl_transport_init, .override_target = hl_interface_override_target, }; -const char *hl_transports[] = { "hla_swd", "hla_jtag", NULL }; - static void hl_constructor(void) __attribute__ ((constructor)); static void hl_constructor(void) { diff --git a/src/jtag/interface.h b/src/jtag/interface.h index b2d7123..475dbed 100644 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -17,6 +17,7 @@ #include <jtag/jtag.h> #include <jtag/swim.h> #include <target/arm_tpiu_swo.h> +#include <transport/transport.h> /* @file * The "Cable Helper API" is what the cable drivers can use to help @@ -208,8 +209,16 @@ struct adapter_driver { /** The name of the interface driver. */ const char * const name; - /** transports supported in C code (NULL terminated vector) */ - const char * const *transports; + /** + * Bitmask of transport IDs supported in C code. + */ + unsigned int transport_ids; + + /** + * ID of transport that gets auto-selected when not specified by the user. + * The auto-selection of transport is DEPRECATED. + */ + unsigned int transport_preferred_id; /** * The interface driver may register additional commands to expose @@ -354,8 +363,6 @@ struct adapter_driver { const struct swim_driver *swim_ops; }; -extern const char * const jtag_only[]; - int adapter_resets(int assert_trst, int assert_srst); int adapter_assert_reset(void); int adapter_deassert_reset(void); diff --git a/src/jtag/swim.c b/src/jtag/swim.c index de3e106..004a9fd 100644 --- a/src/jtag/swim.c +++ b/src/jtag/swim.c @@ -136,7 +136,7 @@ static int swim_transport_init(struct command_context *cmd_ctx) } static struct transport swim_transport = { - .name = "swim", + .id = TRANSPORT_SWIM, .select = swim_transport_select, .init = swim_transport_init, }; diff --git a/src/target/Makefile.am b/src/target/Makefile.am index 1fc7d2a..1a76864 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -224,7 +224,6 @@ ARC_SRC = \ %D%/avr32_mem.h \ %D%/avr32_regs.h \ %D%/semihosting_common.h \ - %D%/stm8.h \ %D%/lakemont.h \ %D%/x86_32_common.h \ %D%/arm_cti.h \ diff --git a/src/target/aarch64.c b/src/target/aarch64.c index ce7808e..101cb14 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -2814,7 +2814,7 @@ static int aarch64_init_arch_info(struct target *target, return ERROR_OK; } -static int armv8r_target_create(struct target *target, Jim_Interp *interp) +static int armv8r_target_create(struct target *target) { struct aarch64_private_config *pc = target->private_config; struct aarch64_common *aarch64; @@ -2833,7 +2833,7 @@ static int armv8r_target_create(struct target *target, Jim_Interp *interp) return aarch64_init_arch_info(target, aarch64, pc->adiv5_config.dap); } -static int aarch64_target_create(struct target *target, Jim_Interp *interp) +static int aarch64_target_create(struct target *target) { struct aarch64_private_config *pc = target->private_config; struct aarch64_common *aarch64; diff --git a/src/target/adi_v5_dapdirect.c b/src/target/adi_v5_dapdirect.c index d198dac..07ea313 100644 --- a/src/target/adi_v5_dapdirect.c +++ b/src/target/adi_v5_dapdirect.c @@ -207,13 +207,13 @@ static int dapdirect_init(struct command_context *ctx) } static struct transport dapdirect_jtag_transport = { - .name = "dapdirect_jtag", + .id = TRANSPORT_DAPDIRECT_JTAG, .select = dapdirect_jtag_select, .init = dapdirect_init, }; static struct transport dapdirect_swd_transport = { - .name = "dapdirect_swd", + .id = TRANSPORT_DAPDIRECT_SWD, .select = dapdirect_swd_select, .init = dapdirect_init, }; diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index e50f8f1..2d28613 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -756,7 +756,7 @@ static int swd_init(struct command_context *ctx) } static struct transport swd_transport = { - .name = "swd", + .id = TRANSPORT_SWD, .select = swd_select, .init = swd_init, }; diff --git a/src/target/arc.c b/src/target/arc.c index 8757caf..f2482c2 100644 --- a/src/target/arc.c +++ b/src/target/arc.c @@ -1424,7 +1424,7 @@ static void arc_deinit_target(struct target *target) } -static int arc_target_create(struct target *target, Jim_Interp *interp) +static int arc_target_create(struct target *target) { struct arc_common *arc = calloc(1, sizeof(*arc)); diff --git a/src/target/arm11.c b/src/target/arm11.c index 756b36b..583830f 100644 --- a/src/target/arm11.c +++ b/src/target/arm11.c @@ -1079,7 +1079,7 @@ static int arm11_remove_breakpoint(struct target *target, return ERROR_OK; } -static int arm11_target_create(struct target *target, Jim_Interp *interp) +static int arm11_target_create(struct target *target) { struct arm11_common *arm11; diff --git a/src/target/arm720t.c b/src/target/arm720t.c index beab632..d1433dd 100644 --- a/src/target/arm720t.c +++ b/src/target/arm720t.c @@ -412,7 +412,7 @@ static int arm720t_init_arch_info(struct target *target, return ERROR_OK; } -static int arm720t_target_create(struct target *target, Jim_Interp *interp) +static int arm720t_target_create(struct target *target) { struct arm720t_common *arm720t = calloc(1, sizeof(*arm720t)); diff --git a/src/target/arm7tdmi.c b/src/target/arm7tdmi.c index 393d3b4..2f59254 100644 --- a/src/target/arm7tdmi.c +++ b/src/target/arm7tdmi.c @@ -669,7 +669,7 @@ int arm7tdmi_init_arch_info(struct target *target, return ERROR_OK; } -static int arm7tdmi_target_create(struct target *target, Jim_Interp *interp) +static int arm7tdmi_target_create(struct target *target) { struct arm7_9_common *arm7_9; diff --git a/src/target/arm920t.c b/src/target/arm920t.c index 53b4d9d..95cfd7c 100644 --- a/src/target/arm920t.c +++ b/src/target/arm920t.c @@ -833,7 +833,7 @@ static int arm920t_init_arch_info(struct target *target, return ERROR_OK; } -static int arm920t_target_create(struct target *target, Jim_Interp *interp) +static int arm920t_target_create(struct target *target) { struct arm920t_common *arm920t; diff --git a/src/target/arm926ejs.c b/src/target/arm926ejs.c index add90c9..0531106 100644 --- a/src/target/arm926ejs.c +++ b/src/target/arm926ejs.c @@ -702,7 +702,7 @@ int arm926ejs_init_arch_info(struct target *target, struct arm926ejs_common *arm return ERROR_OK; } -static int arm926ejs_target_create(struct target *target, Jim_Interp *interp) +static int arm926ejs_target_create(struct target *target) { struct arm926ejs_common *arm926ejs = calloc(1, sizeof(struct arm926ejs_common)); diff --git a/src/target/arm946e.c b/src/target/arm946e.c index 03f7e44..828e70f 100644 --- a/src/target/arm946e.c +++ b/src/target/arm946e.c @@ -79,7 +79,7 @@ static int arm946e_init_arch_info(struct target *target, return ERROR_OK; } -static int arm946e_target_create(struct target *target, Jim_Interp *interp) +static int arm946e_target_create(struct target *target) { struct arm946e_common *arm946e = calloc(1, sizeof(struct arm946e_common)); diff --git a/src/target/arm966e.c b/src/target/arm966e.c index 8598d29..b6bcc8b 100644 --- a/src/target/arm966e.c +++ b/src/target/arm966e.c @@ -38,7 +38,7 @@ int arm966e_init_arch_info(struct target *target, struct arm966e_common *arm966e return ERROR_OK; } -static int arm966e_target_create(struct target *target, Jim_Interp *interp) +static int arm966e_target_create(struct target *target) { struct arm966e_common *arm966e = calloc(1, sizeof(struct arm966e_common)); diff --git a/src/target/arm9tdmi.c b/src/target/arm9tdmi.c index 7e31306..8ab12de 100644 --- a/src/target/arm9tdmi.c +++ b/src/target/arm9tdmi.c @@ -765,7 +765,7 @@ int arm9tdmi_init_arch_info(struct target *target, return ERROR_OK; } -static int arm9tdmi_target_create(struct target *target, Jim_Interp *interp) +static int arm9tdmi_target_create(struct target *target) { struct arm7_9_common *arm7_9 = calloc(1, sizeof(struct arm7_9_common)); diff --git a/src/target/avr32_ap7k.c b/src/target/avr32_ap7k.c index 1b051dc..94962c2 100644 --- a/src/target/avr32_ap7k.c +++ b/src/target/avr32_ap7k.c @@ -510,7 +510,7 @@ static int avr32_ap7k_init_target(struct command_context *cmd_ctx, return ERROR_OK; } -static int avr32_ap7k_target_create(struct target *target, Jim_Interp *interp) +static int avr32_ap7k_target_create(struct target *target) { struct avr32_ap7k_common *ap7k = calloc(1, sizeof(struct avr32_ap7k_common)); diff --git a/src/target/avrt.c b/src/target/avrt.c index 3afe320..e25718b 100644 --- a/src/target/avrt.c +++ b/src/target/avrt.c @@ -16,7 +16,7 @@ #define AVR_JTAG_INS_LEN 4 /* forward declarations */ -static int avr_target_create(struct target *target, Jim_Interp *interp); +static int avr_target_create(struct target *target); static int avr_init_target(struct command_context *cmd_ctx, struct target *target); static int avr_arch_state(struct target *target); @@ -68,7 +68,7 @@ struct target_type avr_target = { .init_target = avr_init_target, }; -static int avr_target_create(struct target *target, Jim_Interp *interp) +static int avr_target_create(struct target *target) { struct avr_common *avr = calloc(1, sizeof(struct avr_common)); diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 9c60645..ee27e1b 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -3126,7 +3126,7 @@ static int cortex_a_init_arch_info(struct target *target, return ERROR_OK; } -static int cortex_a_target_create(struct target *target, Jim_Interp *interp) +static int cortex_a_target_create(struct target *target) { struct cortex_a_common *cortex_a; struct adiv5_private_config *pc; @@ -3148,7 +3148,7 @@ static int cortex_a_target_create(struct target *target, Jim_Interp *interp) return cortex_a_init_arch_info(target, cortex_a, pc->dap); } -static int cortex_r4_target_create(struct target *target, Jim_Interp *interp) +static int cortex_r4_target_create(struct target *target) { struct cortex_a_common *cortex_a; struct adiv5_private_config *pc; diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index e17f23c..ba9d83d 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -2916,7 +2916,7 @@ static int cortex_m_init_arch_info(struct target *target, return ERROR_OK; } -static int cortex_m_target_create(struct target *target, Jim_Interp *interp) +static int cortex_m_target_create(struct target *target) { struct adiv5_private_config *pc; diff --git a/src/target/dsp563xx.c b/src/target/dsp563xx.c index 629056f..8198438 100644 --- a/src/target/dsp563xx.c +++ b/src/target/dsp563xx.c @@ -880,7 +880,7 @@ static void dsp563xx_invalidate_x_context(struct target *target, } } -static int dsp563xx_target_create(struct target *target, Jim_Interp *interp) +static int dsp563xx_target_create(struct target *target) { struct dsp563xx_common *dsp563xx = calloc(1, sizeof(struct dsp563xx_common)); diff --git a/src/target/dsp5680xx.c b/src/target/dsp5680xx.c index 3f9a674..65efbae 100644 --- a/src/target/dsp5680xx.c +++ b/src/target/dsp5680xx.c @@ -855,7 +855,7 @@ static int eonce_pc_store(struct target *target) return ERROR_OK; } -static int dsp5680xx_target_create(struct target *target, Jim_Interp *interp) +static int dsp5680xx_target_create(struct target *target) { struct dsp5680xx_common *dsp5680xx = calloc(1, sizeof(struct dsp5680xx_common)); diff --git a/src/target/esirisc.c b/src/target/esirisc.c index da40928..fac5dc7 100644 --- a/src/target/esirisc.c +++ b/src/target/esirisc.c @@ -1575,7 +1575,7 @@ static int esirisc_identify(struct target *target) return ERROR_OK; } -static int esirisc_target_create(struct target *target, Jim_Interp *interp) +static int esirisc_target_create(struct target *target) { struct jtag_tap *tap = target->tap; struct esirisc_common *esirisc; diff --git a/src/target/espressif/esp32.c b/src/target/espressif/esp32.c index 4deb5e0..399ba8e 100644 --- a/src/target/espressif/esp32.c +++ b/src/target/espressif/esp32.c @@ -326,7 +326,7 @@ static const struct esp_semihost_ops esp32_semihost_ops = { .prepare = esp32_disable_wdts }; -static int esp32_target_create(struct target *target, Jim_Interp *interp) +static int esp32_target_create(struct target *target) { struct xtensa_debug_module_config esp32_dm_cfg = { .dbg_ops = &esp32_dbg_ops, diff --git a/src/target/espressif/esp32s2.c b/src/target/espressif/esp32s2.c index 4f3914f..b86e43e 100644 --- a/src/target/espressif/esp32s2.c +++ b/src/target/espressif/esp32s2.c @@ -445,7 +445,7 @@ static const struct esp_semihost_ops esp32s2_semihost_ops = { .prepare = esp32s2_disable_wdts }; -static int esp32s2_target_create(struct target *target, Jim_Interp *interp) +static int esp32s2_target_create(struct target *target) { struct xtensa_debug_module_config esp32s2_dm_cfg = { .dbg_ops = &esp32s2_dbg_ops, diff --git a/src/target/espressif/esp32s3.c b/src/target/espressif/esp32s3.c index 7507c11..82413f7 100644 --- a/src/target/espressif/esp32s3.c +++ b/src/target/espressif/esp32s3.c @@ -320,7 +320,7 @@ static const struct esp_semihost_ops esp32s3_semihost_ops = { .prepare = esp32s3_disable_wdts }; -static int esp32s3_target_create(struct target *target, Jim_Interp *interp) +static int esp32s3_target_create(struct target *target) { struct xtensa_debug_module_config esp32s3_dm_cfg = { .dbg_ops = &esp32s3_dbg_ops, diff --git a/src/target/fa526.c b/src/target/fa526.c index 38b7ab2..d832d3e 100644 --- a/src/target/fa526.c +++ b/src/target/fa526.c @@ -329,7 +329,7 @@ static int fa526_init_arch_info(struct target *target, return ERROR_OK; } -static int fa526_target_create(struct target *target, Jim_Interp *interp) +static int fa526_target_create(struct target *target) { struct arm920t_common *arm920t = calloc(1, sizeof(struct arm920t_common)); diff --git a/src/target/feroceon.c b/src/target/feroceon.c index 840ca1b..cf2c838 100644 --- a/src/target/feroceon.c +++ b/src/target/feroceon.c @@ -622,7 +622,7 @@ static void feroceon_common_setup(struct target *target) arm7_9->wp1_used_default = -1; } -static int feroceon_target_create(struct target *target, Jim_Interp *interp) +static int feroceon_target_create(struct target *target) { struct arm926ejs_common *arm926ejs = calloc(1, sizeof(struct arm926ejs_common)); @@ -640,7 +640,7 @@ static int feroceon_target_create(struct target *target, Jim_Interp *interp) return ERROR_OK; } -static int dragonite_target_create(struct target *target, Jim_Interp *interp) +static int dragonite_target_create(struct target *target) { struct arm966e_common *arm966e = calloc(1, sizeof(struct arm966e_common)); diff --git a/src/target/hla_target.c b/src/target/hla_target.c index ef05df2..983cd87 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -187,8 +187,7 @@ static int adapter_init_target(struct command_context *cmd_ctx, return ERROR_OK; } -static int adapter_target_create(struct target *target, - Jim_Interp *interp) +static int adapter_target_create(struct target *target) { LOG_DEBUG("%s", __func__); struct adiv5_private_config *pc = target->private_config; diff --git a/src/target/ls1_sap.c b/src/target/ls1_sap.c index 692f4cc..49335a8 100644 --- a/src/target/ls1_sap.c +++ b/src/target/ls1_sap.c @@ -17,7 +17,7 @@ struct ls1_sap { struct jtag_tap *tap; }; -static int ls1_sap_target_create(struct target *target, Jim_Interp *interp) +static int ls1_sap_target_create(struct target *target) { struct ls1_sap *ls1_sap = calloc(1, sizeof(struct ls1_sap)); diff --git a/src/target/mem_ap.c b/src/target/mem_ap.c index fdc52c3..c5618c9 100644 --- a/src/target/mem_ap.c +++ b/src/target/mem_ap.c @@ -24,7 +24,7 @@ struct mem_ap { uint64_t ap_num; }; -static int mem_ap_target_create(struct target *target, Jim_Interp *interp) +static int mem_ap_target_create(struct target *target) { struct mem_ap *mem_ap; struct adiv5_private_config *pc; diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index dc74501..4e27914 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -1158,7 +1158,7 @@ static int mips_m4k_init_arch_info(struct target *target, return ERROR_OK; } -static int mips_m4k_target_create(struct target *target, Jim_Interp *interp) +static int mips_m4k_target_create(struct target *target) { struct mips_m4k_common *mips_m4k = calloc(1, sizeof(struct mips_m4k_common)); diff --git a/src/target/mips_mips64.c b/src/target/mips_mips64.c index 85e3779..a181a15 100644 --- a/src/target/mips_mips64.c +++ b/src/target/mips_mips64.c @@ -1082,7 +1082,7 @@ static int mips_mips64_init_target(struct command_context *cmd_ctx, return mips64_build_reg_cache(target); } -static int mips_mips64_target_create(struct target *target, Jim_Interp *interp) +static int mips_mips64_target_create(struct target *target) { struct mips_mips64_common *mips_mips64; struct mips64_common *mips64; diff --git a/src/target/openrisc/or1k.c b/src/target/openrisc/or1k.c index 4b9d3bc..4aa2bd7 100644 --- a/src/target/openrisc/or1k.c +++ b/src/target/openrisc/or1k.c @@ -1097,7 +1097,7 @@ static int or1k_init_target(struct command_context *cmd_ctx, return ERROR_OK; } -static int or1k_target_create(struct target *target, Jim_Interp *interp) +static int or1k_target_create(struct target *target) { if (!target->tap) return ERROR_FAIL; diff --git a/src/target/quark_d20xx.c b/src/target/quark_d20xx.c index 90cf667..931f0da 100644 --- a/src/target/quark_d20xx.c +++ b/src/target/quark_d20xx.c @@ -32,7 +32,7 @@ #include "lakemont.h" #include "x86_32_common.h" -static int quark_d20xx_target_create(struct target *t, Jim_Interp *interp) +static int quark_d20xx_target_create(struct target *t) { struct x86_32_common *x86_32 = calloc(1, sizeof(struct x86_32_common)); if (!x86_32) { diff --git a/src/target/quark_x10xx.c b/src/target/quark_x10xx.c index 0daa642..2abc32a 100644 --- a/src/target/quark_x10xx.c +++ b/src/target/quark_x10xx.c @@ -40,7 +40,7 @@ #include "lakemont.h" #include "x86_32_common.h" -static int quark_x10xx_target_create(struct target *t, Jim_Interp *interp) +static int quark_x10xx_target_create(struct target *t) { struct x86_32_common *x86_32 = calloc(1, sizeof(*x86_32)); diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 2e475a5..ce0af2a 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -489,7 +489,7 @@ static struct riscv_private_config *alloc_default_riscv_private_config(void) return config; } -static int riscv_create_target(struct target *target, Jim_Interp *interp) +static int riscv_create_target(struct target *target) { LOG_TARGET_DEBUG(target, "riscv_create_target()"); struct riscv_private_config *config = target->private_config; diff --git a/src/target/stm8.c b/src/target/stm8.c index 76482e8..81c41f2 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -13,14 +13,12 @@ #include <helper/log.h> #include "target.h" #include "target_type.h" -#include "hello.h" #include "jtag/interface.h" #include "jtag/jtag.h" #include "jtag/swim.h" #include "register.h" #include "breakpoints.h" #include "algorithm.h" -#include "stm8.h" static struct reg_cache *stm8_build_reg_cache(struct target *target); static int stm8_read_core_reg(struct target *target, unsigned int num); @@ -54,6 +52,8 @@ static const struct { { 5, "cc", 8, REG_TYPE_UINT8, "general", "org.gnu.gdb.stm8.core", 0 }, }; +#define STM8_COMMON_MAGIC 0x53544D38U + #define STM8_NUM_REGS ARRAY_SIZE(stm8_regs) #define STM8_PC 0 #define STM8_A 1 @@ -168,6 +168,51 @@ struct stm8_comparator { enum hw_break_type type; }; +struct stm8_common { + unsigned int common_magic; + + void *arch_info; + struct reg_cache *core_cache; + uint32_t core_regs[STM8_NUM_REGS]; + + /* working area for fastdata access */ + struct working_area *fast_data_area; + + bool swim_configured; + bool bp_scanned; + uint8_t num_hw_bpoints; + uint8_t num_hw_bpoints_avail; + struct stm8_comparator *hw_break_list; + uint32_t blocksize; + uint32_t flashstart; + uint32_t flashend; + uint32_t eepromstart; + uint32_t eepromend; + uint32_t optionstart; + uint32_t optionend; + bool enable_step_irq; + + bool enable_stm8l; + uint32_t flash_cr2; + uint32_t flash_ncr2; + uint32_t flash_iapsr; + uint32_t flash_dukr; + uint32_t flash_pukr; + + /* cc value used for interrupt flags restore */ + uint32_t cc; + bool cc_valid; + + /* register cache to processor synchronization */ + int (*read_core_reg)(struct target *target, unsigned int num); + int (*write_core_reg)(struct target *target, unsigned int num); +}; + +static struct stm8_common *target_to_stm8(struct target *target) +{ + return target->arch_info; +} + static int stm8_adapter_read_memory(struct target *target, uint32_t addr, int size, int count, void *buf) { @@ -1106,8 +1151,7 @@ static int stm8_init_arch_info(struct target *target, return ERROR_OK; } -static int stm8_target_create(struct target *target, - Jim_Interp *interp) +static int stm8_target_create(struct target *target) { struct stm8_common *stm8 = calloc(1, sizeof(struct stm8_common)); diff --git a/src/target/stm8.h b/src/target/stm8.h deleted file mode 100644 index 55e1071..0000000 --- a/src/target/stm8.h +++ /dev/null @@ -1,63 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/* -* OpenOCD STM8 target driver -* Copyright (C) 2017 Ake Rehnman -* ake.rehnman(at)gmail.com -*/ - -#ifndef OPENOCD_TARGET_STM8_H -#define OPENOCD_TARGET_STM8_H - -struct target; - -#define STM8_COMMON_MAGIC 0x53544D38U -#define STM8_NUM_CORE_REGS 6 - -struct stm8_common { - unsigned int common_magic; - - void *arch_info; - struct reg_cache *core_cache; - uint32_t core_regs[STM8_NUM_CORE_REGS]; - - /* working area for fastdata access */ - struct working_area *fast_data_area; - - bool swim_configured; - bool bp_scanned; - uint8_t num_hw_bpoints; - uint8_t num_hw_bpoints_avail; - struct stm8_comparator *hw_break_list; - uint32_t blocksize; - uint32_t flashstart; - uint32_t flashend; - uint32_t eepromstart; - uint32_t eepromend; - uint32_t optionstart; - uint32_t optionend; - bool enable_step_irq; - - bool enable_stm8l; - uint32_t flash_cr2; - uint32_t flash_ncr2; - uint32_t flash_iapsr; - uint32_t flash_dukr; - uint32_t flash_pukr; - - /* cc value used for interrupt flags restore */ - uint32_t cc; - bool cc_valid; - - /* register cache to processor synchronization */ - int (*read_core_reg)(struct target *target, unsigned int num); - int (*write_core_reg)(struct target *target, unsigned int num); -}; - -static inline struct stm8_common * -target_to_stm8(struct target *target) -{ - return target->arch_info; -} - -#endif /* OPENOCD_TARGET_STM8_H */ diff --git a/src/target/target.c b/src/target/target.c index 442e8be..1125252 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -162,7 +162,7 @@ static const char *target_strerror_safe(int err) return n->name; } -static const struct jim_nvp nvp_target_event[] = { +static const struct nvp nvp_target_event[] = { { .value = TARGET_EVENT_GDB_HALT, .name = "gdb-halt" }, { .value = TARGET_EVENT_HALTED, .name = "halted" }, @@ -237,7 +237,7 @@ static const struct nvp nvp_target_debug_reason[] = { { .name = NULL, .value = -1 }, }; -static const struct jim_nvp nvp_target_endian[] = { +static const struct nvp nvp_target_endian[] = { { .name = "big", .value = TARGET_BIG_ENDIAN }, { .name = "little", .value = TARGET_LITTLE_ENDIAN }, { .name = "be", .value = TARGET_BIG_ENDIAN }, @@ -284,7 +284,7 @@ const char *target_state_name(const struct target *t) const char *target_event_name(enum target_event event) { const char *cp; - cp = jim_nvp_value2name_simple(nvp_target_event, event)->name; + cp = nvp_value2name(nvp_target_event, event)->name; if (!cp) { LOG_ERROR("Invalid target event: %d", (int)(event)); cp = "(*BUG*unknown*BUG*)"; @@ -2848,8 +2848,7 @@ COMMAND_HANDLER(handle_targets_command) marker, target_name(target), target_type_name(target), - jim_nvp_value2name_simple(nvp_target_endian, - target->endianness)->name, + nvp_value2name(nvp_target_endian, target->endianness)->name, target->tap->dotted_name, state); } @@ -4841,7 +4840,7 @@ enum target_cfg_param { TCFG_GDB_MAX_CONNECTIONS, }; -static struct jim_nvp nvp_config_opts[] = { +static struct nvp nvp_config_opts[] = { { .name = "-type", .value = TCFG_TYPE }, { .name = "-event", .value = TCFG_EVENT }, { .name = "-work-area-virt", .value = TCFG_WORK_AREA_VIRT }, @@ -4859,78 +4858,71 @@ static struct jim_nvp nvp_config_opts[] = { { .name = NULL, .value = -1 } }; -static int target_configure(struct jim_getopt_info *goi, struct target *target) +static COMMAND_HELPER(target_configure, struct target *target, unsigned int index, bool is_configure) { - struct jim_nvp *n; - Jim_Obj *o; - jim_wide w; - int e; + const struct nvp *n; + int retval; /* parse config or cget options ... */ - while (goi->argc > 0) { - Jim_SetEmptyResult(goi->interp); - /* jim_getopt_debug(goi); */ - + while (index < CMD_ARGC) { if (target->type->target_jim_configure) { /* target defines a configure function */ /* target gets first dibs on parameters */ - e = (*(target->type->target_jim_configure))(target, goi); + struct jim_getopt_info goi; + jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC - index, CMD_JIMTCL_ARGV + index); + goi.is_configure = is_configure; + int e = (*target->type->target_jim_configure)(target, &goi); + index = CMD_ARGC - goi.argc; if (e == JIM_OK) { /* more? */ continue; } if (e == JIM_ERR) { /* An error */ - return e; + int reslen; + const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); + if (reslen > 0) + command_print(CMD, "%s", result); + return ERROR_FAIL; } /* otherwise we 'continue' below */ } - e = jim_getopt_nvp(goi, nvp_config_opts, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(goi, nvp_config_opts, 0); - return e; + n = nvp_name2value(nvp_config_opts, CMD_ARGV[index]); + if (!n->name) { + nvp_unknown_command_print(CMD, nvp_config_opts, NULL, CMD_ARGV[index]); + return ERROR_COMMAND_ARGUMENT_INVALID; } + index++; switch (n->value) { case TCFG_TYPE: /* not settable */ - if (goi->is_configure) { - Jim_SetResultFormatted(goi->interp, - "not settable: %s", n->name); - return JIM_ERR; - } else { -no_params: - if (goi->argc != 0) { - Jim_WrongNumArgs(goi->interp, - goi->argc, goi->argv, - "NO PARAMS"); - return JIM_ERR; - } + if (is_configure) { + command_print(CMD, "not settable: %s", n->name); + return ERROR_COMMAND_ARGUMENT_INVALID; } - Jim_SetResultString(goi->interp, - target_type_name(target), -1); + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "%s", target_type_name(target)); /* loop for more */ break; + case TCFG_EVENT: - if (goi->argc == 0) { - Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ..."); - return JIM_ERR; + if (index == CMD_ARGC) { + command_print(CMD, "missing event-name"); + return ERROR_COMMAND_ARGUMENT_INVALID; } - e = jim_getopt_nvp(goi, nvp_target_event, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(goi, nvp_target_event, 1); - return e; + n = nvp_name2value(nvp_target_event, CMD_ARGV[index]); + if (!n->name) { + nvp_unknown_command_print(CMD, nvp_target_event, CMD_ARGV[index - 1], CMD_ARGV[index]); + return ERROR_COMMAND_ARGUMENT_INVALID; } + index++; - if (goi->is_configure) { - if (goi->argc != 1) { - Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?"); - return JIM_ERR; - } - } else { - if (goi->argc != 0) { - Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name?"); - return JIM_ERR; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing event-body"); + return ERROR_COMMAND_ARGUMENT_INVALID; } } @@ -4946,20 +4938,20 @@ no_params: if (&teap->list == &target->events_action) teap = NULL; - if (goi->is_configure) { + if (is_configure) { /* START_DEPRECATED_TPIU */ if (n->value == TARGET_EVENT_TRACE_CONFIG) LOG_INFO("DEPRECATED target event %s; use TPIU events {pre,post}-{enable,disable}", n->name); /* END_DEPRECATED_TPIU */ - jim_getopt_obj(goi, &o); - if (Jim_Length(o) == 0) { + if (strlen(CMD_ARGV[index]) == 0) { /* empty action, drop existing one */ if (teap) { list_del(&teap->list); Jim_DecrRefCount(teap->interp, teap->body); free(teap); } + index++; break; } @@ -4970,10 +4962,12 @@ no_params: replace = false; } teap->event = n->value; - teap->interp = goi->interp; + teap->interp = CMD_CTX->interp; if (teap->body) Jim_DecrRefCount(teap->interp, teap->body); - teap->body = Jim_DuplicateObj(goi->interp, o); + /* use jim object to keep its reference on tcl file and line */ + /* TODO: need duplicate? isn't IncrRefCount enough? */ + teap->body = Jim_DuplicateObj(teap->interp, CMD_JIMTCL_ARGV[index++]); /* * FIXME: * Tcl/TK - "tk events" have a nice feature. @@ -4990,238 +4984,278 @@ no_params: /* add to head of event list */ list_add(&teap->list, &target->events_action); } - Jim_SetEmptyResult(goi->interp); } else { - /* get */ - if (!teap) - Jim_SetEmptyResult(goi->interp); - else - Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, teap->body)); + /* cget */ + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (teap) + command_print(CMD, "%s", Jim_GetString(teap->body, NULL)); } } /* loop for more */ break; case TCFG_WORK_AREA_VIRT: - if (goi->is_configure) { - target_free_all_working_areas(target); - e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) - return e; - target->working_area_virt = w; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[index], target->working_area_virt); + index++; target->working_area_virt_spec = true; + target_free_all_working_areas(target); } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, TARGET_ADDR_FMT, target->working_area_virt); } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_virt)); /* loop for more */ break; case TCFG_WORK_AREA_PHYS: - if (goi->is_configure) { - target_free_all_working_areas(target); - e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) - return e; - target->working_area_phys = w; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[index], target->working_area_phys); + index++; target->working_area_phys_spec = true; + target_free_all_working_areas(target); } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, TARGET_ADDR_FMT, target->working_area_phys); } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_phys)); /* loop for more */ break; case TCFG_WORK_AREA_SIZE: - if (goi->is_configure) { + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index], target->working_area_size); + index++; target_free_all_working_areas(target); - e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) - return e; - target->working_area_size = w; } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "0x%08" PRIx32, target->working_area_size); } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_size)); /* loop for more */ break; case TCFG_WORK_AREA_BACKUP: - if (goi->is_configure) { + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + retval = command_parse_bool_arg(CMD_ARGV[index], &target->backup_working_area); + if (retval != ERROR_OK) + return retval; + index++; target_free_all_working_areas(target); - e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) - return e; - /* make this boolean */ - target->backup_working_area = (w != 0); } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, target->backup_working_area ? "1" : "0"); } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->backup_working_area ? 1 : 0)); - /* loop for more e*/ + /* loop for more */ break; - case TCFG_ENDIAN: - if (goi->is_configure) { - e = jim_getopt_nvp(goi, nvp_target_endian, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(goi, nvp_target_endian, 1); - return e; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + n = nvp_name2value(nvp_target_endian, CMD_ARGV[index]); + if (!n->name) { + nvp_unknown_command_print(CMD, nvp_target_endian, CMD_ARGV[index - 1], CMD_ARGV[index]); + return ERROR_COMMAND_ARGUMENT_INVALID; } + index++; target->endianness = n->value; } else { - if (goi->argc != 0) - goto no_params; - } - n = jim_nvp_value2name_simple(nvp_target_endian, target->endianness); - if (!n->name) { - target->endianness = TARGET_LITTLE_ENDIAN; - n = jim_nvp_value2name_simple(nvp_target_endian, target->endianness); + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + n = nvp_value2name(nvp_target_endian, target->endianness); + if (!n->name) { + target->endianness = TARGET_LITTLE_ENDIAN; + n = nvp_value2name(nvp_target_endian, target->endianness); + } + command_print(CMD, "%s", n->name); } - Jim_SetResultString(goi->interp, n->name, -1); /* loop for more */ break; case TCFG_COREID: - if (goi->is_configure) { - e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) - return e; - target->coreid = (int32_t)w; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + COMMAND_PARSE_NUMBER(s32, CMD_ARGV[index], target->coreid); + index++; } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "%" PRIi32, target->coreid); } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->coreid)); /* loop for more */ break; case TCFG_CHAIN_POSITION: - if (goi->is_configure) { - Jim_Obj *o_t; - struct jtag_tap *tap; - + if (is_configure) { if (target->has_dap) { - Jim_SetResultString(goi->interp, - "target requires -dap parameter instead of -chain-position!", -1); - return JIM_ERR; + command_print(CMD, "target requires -dap parameter instead of -chain-position!"); + return ERROR_COMMAND_ARGUMENT_INVALID; } - target_free_all_working_areas(target); - e = jim_getopt_obj(goi, &o_t); - if (e != JIM_OK) - return e; - tap = jtag_tap_by_jim_obj(goi->interp, o_t); - if (!tap) - return JIM_ERR; + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[index]); + if (!tap) { + command_print(CMD, "Tap '%s' could not be found", CMD_ARGV[index]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + index++; target->tap = tap; target->tap_configured = true; } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "%s", target->tap->dotted_name); } - Jim_SetResultString(goi->interp, target->tap->dotted_name, -1); - /* loop for more e*/ + /* loop for more */ break; + case TCFG_DBGBASE: - if (goi->is_configure) { - e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) - return e; - target->dbgbase = (uint32_t)w; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index], target->dbgbase); + index++; target->dbgbase_set = true; } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "0x%08" PRIx32, target->dbgbase); } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->dbgbase)); /* loop for more */ break; + case TCFG_RTOS: - /* RTOS */ - { - int result = rtos_create(goi, target); - if (result != JIM_OK) - return result; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + struct jim_getopt_info goi; + jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC - index, CMD_JIMTCL_ARGV + index); + index++; + goi.is_configure = true; + int resval = rtos_create(&goi, target); + int reslen; + const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); + if (reslen > 0) + command_print(CMD, "%s", result); + if (resval != JIM_OK) + return ERROR_FAIL; + } else { + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + if (target->rtos) + command_print(CMD, "%s", target->rtos->type->name); } /* loop for more */ break; case TCFG_DEFER_EXAMINE: - /* DEFER_EXAMINE */ - target->defer_examine = true; + if (is_configure) + target->defer_examine = true; + else + command_print(CMD, "%s", target->defer_examine ? "true" : "false"); /* loop for more */ break; case TCFG_GDB_PORT: - if (goi->is_configure) { - struct command_context *cmd_ctx = current_command_context(goi->interp); - if (cmd_ctx->mode != COMMAND_CONFIG) { - Jim_SetResultString(goi->interp, "-gdb-port must be configured before 'init'", -1); - return JIM_ERR; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; } - const char *s; - e = jim_getopt_string(goi, &s, NULL); - if (e != JIM_OK) - return e; + /* TODO: generalize test of COMMAND_CONFIG */ + if (CMD_CTX->mode != COMMAND_CONFIG) { + command_print(CMD, "-gdb-port must be configured before 'init'"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + char *s = strdup(CMD_ARGV[index]); + if (!s) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } free(target->gdb_port_override); - target->gdb_port_override = strdup(s); + target->gdb_port_override = s; + index++; } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "%s", target->gdb_port_override ? target->gdb_port_override : "undefined"); } - Jim_SetResultString(goi->interp, target->gdb_port_override ? target->gdb_port_override : "undefined", -1); /* loop for more */ break; case TCFG_GDB_MAX_CONNECTIONS: - if (goi->is_configure) { - struct command_context *cmd_ctx = current_command_context(goi->interp); - if (cmd_ctx->mode != COMMAND_CONFIG) { - Jim_SetResultString(goi->interp, "-gdb-max-connections must be configured before 'init'", -1); - return JIM_ERR; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; } - e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) - return e; - target->gdb_max_connections = (w < 0) ? CONNECTION_LIMIT_UNLIMITED : (int)w; + if (CMD_CTX->mode != COMMAND_CONFIG) { + command_print(CMD, "-gdb-max-connections must be configured before 'init'"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[index], target->gdb_max_connections); + index++; + if (target->gdb_max_connections < 0) + target->gdb_max_connections = CONNECTION_LIMIT_UNLIMITED; } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "%d", target->gdb_max_connections); } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->gdb_max_connections)); + /* loop for more */ break; } - } /* while (goi->argc) */ - + } - /* done - we return */ - return JIM_OK; + return ERROR_OK; } -static int jim_target_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(handle_target_configure) { - struct command *c = jim_to_command(interp); - struct jim_getopt_info goi; + if (!CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - goi.is_configure = !strcmp(c->name, "configure"); - if (goi.argc < 1) { - Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, - "missing: -option ..."); - return JIM_ERR; - } - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - return target_configure(&goi, target); + bool is_configure = !strcmp(CMD_NAME, "configure"); + + struct target *target = get_current_target(CMD_CTX); + + return CALL_COMMAND_HANDLER(target_configure, target, 0, is_configure); } COMMAND_HANDLER(handle_target_examine) @@ -5454,40 +5488,34 @@ COMMAND_HANDLER(handle_target_debug_reason) return ERROR_OK; } -static int jim_target_invoke_event(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_target_invoke_event) { - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - if (goi.argc != 1) { - const char *cmd_name = Jim_GetString(argv[0], NULL); - Jim_SetResultFormatted(goi.interp, "%s <eventname>", cmd_name); - return JIM_ERR; - } - struct jim_nvp *n; - int e = jim_getopt_nvp(&goi, nvp_target_event, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(&goi, nvp_target_event, 1); - return e; + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + const struct nvp *n = nvp_name2value(nvp_target_event, CMD_ARGV[0]); + if (!n->name) { + nvp_unknown_command_print(CMD, nvp_target_event, NULL, CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; } - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); + + struct target *target = get_current_target(CMD_CTX); target_handle_event(target, n->value); - return JIM_OK; + return ERROR_OK; } static const struct command_registration target_instance_command_handlers[] = { { .name = "configure", .mode = COMMAND_ANY, - .jim_handler = jim_target_configure, + .handler = handle_target_configure, .help = "configure a new target for use", .usage = "[target_attribute ...]", }, { .name = "cget", .mode = COMMAND_ANY, - .jim_handler = jim_target_configure, + .handler = handle_target_configure, .help = "returns the specified target attribute", .usage = "target_attribute", }, @@ -5655,51 +5683,36 @@ static const struct command_registration target_instance_command_handlers[] = { { .name = "invoke-event", .mode = COMMAND_EXEC, - .jim_handler = jim_target_invoke_event, + .handler = handle_target_invoke_event, .help = "invoke handler for specified event", .usage = "event_name", }, COMMAND_REGISTRATION_DONE }; -static int target_create(struct jim_getopt_info *goi) +COMMAND_HANDLER(handle_target_create) { - Jim_Obj *new_cmd; - Jim_Cmd *cmd; - const char *cp; - int e; + int retval = ERROR_OK; int x; - struct target *target; - struct command_context *cmd_ctx; - - cmd_ctx = current_command_context(goi->interp); - assert(cmd_ctx); - if (goi->argc < 3) { - Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ?type? ..options..."); - return JIM_ERR; - } + if (CMD_ARGC < 4) + return ERROR_COMMAND_SYNTAX_ERROR; - /* COMMAND */ - jim_getopt_obj(goi, &new_cmd); - /* does this command exist? */ - cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_NONE); - if (cmd) { - cp = Jim_GetString(new_cmd, NULL); - Jim_SetResultFormatted(goi->interp, "Command/target: %s Exists", cp); - return JIM_ERR; + /* check if the target name clashes with an existing command name */ + Jim_Cmd *jimcmd = Jim_GetCommand(CMD_CTX->interp, CMD_JIMTCL_ARGV[0], JIM_NONE); + if (jimcmd) { + command_print(CMD, "Command/target: %s Exists", CMD_ARGV[0]); + return ERROR_FAIL; } /* TYPE */ - e = jim_getopt_string(goi, &cp, NULL); - if (e != JIM_OK) - return e; + const char *cp = CMD_ARGV[1]; struct transport *tr = get_current_transport(); if (tr && tr->override_target) { - e = tr->override_target(&cp); - if (e != ERROR_OK) { - LOG_ERROR("The selected transport doesn't support this target"); - return JIM_ERR; + retval = tr->override_target(&cp); + if (retval != ERROR_OK) { + command_print(CMD, "The selected transport doesn't support this target"); + return retval; } LOG_INFO("The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD"); } @@ -5711,28 +5724,29 @@ static int target_create(struct jim_getopt_info *goi) } } if (!target_types[x]) { - Jim_SetResultFormatted(goi->interp, "Unknown target type %s, try one of ", cp); + char *all = NULL; for (x = 0 ; target_types[x] ; x++) { - if (target_types[x + 1]) { - Jim_AppendStrings(goi->interp, - Jim_GetResult(goi->interp), - target_types[x]->name, - ", ", NULL); - } else { - Jim_AppendStrings(goi->interp, - Jim_GetResult(goi->interp), - " or ", - target_types[x]->name, NULL); + char *prev = all; + if (all) + all = alloc_printf("%s, %s", all, target_types[x]->name); + else + all = alloc_printf("%s", target_types[x]->name); + free(prev); + if (!all) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; } } - return JIM_ERR; + command_print(CMD, "Unknown target type %s, try one of %s", cp, all); + free(all); + return ERROR_FAIL; } /* Create it */ - target = calloc(1, sizeof(struct target)); + struct target *target = calloc(1, sizeof(struct target)); if (!target) { LOG_ERROR("Out of memory"); - return JIM_ERR; + return ERROR_FAIL; } /* set empty smp cluster */ @@ -5743,7 +5757,7 @@ static int target_create(struct jim_getopt_info *goi) if (!target->type) { LOG_ERROR("Out of memory"); free(target); - return JIM_ERR; + return ERROR_FAIL; } memcpy(target->type, target_types[x], sizeof(struct target_type)); @@ -5776,7 +5790,7 @@ static int target_create(struct jim_getopt_info *goi) LOG_ERROR("Out of memory"); free(target->type); free(target); - return JIM_ERR; + return ERROR_FAIL; } target->dbgmsg = NULL; @@ -5790,45 +5804,43 @@ static int target_create(struct jim_getopt_info *goi) target->gdb_port_override = NULL; target->gdb_max_connections = 1; - cp = Jim_GetString(new_cmd, NULL); - target->cmd_name = strdup(cp); + target->cmd_name = strdup(CMD_ARGV[0]); if (!target->cmd_name) { LOG_ERROR("Out of memory"); free(target->trace_info); free(target->type); free(target); - return JIM_ERR; + return ERROR_FAIL; } /* Do the rest as "configure" options */ - goi->is_configure = true; - e = target_configure(goi, target); - - if (e == JIM_OK) { + bool is_configure = true; + retval = CALL_COMMAND_HANDLER(target_configure, target, 2, is_configure); + if (retval == ERROR_OK) { if (target->has_dap) { if (!target->dap_configured) { - Jim_SetResultString(goi->interp, "-dap ?name? required when creating target", -1); - e = JIM_ERR; + command_print(CMD, "-dap ?name? required when creating target"); + retval = ERROR_COMMAND_ARGUMENT_INVALID; } } else { if (!target->tap_configured) { - Jim_SetResultString(goi->interp, "-chain-position ?name? required when creating target", -1); - e = JIM_ERR; + command_print(CMD, "-chain-position ?name? required when creating target"); + retval = ERROR_COMMAND_ARGUMENT_INVALID; } } /* tap must be set after target was configured */ if (!target->tap) - e = JIM_ERR; + retval = ERROR_COMMAND_ARGUMENT_INVALID; } - if (e != JIM_OK) { + if (retval != ERROR_OK) { rtos_destroy(target); free(target->gdb_port_override); free(target->trace_info); free(target->type); free(target->private_config); free(target); - return e; + return retval; } if (target->endianness == TARGET_ENDIAN_UNKNOWN) { @@ -5837,8 +5849,8 @@ static int target_create(struct jim_getopt_info *goi) } if (target->type->target_create) { - e = (*(target->type->target_create))(target, goi->interp); - if (e != ERROR_OK) { + retval = (*target->type->target_create)(target); + if (retval != ERROR_OK) { LOG_DEBUG("target_create failed"); free(target->cmd_name); rtos_destroy(target); @@ -5847,15 +5859,15 @@ static int target_create(struct jim_getopt_info *goi) free(target->type); free(target->private_config); free(target); - return JIM_ERR; + return retval; } } /* create the target specific commands */ if (target->type->commands) { - e = register_commands(cmd_ctx, NULL, target->type->commands); - if (e != ERROR_OK) - LOG_ERROR("unable to register '%s' commands", cp); + retval = register_commands(CMD_CTX, NULL, target->type->commands); + if (retval != ERROR_OK) + LOG_ERROR("unable to register '%s' commands", CMD_ARGV[0]); } /* now - create the new target name command */ @@ -5870,7 +5882,7 @@ static int target_create(struct jim_getopt_info *goi) }; const struct command_registration target_commands[] = { { - .name = cp, + .name = CMD_ARGV[0], .mode = COMMAND_ANY, .help = "target command group", .usage = "", @@ -5878,8 +5890,8 @@ static int target_create(struct jim_getopt_info *goi) }, COMMAND_REGISTRATION_DONE }; - e = register_commands_override_target(cmd_ctx, NULL, target_commands, target); - if (e != ERROR_OK) { + retval = register_commands_override_target(CMD_CTX, NULL, target_commands, target); + if (retval != ERROR_OK) { if (target->type->deinit_target) target->type->deinit_target(target); free(target->cmd_name); @@ -5888,14 +5900,14 @@ static int target_create(struct jim_getopt_info *goi) free(target->trace_info); free(target->type); free(target); - return JIM_ERR; + return retval; } /* append to end of list */ append_to_list_all_targets(target); - cmd_ctx->current_target = target; - return JIM_OK; + CMD_CTX->current_target = target; + return ERROR_OK; } COMMAND_HANDLER(handle_target_current) @@ -6016,18 +6028,6 @@ COMMAND_HANDLER(handle_target_smp) return retval; } -static int jim_target_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - if (goi.argc < 3) { - Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, - "<name> <target_type> [<target_options> ...]"); - return JIM_ERR; - } - return target_create(&goi); -} - static const struct command_registration target_subcommand_handlers[] = { { .name = "init", @@ -6039,7 +6039,7 @@ static const struct command_registration target_subcommand_handlers[] = { { .name = "create", .mode = COMMAND_CONFIG, - .jim_handler = jim_target_create, + .handler = handle_target_create, .usage = "name type '-chain-position' name [options ...]", .help = "Creates and selects a new target", }, diff --git a/src/target/target_type.h b/src/target/target_type.h index ce98cba..eddedbf 100644 --- a/src/target/target_type.h +++ b/src/target/target_type.h @@ -194,7 +194,7 @@ struct target_type { const struct command_registration *commands; /* called when target is created */ - int (*target_create)(struct target *target, Jim_Interp *interp); + int (*target_create)(struct target *target); /* called for various config parameters */ /* returns JIM_CONTINUE - if option not understood */ diff --git a/src/target/xscale.c b/src/target/xscale.c index 5cc790a..84318a9 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -3012,7 +3012,7 @@ static int xscale_init_arch_info(struct target *target, return ERROR_OK; } -static int xscale_target_create(struct target *target, Jim_Interp *interp) +static int xscale_target_create(struct target *target) { struct xscale_common *xscale; diff --git a/src/target/xtensa/xtensa_chip.c b/src/target/xtensa/xtensa_chip.c index ce6d35c..aab7ee3 100644 --- a/src/target/xtensa/xtensa_chip.c +++ b/src/target/xtensa/xtensa_chip.c @@ -81,7 +81,7 @@ static const struct xtensa_power_ops xtensa_chip_dm_pwr_ops = { .queue_reg_write = xtensa_dm_queue_pwr_reg_write }; -static int xtensa_chip_target_create(struct target *target, Jim_Interp *interp) +static int xtensa_chip_target_create(struct target *target) { struct xtensa_debug_module_config xtensa_chip_dm_cfg = { .dbg_ops = &xtensa_chip_dm_dbg_ops, diff --git a/src/transport/transport.c b/src/transport/transport.c index 0af1360..ab5be49 100644 --- a/src/transport/transport.c +++ b/src/transport/transport.c @@ -30,6 +30,9 @@ * messaging and error handling. */ +#include <helper/align.h> +#include <helper/bits.h> +#include <helper/list.h> #include <helper/log.h> #include <helper/replacements.h> #include <transport/transport.h> @@ -43,24 +46,82 @@ extern struct command_context *global_cmd_ctx; */ /** List of transports known to OpenOCD. */ -static struct transport *transport_list; +static const struct { + unsigned int id; + const char *name; + const char *full_name; + const char *deprecated_name; +} transport_names[] = { + { TRANSPORT_JTAG, "jtag", "jtag", NULL, }, + { TRANSPORT_SWD, "swd", "swd", NULL, }, + { TRANSPORT_HLA_JTAG, "jtag", "jtag (hla)", "hla_jtag", }, + { TRANSPORT_HLA_SWD, "swd", "swd (hla)", "hla_swd", }, + { TRANSPORT_DAPDIRECT_JTAG, "jtag", "jtag (dapdirect)", "dapdirect_jtag", }, + { TRANSPORT_DAPDIRECT_SWD, "swd", "swd (dapdirect)", "dapdirect_swd", }, + { TRANSPORT_SWIM, "swim", "swim", NULL, }, +}; + +/** List of transports registered in OpenOCD, alphabetically sorted per name. */ +static OOCD_LIST_HEAD(transport_list); + +/** + * Bitmask of transport IDs which the currently selected debug adapter supports. + * This is declared by the time that adapter is fully set up. + */ +static unsigned int allowed_transports; + +/** + * Transport ID auto-selected when not specified by the user. + */ +static unsigned int preferred_transport; /** - * NULL-terminated Vector of names of transports which the - * currently selected debug adapter supports. This is declared - * by the time that adapter is fully set up. + * Adapter supports a single transport; it has been auto-selected */ -static const char * const *allowed_transports; +static bool transport_single_is_autoselected; /** * The transport being used for the current OpenOCD session. */ static struct transport *session; -static int transport_select(struct command_context *ctx, const char *name) +const char *transport_name(unsigned int id) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(transport_names); i++) + if (id == transport_names[i].id) + return transport_names[i].name; + + return NULL; +} + +static const char *transport_full_name(unsigned int id) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(transport_names); i++) + if (id == transport_names[i].id) + return transport_names[i].full_name; + + return NULL; +} + +static const char *transport_deprecated_name(unsigned int id) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(transport_names); i++) + if (id == transport_names[i].id) + return transport_names[i].deprecated_name; + + return NULL; +} + +static bool is_transport_id_valid(unsigned int id) +{ + return (id != 0) && ((id & ~TRANSPORT_VALID_MASK) == 0) && IS_PWR_OF_2(id); +} + +static int transport_select(struct command_context *ctx, unsigned int transport_id) { /* name may only identify a known transport; * caller guarantees session's transport isn't yet set.*/ - for (struct transport *t = transport_list; t; t = t->next) { - if (strcmp(t->name, name) == 0) { + struct transport *t; + list_for_each_entry(t, &transport_list, lh) { + if (t->id == transport_id) { int retval = t->select(ctx); /* select() registers commands specific to this * transport, and may also reset the link, e.g. @@ -69,12 +130,14 @@ static int transport_select(struct command_context *ctx, const char *name) if (retval == ERROR_OK) session = t; else - LOG_ERROR("Error selecting '%s' as transport", t->name); + LOG_ERROR("Error selecting '%s' as transport", + transport_full_name(transport_id)); return retval; } } - LOG_ERROR("No transport named '%s' is available.", name); + LOG_ERROR("No transport named '%s' is available.", + transport_full_name(transport_id)); return ERROR_FAIL; } @@ -83,29 +146,48 @@ static int transport_select(struct command_context *ctx, const char *name) * to declare the set of transports supported by an adapter. When * there is only one member of that set, it is automatically selected. */ -int allow_transports(struct command_context *ctx, const char * const *vector) +int allow_transports(struct command_context *ctx, unsigned int transport_ids, + unsigned int transport_preferred_id) { - /* NOTE: caller is required to provide only a list - * of *valid* transport names - * - * REVISIT should we validate that? and insist there's - * at least one non-NULL element in that list? - * - * ... allow removals, e.g. external strapping prevents use - * of one transport; C code should be definitive about what - * can be used when all goes well. - */ if (allowed_transports || session) { LOG_ERROR("Can't modify the set of allowed transports."); return ERROR_FAIL; } - allowed_transports = vector; + /* validate the values in transport_ids and transport_preferred_id */ + if (transport_ids == 0 || (transport_ids & ~TRANSPORT_VALID_MASK) != 0) { + LOG_ERROR("BUG: Unknown transport IDs %lu", transport_ids & ~TRANSPORT_VALID_MASK); + return ERROR_FAIL; + } + + if ((transport_ids & transport_preferred_id) == 0 + || !IS_PWR_OF_2(transport_preferred_id)) { + LOG_ERROR("BUG: Invalid adapter transport_preferred_id"); + return ERROR_FAIL; + } + + unsigned int mask = transport_ids & + (TRANSPORT_JTAG | TRANSPORT_HLA_JTAG | TRANSPORT_DAPDIRECT_JTAG); + if (mask && !IS_PWR_OF_2(mask)) { + LOG_ERROR("BUG: Multiple JTAG transports"); + return ERROR_FAIL; + } + + mask = transport_ids & + (TRANSPORT_SWD | TRANSPORT_HLA_SWD | TRANSPORT_DAPDIRECT_SWD); + if (mask && !IS_PWR_OF_2(mask)) { + LOG_ERROR("BUG: Multiple SWD transports"); + return ERROR_FAIL; + } + + allowed_transports = transport_ids; + preferred_transport = transport_preferred_id; /* autoselect if there's no choice ... */ - if (!vector[1]) { - LOG_INFO("only one transport option; autoselecting '%s'", vector[0]); - return transport_select(ctx, vector[0]); + if (IS_PWR_OF_2(transport_ids)) { + LOG_DEBUG("only one transport option; autoselecting '%s'", transport_name(transport_ids)); + transport_single_is_autoselected = true; + return transport_select(ctx, transport_ids); } return ERROR_OK; @@ -130,20 +212,33 @@ int transport_register(struct transport *new_transport) { struct transport *t; - for (t = transport_list; t; t = t->next) { - if (strcmp(t->name, new_transport->name) == 0) { - LOG_ERROR("transport name already used"); + if (!is_transport_id_valid(new_transport->id)) { + LOG_ERROR("invalid transport ID 0x%x", new_transport->id); + return ERROR_FAIL; + } + + list_for_each_entry(t, &transport_list, lh) { + if (t->id == new_transport->id) { + LOG_ERROR("transport '%s' already registered", + transport_name(t->id)); return ERROR_FAIL; } } if (!new_transport->select || !new_transport->init) - LOG_ERROR("invalid transport %s", new_transport->name); + LOG_ERROR("invalid transport %s", + transport_full_name(new_transport->id)); + + /* splice this into the list, sorted in alphabetic order */ + list_for_each_entry(t, &transport_list, lh) { + if (strcmp(transport_name(t->id), + transport_name(new_transport->id)) >= 0) + break; + } + list_add_tail(&new_transport->lh, &t->lh); - /* splice this into the list */ - new_transport->next = transport_list; - transport_list = new_transport; - LOG_DEBUG("register '%s'", new_transport->name); + LOG_DEBUG("register '%s' (ID %d)", + transport_full_name(new_transport->id), new_transport->id); return ERROR_OK; } @@ -160,6 +255,14 @@ struct transport *get_current_transport(void) return session; } +const char *get_current_transport_name(void) +{ + if (!session || !is_transport_id_valid(session->id)) + NULL; + + return transport_full_name(session->id); +} + /*-----------------------------------------------------------------------*/ /* @@ -174,14 +277,18 @@ COMMAND_HANDLER(handle_transport_init) /* no session transport configured, print transports then fail */ LOG_ERROR("Transports available:"); - const char * const *vector = allowed_transports; - while (*vector) { - LOG_ERROR("%s", *vector); - vector++; + for (unsigned int i = BIT(0); i & TRANSPORT_VALID_MASK; i <<= 1) { + if (i & allowed_transports) + LOG_ERROR("%s", transport_full_name(i)); } return ERROR_FAIL; } + if (transport_single_is_autoselected) + LOG_WARNING("DEPRECATED: auto-selecting transport \"%s\". " + "Use 'transport select %s' to suppress this message.", + transport_full_name(session->id), transport_name(session->id)); + return session->init(CMD_CTX); } @@ -192,8 +299,15 @@ COMMAND_HANDLER(handle_transport_list) command_print(CMD, "The following transports are available:"); - for (struct transport *t = transport_list; t; t = t->next) - command_print(CMD, "\t%s", t->name); + struct transport *t; + const char *prev_name = NULL; + /* list is sorted, don't print duplicated transport names */ + list_for_each_entry(t, &transport_list, lh) { + const char *name = transport_name(t->id); + if (!prev_name || strcmp(prev_name, name)) + command_print(CMD, "\t%s", name); + prev_name = name; + } return ERROR_OK; } @@ -216,20 +330,29 @@ COMMAND_HANDLER(handle_transport_select) command_print(CMD, "Debug adapter does not support any transports? Check config file order."); return ERROR_FAIL; } - LOG_INFO("auto-selecting first available session transport \"%s\". " - "To override use 'transport select <transport>'.", allowed_transports[0]); - int retval = transport_select(CMD_CTX, allowed_transports[0]); + LOG_WARNING("DEPRECATED: auto-selecting transport \"%s\". " + "Use 'transport select %s' to suppress this message.", + transport_full_name(preferred_transport), + transport_name(preferred_transport)); + int retval = transport_select(CMD_CTX, preferred_transport); if (retval != ERROR_OK) return retval; } - command_print(CMD, "%s", session->name); + command_print(CMD, "%s", transport_full_name(session->id)); return ERROR_OK; } /* assign transport */ if (session) { - if (!strcmp(session->name, CMD_ARGV[0])) { - LOG_WARNING("Transport \"%s\" was already selected", session->name); + if (!strcmp(transport_name(session->id), CMD_ARGV[0]) + || (transport_deprecated_name(session->id) + && !strcmp(transport_deprecated_name(session->id), CMD_ARGV[0]))) { + if (transport_single_is_autoselected) { + /* Nothing to do, but also nothing to complain */ + transport_single_is_autoselected = false; + return ERROR_OK; + } + LOG_WARNING("Transport \"%s\" was already selected", CMD_ARGV[0]); return ERROR_OK; } command_print(CMD, "Can't change session's transport after the initial selection was made"); @@ -247,12 +370,18 @@ COMMAND_HANDLER(handle_transport_select) return ERROR_FAIL; } - for (unsigned int i = 0; allowed_transports[i]; i++) { - if (!strcmp(allowed_transports[i], CMD_ARGV[0])) { - int retval = transport_select(CMD_CTX, CMD_ARGV[0]); - if (retval != ERROR_OK) - return retval; - return ERROR_OK; + for (unsigned int i = BIT(0); i & TRANSPORT_VALID_MASK; i <<= 1) { + if (!(i & allowed_transports)) + continue; + + if (!strcmp(transport_name(i), CMD_ARGV[0])) + return transport_select(CMD_CTX, i); + + if (transport_deprecated_name(i) + && !strcmp(transport_deprecated_name(i), CMD_ARGV[0])) { + LOG_WARNING("DEPRECATED! use 'transport select %s', not 'transport select %s'", + transport_name(i), transport_deprecated_name(i)); + return transport_select(CMD_CTX, i); } } diff --git a/src/transport/transport.h b/src/transport/transport.h index 2e3dcc6..5445bcf 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -12,7 +12,27 @@ #include "config.h" #endif +#include "helper/bits.h" #include "helper/command.h" +#include "helper/list.h" + +#define TRANSPORT_JTAG BIT(0) +#define TRANSPORT_SWD BIT(1) +#define TRANSPORT_HLA_JTAG BIT(2) +#define TRANSPORT_HLA_SWD BIT(3) +#define TRANSPORT_DAPDIRECT_JTAG BIT(4) +#define TRANSPORT_DAPDIRECT_SWD BIT(5) +#define TRANSPORT_SWIM BIT(6) + +/* mask for valid ID */ +#define TRANSPORT_VALID_MASK \ + (TRANSPORT_JTAG | \ + TRANSPORT_SWD | \ + TRANSPORT_HLA_JTAG | \ + TRANSPORT_HLA_SWD | \ + TRANSPORT_DAPDIRECT_JTAG | \ + TRANSPORT_DAPDIRECT_SWD | \ + TRANSPORT_SWIM) /** * Wrapper for transport lifecycle operations. @@ -34,11 +54,10 @@ */ struct transport { /** - * Each transport has a unique name, used to select it - * from among the alternatives. Examples might include - * "jtag", * "swd", "AVR_ISP" and more. + * Each transport has a unique ID, used to select it + * from among the alternatives. */ - const char *name; + unsigned int id; /** * When a transport is selected, this method registers @@ -66,18 +85,23 @@ struct transport { int (*override_target)(const char **targetname); /** - * Transports are stored in a singly linked list. + * Transports are stored in a linked list. */ - struct transport *next; + struct list_head lh; }; int transport_register(struct transport *new_transport); struct transport *get_current_transport(void); +const char *get_current_transport_name(void); + +const char *transport_name(unsigned int id); + int transport_register_commands(struct command_context *ctx); -int allow_transports(struct command_context *ctx, const char * const *vector); +int allow_transports(struct command_context *ctx, unsigned int transport_ids, + unsigned int transport_preferred_id); bool transport_is_jtag(void); bool transport_is_swd(void); |