Merge branch 'master' into from_upstream
I may have broken memory sampling with this merge. Conflicts: doc/openocd.texi src/helper/command.c src/jtag/drivers/ftdi.c src/rtos/FreeRTOS.c Change-Id: I2b7e09b2d3b244db546c5212532e6b48fb66dca4
This commit is contained in:
commit
927c4db298
|
@ -45,6 +45,9 @@ AC_SEARCH_LIBS([openpty], [util])
|
||||||
|
|
||||||
AC_CHECK_HEADERS([sys/socket.h])
|
AC_CHECK_HEADERS([sys/socket.h])
|
||||||
AC_CHECK_HEADERS([elf.h])
|
AC_CHECK_HEADERS([elf.h])
|
||||||
|
AC_EGREP_HEADER(Elf64_Ehdr, [elf.h], [
|
||||||
|
AC_DEFINE([HAVE_ELF64], [1], [Define to 1 if the system has the type `Elf64_Ehdr'.])
|
||||||
|
])
|
||||||
AC_CHECK_HEADERS([dirent.h])
|
AC_CHECK_HEADERS([dirent.h])
|
||||||
AC_CHECK_HEADERS([fcntl.h])
|
AC_CHECK_HEADERS([fcntl.h])
|
||||||
AC_CHECK_HEADERS([malloc.h])
|
AC_CHECK_HEADERS([malloc.h])
|
||||||
|
|
|
@ -154,6 +154,11 @@ ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="660", GROUP="plugdev",
|
||||||
# Debug Board for Neo1973
|
# Debug Board for Neo1973
|
||||||
ATTRS{idVendor}=="1457", ATTRS{idProduct}=="5118", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
ATTRS{idVendor}=="1457", ATTRS{idProduct}=="5118", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
||||||
|
|
||||||
|
# OSBDM
|
||||||
|
ATTRS{idVendor}=="15a2", ATTRS{idProduct}=="0042", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
||||||
|
ATTRS{idVendor}=="15a2", ATTRS{idProduct}=="0058", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
||||||
|
ATTRS{idVendor}=="15a2", ATTRS{idProduct}=="005e", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
||||||
|
|
||||||
# Olimex ARM-USB-OCD
|
# Olimex ARM-USB-OCD
|
||||||
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0003", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0003", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
||||||
|
|
||||||
|
|
1088
doc/openocd.texi
1088
doc/openocd.texi
File diff suppressed because it is too large
Load Diff
|
@ -479,8 +479,8 @@ static int nand_init(struct command_context *cmd_ctx)
|
||||||
{
|
{
|
||||||
if (!nand_devices)
|
if (!nand_devices)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
struct command *parent = command_find_in_context(cmd_ctx, "nand");
|
|
||||||
return register_commands(cmd_ctx, parent, nand_exec_command_handlers);
|
return register_commands(cmd_ctx, "nand", nand_exec_command_handlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_nand_init_command)
|
COMMAND_HANDLER(handle_nand_init_command)
|
||||||
|
|
|
@ -52,6 +52,7 @@ NOR_DRIVERS = \
|
||||||
%D%/psoc5lp.c \
|
%D%/psoc5lp.c \
|
||||||
%D%/psoc6.c \
|
%D%/psoc6.c \
|
||||||
%D%/renesas_rpchf.c \
|
%D%/renesas_rpchf.c \
|
||||||
|
%D%/rp2040.c \
|
||||||
%D%/sfdp.c \
|
%D%/sfdp.c \
|
||||||
%D%/sh_qspi.c \
|
%D%/sh_qspi.c \
|
||||||
%D%/sim3x.c \
|
%D%/sim3x.c \
|
||||||
|
|
|
@ -68,6 +68,7 @@ extern const struct flash_driver psoc5lp_eeprom_flash;
|
||||||
extern const struct flash_driver psoc5lp_nvl_flash;
|
extern const struct flash_driver psoc5lp_nvl_flash;
|
||||||
extern const struct flash_driver psoc6_flash;
|
extern const struct flash_driver psoc6_flash;
|
||||||
extern const struct flash_driver renesas_rpchf_flash;
|
extern const struct flash_driver renesas_rpchf_flash;
|
||||||
|
extern const struct flash_driver rp2040_flash;
|
||||||
extern const struct flash_driver sh_qspi_flash;
|
extern const struct flash_driver sh_qspi_flash;
|
||||||
extern const struct flash_driver sim3x_flash;
|
extern const struct flash_driver sim3x_flash;
|
||||||
extern const struct flash_driver stellaris_flash;
|
extern const struct flash_driver stellaris_flash;
|
||||||
|
@ -141,6 +142,7 @@ static const struct flash_driver * const flash_drivers[] = {
|
||||||
&psoc5lp_nvl_flash,
|
&psoc5lp_nvl_flash,
|
||||||
&psoc6_flash,
|
&psoc6_flash,
|
||||||
&renesas_rpchf_flash,
|
&renesas_rpchf_flash,
|
||||||
|
&rp2040_flash,
|
||||||
&sh_qspi_flash,
|
&sh_qspi_flash,
|
||||||
&sim3x_flash,
|
&sim3x_flash,
|
||||||
&stellaris_flash,
|
&stellaris_flash,
|
||||||
|
|
|
@ -109,7 +109,6 @@ static const struct command_registration esirisc_flash_command_handlers[];
|
||||||
FLASH_BANK_COMMAND_HANDLER(esirisc_flash_bank_command)
|
FLASH_BANK_COMMAND_HANDLER(esirisc_flash_bank_command)
|
||||||
{
|
{
|
||||||
struct esirisc_flash_bank *esirisc_info;
|
struct esirisc_flash_bank *esirisc_info;
|
||||||
struct command *esirisc_cmd;
|
|
||||||
|
|
||||||
if (CMD_ARGC < 9)
|
if (CMD_ARGC < 9)
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
@ -123,8 +122,7 @@ FLASH_BANK_COMMAND_HANDLER(esirisc_flash_bank_command)
|
||||||
bank->driver_priv = esirisc_info;
|
bank->driver_priv = esirisc_info;
|
||||||
|
|
||||||
/* register commands using existing esirisc context */
|
/* register commands using existing esirisc context */
|
||||||
esirisc_cmd = command_find_in_context(CMD_CTX, "esirisc");
|
register_commands(CMD_CTX, "esirisc", esirisc_flash_command_handlers);
|
||||||
register_commands(CMD_CTX, esirisc_cmd, esirisc_flash_command_handlers);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -289,7 +289,7 @@ static const struct nrf5_device_package nrf5_packages_table[] = {
|
||||||
|
|
||||||
const struct flash_driver nrf5_flash, nrf51_flash;
|
const struct flash_driver nrf5_flash, nrf51_flash;
|
||||||
|
|
||||||
static int nrf5_bank_is_probed(struct flash_bank *bank)
|
static bool nrf5_bank_is_probed(const struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
struct nrf5_bank *nbank = bank->driver_priv;
|
struct nrf5_bank *nbank = bank->driver_priv;
|
||||||
|
|
||||||
|
@ -309,13 +309,10 @@ static int nrf5_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf5_i
|
||||||
struct nrf5_bank *nbank = bank->driver_priv;
|
struct nrf5_bank *nbank = bank->driver_priv;
|
||||||
*chip = nbank->chip;
|
*chip = nbank->chip;
|
||||||
|
|
||||||
int probed = nrf5_bank_is_probed(bank);
|
if (nrf5_bank_is_probed(bank))
|
||||||
if (probed < 0)
|
|
||||||
return probed;
|
|
||||||
else if (!probed)
|
|
||||||
return nrf5_probe(bank);
|
|
||||||
else
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
||||||
|
return nrf5_probe(bank);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nrf5_wait_for_nvmc(struct nrf5_info *chip)
|
static int nrf5_wait_for_nvmc(struct nrf5_info *chip)
|
||||||
|
@ -871,14 +868,10 @@ static int nrf5_probe(struct flash_bank *bank)
|
||||||
|
|
||||||
static int nrf5_auto_probe(struct flash_bank *bank)
|
static int nrf5_auto_probe(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
int probed = nrf5_bank_is_probed(bank);
|
if (nrf5_bank_is_probed(bank))
|
||||||
|
|
||||||
if (probed < 0)
|
|
||||||
return probed;
|
|
||||||
else if (probed)
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
else
|
|
||||||
return nrf5_probe(bank);
|
return nrf5_probe(bank);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nrf5_erase_all(struct nrf5_info *chip)
|
static int nrf5_erase_all(struct nrf5_info *chip)
|
||||||
|
|
|
@ -1132,7 +1132,7 @@ static const struct numicro_cpu_type NuMicroParts[] = {
|
||||||
/* Private bank information for NuMicro. */
|
/* Private bank information for NuMicro. */
|
||||||
struct numicro_flash_bank {
|
struct numicro_flash_bank {
|
||||||
struct working_area *write_algorithm;
|
struct working_area *write_algorithm;
|
||||||
int probed;
|
bool probed;
|
||||||
const struct numicro_cpu_type *cpu;
|
const struct numicro_cpu_type *cpu;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,453 @@
|
||||||
|
/* 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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_DEBUG("Calling ROM func @0x%" PRIx16 " with %d arguments", func_offset, n_args);
|
||||||
|
LOG_DEBUG("Calling on core \"%s\"", target->cmd_name);
|
||||||
|
|
||||||
|
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);
|
||||||
|
init_reg_param(&args[n_args + 1], "sp", 32, PARAM_OUT);
|
||||||
|
buf_set_u32(args[n_args + 1].value, 0, 32, stacktop);
|
||||||
|
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < n_args + 2; ++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_args + 1, args, /* User arguments + r7 */
|
||||||
|
priv->jump_debug_trampoline, priv->jump_debug_trampoline_end,
|
||||||
|
3000, /* 3s timeout */
|
||||||
|
&alg_info
|
||||||
|
);
|
||||||
|
for (unsigned int i = 0; i < n_args + 2; ++i)
|
||||||
|
destroy_reg_param(&args[i]);
|
||||||
|
if (err != ERROR_OK)
|
||||||
|
LOG_ERROR("Failed to invoke ROM function @0x%" PRIx16 "\n", func_offset);
|
||||||
|
return err;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stack_grab_and_prep(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct rp2040_flash_bank *priv = bank->driver_priv;
|
||||||
|
|
||||||
|
/* 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(bank->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(bank->target, priv, priv->jump_connect_internal_flash, NULL, 0);
|
||||||
|
if (err != ERROR_OK) {
|
||||||
|
LOG_ERROR("RP2040 erase: failed to connect internal flash");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("Kicking flash out of XIP mode");
|
||||||
|
err = rp2040_call_rom_func(bank->target, priv, priv->jump_flash_exit_xip, NULL, 0);
|
||||||
|
if (err != ERROR_OK) {
|
||||||
|
LOG_ERROR("RP2040 erase: 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;
|
||||||
|
struct working_area *bounce;
|
||||||
|
|
||||||
|
int err = stack_grab_and_prep(bank);
|
||||||
|
if (err != ERROR_OK)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
const unsigned int chunk_size = target_get_working_area_avail(target);
|
||||||
|
if (target_alloc_working_area(target, chunk_size, &bounce) != ERROR_OK) {
|
||||||
|
LOG_ERROR("Could not allocate bounce buffer for flash programming. Can't continue");
|
||||||
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
if (err != ERROR_OK) {
|
||||||
|
LOG_ERROR("Failed to invoke flash programming code on target");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer += write_size;
|
||||||
|
offset += write_size;
|
||||||
|
count -= write_size;
|
||||||
|
}
|
||||||
|
target_free_working_area(target, bounce);
|
||||||
|
|
||||||
|
if (err != ERROR_OK)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* Flash is successfully programmed. We can now do a bit of poking to make the flash
|
||||||
|
contents visible to us via memory-mapped (XIP) interface in the 0x1... memory region */
|
||||||
|
LOG_DEBUG("Flushing flash cache after write behind");
|
||||||
|
err = rp2040_call_rom_func(bank->target, priv, priv->jump_flush_cache, NULL, 0);
|
||||||
|
if (err != ERROR_OK) {
|
||||||
|
LOG_ERROR("RP2040 write: failed to flush flash cache");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
LOG_DEBUG("Configuring SSI for execute-in-place");
|
||||||
|
err = rp2040_call_rom_func(bank->target, priv, priv->jump_enter_cmd_xip, NULL, 0);
|
||||||
|
if (err != ERROR_OK)
|
||||||
|
LOG_ERROR("RP2040 write: failed to flush flash cache");
|
||||||
|
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;
|
||||||
|
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 = stack_grab_and_prep(bank);
|
||||||
|
if (err != ERROR_OK)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
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). OpenOCD's spi.c only uses "block" sizes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
err = rp2040_call_rom_func(bank->target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args));
|
||||||
|
|
||||||
|
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_flash_probe(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct rp2040_flash_bank *priv = bank->driver_priv;
|
||||||
|
struct target *target = bank->target;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = stack_grab_and_prep(bank);
|
||||||
|
if (err != ERROR_OK)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
uint32_t device_id = 0;
|
||||||
|
const target_addr_t ssi_dr0 = 0x18000060;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
device_id >>= 8;
|
||||||
|
|
||||||
|
err = rp2040_ssel_active(target, false);
|
||||||
|
if (err != ERROR_OK) {
|
||||||
|
LOG_ERROR("SSEL inactive failed");
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* 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->size = priv->dev->size_in_bytes;
|
||||||
|
|
||||||
|
bank->num_sectors = bank->size / priv->dev->sectorsize;
|
||||||
|
LOG_INFO("RP2040 B0 Flash Probe: %d bytes @" TARGET_ADDR_FMT ", in %d 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct flash_driver rp2040_flash = {
|
||||||
|
.name = "rp2040_flash",
|
||||||
|
.commands = NULL,
|
||||||
|
.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
|
||||||
|
};
|
|
@ -692,7 +692,7 @@ static int stm32x_probe(struct flash_bank *bank)
|
||||||
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
|
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
|
||||||
uint16_t flash_size_in_kb;
|
uint16_t flash_size_in_kb;
|
||||||
uint16_t max_flash_size_in_kb;
|
uint16_t max_flash_size_in_kb;
|
||||||
uint32_t device_id;
|
uint32_t dbgmcu_idcode;
|
||||||
int page_size;
|
int page_size;
|
||||||
uint32_t base_address = 0x08000000;
|
uint32_t base_address = 0x08000000;
|
||||||
|
|
||||||
|
@ -705,14 +705,17 @@ static int stm32x_probe(struct flash_bank *bank)
|
||||||
stm32x_info->default_rdp = 0xA5;
|
stm32x_info->default_rdp = 0xA5;
|
||||||
|
|
||||||
/* read stm32 device id register */
|
/* read stm32 device id register */
|
||||||
int retval = stm32x_get_device_id(bank, &device_id);
|
int retval = stm32x_get_device_id(bank, &dbgmcu_idcode);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
|
LOG_INFO("device id = 0x%08" PRIx32 "", dbgmcu_idcode);
|
||||||
|
|
||||||
|
uint16_t device_id = dbgmcu_idcode & 0xfff;
|
||||||
|
uint16_t rev_id = dbgmcu_idcode >> 16;
|
||||||
|
|
||||||
/* set page size, protection granularity and max flash size depending on family */
|
/* set page size, protection granularity and max flash size depending on family */
|
||||||
switch (device_id & 0xfff) {
|
switch (device_id) {
|
||||||
case 0x440: /* stm32f05x */
|
case 0x440: /* stm32f05x */
|
||||||
page_size = 1024;
|
page_size = 1024;
|
||||||
stm32x_info->ppage_size = 4;
|
stm32x_info->ppage_size = 4;
|
||||||
|
@ -754,6 +757,25 @@ static int stm32x_probe(struct flash_bank *bank)
|
||||||
page_size = 1024;
|
page_size = 1024;
|
||||||
stm32x_info->ppage_size = 4;
|
stm32x_info->ppage_size = 4;
|
||||||
max_flash_size_in_kb = 128;
|
max_flash_size_in_kb = 128;
|
||||||
|
/* GigaDevice GD32F1x0 & GD32F3x0 series devices share DEV_ID
|
||||||
|
with STM32F101/2/3 medium-density line,
|
||||||
|
however they use a REV_ID different from any STM32 device.
|
||||||
|
The main difference is another offset of user option bits
|
||||||
|
(like WDG_SW, nRST_STOP, nRST_STDBY) in option byte register
|
||||||
|
(FLASH_OBR/FMC_OBSTAT 0x4002201C).
|
||||||
|
This caused problems e.g. during flash block programming
|
||||||
|
because of unexpected active hardware watchog. */
|
||||||
|
switch (rev_id) {
|
||||||
|
case 0x1303: /* gd32f1x0 */
|
||||||
|
stm32x_info->user_data_offset = 16;
|
||||||
|
stm32x_info->option_offset = 6;
|
||||||
|
max_flash_size_in_kb = 64;
|
||||||
|
break;
|
||||||
|
case 0x1704: /* gd32f3x0 */
|
||||||
|
stm32x_info->user_data_offset = 16;
|
||||||
|
stm32x_info->option_offset = 6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 0x412: /* stm32f1x low-density */
|
case 0x412: /* stm32f1x low-density */
|
||||||
page_size = 1024;
|
page_size = 1024;
|
||||||
|
@ -955,6 +977,14 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||||
rev_str = "A";
|
rev_str = "A";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0x1303: /* gd32f1x0 */
|
||||||
|
device_str = "GD32F1x0";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x1704: /* gd32f3x0 */
|
||||||
|
device_str = "GD32F3x0";
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x2000:
|
case 0x2000:
|
||||||
rev_str = "B";
|
rev_str = "B";
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1249,8 +1249,7 @@ static int flash_init_drivers(struct command_context *cmd_ctx)
|
||||||
if (!flash_bank_list())
|
if (!flash_bank_list())
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
||||||
struct command *parent = command_find_in_context(cmd_ctx, "flash");
|
return register_commands(cmd_ctx, "flash", flash_exec_command_handlers);
|
||||||
return register_commands(cmd_ctx, parent, flash_exec_command_handlers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_flash_bank_command)
|
COMMAND_HANDLER(handle_flash_bank_command)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -26,6 +26,7 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <jim-nvp.h>
|
#include <jim-nvp.h>
|
||||||
|
|
||||||
|
#include <helper/list.h>
|
||||||
#include <helper/types.h>
|
#include <helper/types.h>
|
||||||
|
|
||||||
/* To achieve C99 printf compatibility in MinGW, gnu_printf should be
|
/* To achieve C99 printf compatibility in MinGW, gnu_printf should be
|
||||||
|
@ -41,6 +42,7 @@ enum command_mode {
|
||||||
COMMAND_EXEC,
|
COMMAND_EXEC,
|
||||||
COMMAND_CONFIG,
|
COMMAND_CONFIG,
|
||||||
COMMAND_ANY,
|
COMMAND_ANY,
|
||||||
|
COMMAND_UNKNOWN = -1, /* error condition */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct command_context;
|
struct command_context;
|
||||||
|
@ -52,7 +54,6 @@ typedef int (*command_output_handler_t)(struct command_context *context,
|
||||||
struct command_context {
|
struct command_context {
|
||||||
Jim_Interp *interp;
|
Jim_Interp *interp;
|
||||||
enum command_mode mode;
|
enum command_mode mode;
|
||||||
struct command *commands;
|
|
||||||
struct target *current_target;
|
struct target *current_target;
|
||||||
/* The target set by 'targets xx' command or the latest created */
|
/* The target set by 'targets xx' command or the latest created */
|
||||||
struct target *current_target_override;
|
struct target *current_target_override;
|
||||||
|
@ -64,6 +65,7 @@ struct command_context {
|
||||||
*/
|
*/
|
||||||
command_output_handler_t output_handler;
|
command_output_handler_t output_handler;
|
||||||
void *output_handler_priv;
|
void *output_handler_priv;
|
||||||
|
struct list_head *help_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct command;
|
struct command;
|
||||||
|
@ -179,22 +181,24 @@ typedef __COMMAND_HANDLER((*command_handler_t));
|
||||||
|
|
||||||
struct command {
|
struct command {
|
||||||
char *name;
|
char *name;
|
||||||
char *help;
|
|
||||||
char *usage;
|
|
||||||
struct command *parent;
|
|
||||||
struct command *children;
|
|
||||||
command_handler_t handler;
|
command_handler_t handler;
|
||||||
Jim_CmdProc *jim_handler;
|
Jim_CmdProc *jim_handler;
|
||||||
void *jim_handler_data;
|
void *jim_handler_data;
|
||||||
/* Currently used only for target of target-prefixed cmd.
|
/* Command handlers can use it for any handler specific data */
|
||||||
* Native OpenOCD commands use jim_handler_data exclusively
|
struct target *jim_override_target;
|
||||||
* as a target override.
|
/* Used only for target of target-prefixed cmd */
|
||||||
* Jim handlers outside of target cmd tree can use
|
|
||||||
* jim_handler_data for any handler specific data */
|
|
||||||
enum command_mode mode;
|
enum command_mode mode;
|
||||||
struct command *next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the struct command pointer kept in private data
|
||||||
|
* Used to enforce check on data type
|
||||||
|
*/
|
||||||
|
static inline struct command *jim_to_command(Jim_Interp *interp)
|
||||||
|
{
|
||||||
|
return Jim_CmdPrivData(interp);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Commands should be registered by filling in one or more of these
|
* Commands should be registered by filling in one or more of these
|
||||||
* structures and passing them to [un]register_commands().
|
* structures and passing them to [un]register_commands().
|
||||||
|
@ -233,6 +237,10 @@ struct command_registration {
|
||||||
/** Use this as the last entry in an array of command_registration records. */
|
/** Use this as the last entry in an array of command_registration records. */
|
||||||
#define COMMAND_REGISTRATION_DONE { .name = NULL, .chain = NULL }
|
#define COMMAND_REGISTRATION_DONE { .name = NULL, .chain = NULL }
|
||||||
|
|
||||||
|
int __register_commands(struct command_context *cmd_ctx, const char *cmd_prefix,
|
||||||
|
const struct command_registration *cmds, void *data,
|
||||||
|
struct target *override_target);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register one or more commands in the specified context, as children
|
* Register one or more commands in the specified context, as children
|
||||||
* of @c parent (or top-level commends, if NULL). In a registration's
|
* of @c parent (or top-level commends, if NULL). In a registration's
|
||||||
|
@ -241,37 +249,77 @@ struct command_registration {
|
||||||
* Otherwise, the chained commands are added as children of the command.
|
* Otherwise, the chained commands are added as children of the command.
|
||||||
*
|
*
|
||||||
* @param cmd_ctx The command_context in which to register the command.
|
* @param cmd_ctx The command_context in which to register the command.
|
||||||
* @param parent Register this command as a child of this, or NULL to
|
* @param cmd_prefix Register this command as a child of this, or NULL to
|
||||||
* register a top-level command.
|
* register a top-level command.
|
||||||
* @param cmds Pointer to an array of command_registration records that
|
* @param cmds Pointer to an array of command_registration records that
|
||||||
* contains the desired command parameters. The last record must have
|
* contains the desired command parameters. The last record must have
|
||||||
* NULL for all fields.
|
* NULL for all fields.
|
||||||
* @returns ERROR_OK on success; ERROR_FAIL if any registration fails.
|
* @returns ERROR_OK on success; ERROR_FAIL if any registration fails.
|
||||||
*/
|
*/
|
||||||
int register_commands(struct command_context *cmd_ctx, struct command *parent,
|
static inline int register_commands(struct command_context *cmd_ctx, const char *cmd_prefix,
|
||||||
const struct command_registration *cmds);
|
const struct command_registration *cmds)
|
||||||
|
{
|
||||||
|
return __register_commands(cmd_ctx, cmd_prefix, cmds, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register one or more commands, as register_commands(), plus specify
|
||||||
|
* that command should override the current target
|
||||||
|
*
|
||||||
|
* @param cmd_ctx The command_context in which to register the command.
|
||||||
|
* @param cmd_prefix Register this command as a child of this, or NULL to
|
||||||
|
* register a top-level command.
|
||||||
|
* @param cmds Pointer to an array of command_registration records that
|
||||||
|
* contains the desired command parameters. The last record must have
|
||||||
|
* NULL for all fields.
|
||||||
|
* @param target The target that has to override current target.
|
||||||
|
* @returns ERROR_OK on success; ERROR_FAIL if any registration fails.
|
||||||
|
*/
|
||||||
|
static inline int register_commands_override_target(struct command_context *cmd_ctx,
|
||||||
|
const char *cmd_prefix, const struct command_registration *cmds,
|
||||||
|
struct target *target)
|
||||||
|
{
|
||||||
|
return __register_commands(cmd_ctx, cmd_prefix, cmds, NULL, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register one or more commands, as register_commands(), plus specify
|
||||||
|
* a pointer to command private data that would be accessible through
|
||||||
|
* the macro CMD_DATA. The private data will not be freed when command
|
||||||
|
* is unregistered.
|
||||||
|
*
|
||||||
|
* @param cmd_ctx The command_context in which to register the command.
|
||||||
|
* @param cmd_prefix Register this command as a child of this, or NULL to
|
||||||
|
* register a top-level command.
|
||||||
|
* @param cmds Pointer to an array of command_registration records that
|
||||||
|
* contains the desired command parameters. The last record must have
|
||||||
|
* NULL for all fields.
|
||||||
|
* @param data The command private data.
|
||||||
|
* @returns ERROR_OK on success; ERROR_FAIL if any registration fails.
|
||||||
|
*/
|
||||||
|
static inline int register_commands_with_data(struct command_context *cmd_ctx,
|
||||||
|
const char *cmd_prefix, const struct command_registration *cmds,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
return __register_commands(cmd_ctx, cmd_prefix, cmds, data, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unregisters all commands from the specified context.
|
* Unregisters all commands from the specified context.
|
||||||
* @param cmd_ctx The context that will be cleared of registered commands.
|
* @param cmd_ctx The context that will be cleared of registered commands.
|
||||||
* @param parent If given, only clear commands from under this one command.
|
* @param cmd_prefix If given, only clear commands from under this one command.
|
||||||
* @returns ERROR_OK on success, or an error code.
|
* @returns ERROR_OK on success, or an error code.
|
||||||
*/
|
*/
|
||||||
int unregister_all_commands(struct command_context *cmd_ctx,
|
int unregister_all_commands(struct command_context *cmd_ctx,
|
||||||
struct command *parent);
|
const char *cmd_prefix);
|
||||||
|
|
||||||
struct command *command_find_in_context(struct command_context *cmd_ctx,
|
|
||||||
const char *name);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the private command data field for a command and all descendents.
|
* Unregisters the help for all commands. Used at exit to remove the help
|
||||||
* This is used when creating a new hierarchy of commands that depends
|
* added through the commands 'add_help_text' and 'add_usage_text'.
|
||||||
* on obtaining a dynamically created context. The value will be available
|
* @param cmd_ctx The context that will be cleared of registered helps.
|
||||||
* in command handlers by using the CMD_DATA macro.
|
* @returns ERROR_OK on success, or an error code.
|
||||||
* @param c The command (group) whose data pointer(s) will be updated.
|
|
||||||
* @param p The new data pointer to use for the command or its descendents.
|
|
||||||
*/
|
*/
|
||||||
void command_set_handler_data(struct command *c, void *p);
|
int help_del_all_commands(struct command_context *cmd_ctx);
|
||||||
|
|
||||||
void command_set_output_handler(struct command_context *context,
|
void command_set_output_handler(struct command_context *context,
|
||||||
command_output_handler_t output_handler, void *priv);
|
command_output_handler_t output_handler, void *priv);
|
||||||
|
@ -408,6 +456,4 @@ COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label);
|
||||||
#define COMMAND_PARSE_ENABLE(in, out) \
|
#define COMMAND_PARSE_ENABLE(in, out) \
|
||||||
COMMAND_PARSE_BOOL(in, out, "enable", "disable")
|
COMMAND_PARSE_BOOL(in, out, "enable", "disable")
|
||||||
|
|
||||||
void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const *argv);
|
|
||||||
|
|
||||||
#endif /* OPENOCD_HELPER_COMMAND_H */
|
#endif /* OPENOCD_HELPER_COMMAND_H */
|
||||||
|
|
|
@ -333,9 +333,3 @@ const char *Jim_Debug_ArgvString(Jim_Interp *interp, int argc, Jim_Obj *const *a
|
||||||
|
|
||||||
return Jim_String(debug_string_obj);
|
return Jim_String(debug_string_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Jim_nvpInit(Jim_Interp *interp)
|
|
||||||
{
|
|
||||||
/* This is really a helper library, not an extension, but this is the easy way */
|
|
||||||
return JIM_OK;
|
|
||||||
}
|
|
||||||
|
|
|
@ -242,13 +242,13 @@ static inline int socket_select(int max_fd,
|
||||||
typedef uint32_t Elf32_Addr;
|
typedef uint32_t Elf32_Addr;
|
||||||
typedef uint16_t Elf32_Half;
|
typedef uint16_t Elf32_Half;
|
||||||
typedef uint32_t Elf32_Off;
|
typedef uint32_t Elf32_Off;
|
||||||
typedef int32_t Elf32_Sword;
|
|
||||||
typedef uint32_t Elf32_Word;
|
typedef uint32_t Elf32_Word;
|
||||||
typedef uint32_t Elf32_Size;
|
typedef uint32_t Elf32_Size;
|
||||||
typedef Elf32_Off Elf32_Hashelt;
|
|
||||||
|
#define EI_NIDENT 16
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned char e_ident[16]; /* Magic number and other info */
|
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
|
||||||
Elf32_Half e_type; /* Object file type */
|
Elf32_Half e_type; /* Object file type */
|
||||||
Elf32_Half e_machine; /* Architecture */
|
Elf32_Half e_machine; /* Architecture */
|
||||||
Elf32_Word e_version; /* Object file version */
|
Elf32_Word e_version; /* Object file version */
|
||||||
|
@ -290,6 +290,44 @@ typedef struct {
|
||||||
|
|
||||||
#endif /* HAVE_ELF_H */
|
#endif /* HAVE_ELF_H */
|
||||||
|
|
||||||
|
#ifndef HAVE_ELF64
|
||||||
|
|
||||||
|
typedef uint64_t Elf64_Addr;
|
||||||
|
typedef uint16_t Elf64_Half;
|
||||||
|
typedef uint64_t Elf64_Off;
|
||||||
|
typedef uint32_t Elf64_Word;
|
||||||
|
typedef uint64_t Elf64_Xword;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
|
||||||
|
Elf64_Half e_type; /* Object file type */
|
||||||
|
Elf64_Half e_machine; /* Architecture */
|
||||||
|
Elf64_Word e_version; /* Object file version */
|
||||||
|
Elf64_Addr e_entry; /* Entry point virtual address */
|
||||||
|
Elf64_Off e_phoff; /* Program header table file offset */
|
||||||
|
Elf64_Off e_shoff; /* Section header table file offset */
|
||||||
|
Elf64_Word e_flags; /* Processor-specific flags */
|
||||||
|
Elf64_Half e_ehsize; /* ELF header size in bytes */
|
||||||
|
Elf64_Half e_phentsize; /* Program header table entry size */
|
||||||
|
Elf64_Half e_phnum; /* Program header table entry count */
|
||||||
|
Elf64_Half e_shentsize; /* Section header table entry size */
|
||||||
|
Elf64_Half e_shnum; /* Section header table entry count */
|
||||||
|
Elf64_Half e_shstrndx; /* Section header string table index */
|
||||||
|
} Elf64_Ehdr;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Elf64_Word p_type; /* Segment type */
|
||||||
|
Elf64_Word p_flags; /* Segment flags */
|
||||||
|
Elf64_Off p_offset; /* Segment file offset */
|
||||||
|
Elf64_Addr p_vaddr; /* Segment virtual address */
|
||||||
|
Elf64_Addr p_paddr; /* Segment physical address */
|
||||||
|
Elf64_Xword p_filesz; /* Segment size in file */
|
||||||
|
Elf64_Xword p_memsz; /* Segment size in memory */
|
||||||
|
Elf64_Xword p_align; /* Segment alignment */
|
||||||
|
} Elf64_Phdr;
|
||||||
|
|
||||||
|
#endif /* HAVE_ELF64 */
|
||||||
|
|
||||||
#if defined HAVE_LIBUSB1 && !defined HAVE_LIBUSB_ERROR_NAME
|
#if defined HAVE_LIBUSB1 && !defined HAVE_LIBUSB_ERROR_NAME
|
||||||
const char *libusb_error_name(int error_code);
|
const char *libusb_error_name(int error_code);
|
||||||
#endif /* defined HAVE_LIBUSB1 && !defined HAVE_LIBUSB_ERROR_NAME */
|
#endif /* defined HAVE_LIBUSB1 && !defined HAVE_LIBUSB_ERROR_NAME */
|
||||||
|
|
|
@ -21,6 +21,15 @@
|
||||||
#ifndef OPENOCD_HELPER_SYSTEM_H
|
#ifndef OPENOCD_HELPER_SYSTEM_H
|
||||||
#define OPENOCD_HELPER_SYSTEM_H
|
#define OPENOCD_HELPER_SYSTEM_H
|
||||||
|
|
||||||
|
/* +++ platform specific headers +++ */
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#endif
|
||||||
|
/* --- platform specific headers --- */
|
||||||
|
|
||||||
/* standard C library header files */
|
/* standard C library header files */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -34,15 +43,6 @@
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* +++ platform specific headers +++ */
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <winsock2.h>
|
|
||||||
#include <ws2tcpip.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#endif
|
|
||||||
/* --- platform specific headers --- */
|
|
||||||
|
|
||||||
#ifdef HAVE_SYS_SOCKET_H
|
#ifdef HAVE_SYS_SOCKET_H
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -47,16 +47,10 @@
|
||||||
#ifndef __cplusplus
|
#ifndef __cplusplus
|
||||||
|
|
||||||
#define false 0
|
#define false 0
|
||||||
#define true 1
|
#define true 1
|
||||||
|
|
||||||
typedef int _Bool;
|
|
||||||
#else
|
|
||||||
typedef bool _Bool;
|
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#endif /* HAVE__BOOL */
|
#endif /* HAVE__BOOL */
|
||||||
|
|
||||||
#define bool _Bool
|
|
||||||
|
|
||||||
#endif /* HAVE_STDBOOL_H */
|
#endif /* HAVE_STDBOOL_H */
|
||||||
|
|
||||||
/// turns a macro argument into a string constant
|
/// turns a macro argument into a string constant
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <helper/system.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -256,9 +256,8 @@ static int jim_aice_arp_init_reset(Jim_Interp *interp, int argc, Jim_Obj * const
|
||||||
e = aice_init_reset(context);
|
e = aice_init_reset(context);
|
||||||
|
|
||||||
if (e != ERROR_OK) {
|
if (e != ERROR_OK) {
|
||||||
Jim_Obj *eObj = Jim_NewIntObj(goi.interp, e);
|
Jim_Obj *obj = Jim_NewIntObj(goi.interp, e);
|
||||||
Jim_SetResultFormatted(goi.interp, "error: %#s", eObj);
|
Jim_SetResultFormatted(goi.interp, "error: %#s", obj);
|
||||||
Jim_FreeNewObj(goi.interp, eObj);
|
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
}
|
}
|
||||||
return JIM_OK;
|
return JIM_OK;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <helper/system.h>
|
||||||
#include <jtag/drivers/libusb_helper.h>
|
#include <jtag/drivers/libusb_helper.h>
|
||||||
#include <helper/log.h>
|
#include <helper/log.h>
|
||||||
#include <helper/time_support.h>
|
#include <helper/time_support.h>
|
||||||
|
@ -350,8 +351,8 @@ static void aice_unpack_dthmb(uint8_t *cmd_ack_code, uint8_t *target_id,
|
||||||
/* calls the given usb_bulk_* function, allowing for the data to
|
/* calls the given usb_bulk_* function, allowing for the data to
|
||||||
* trickle in with some timeouts */
|
* trickle in with some timeouts */
|
||||||
static int usb_bulk_with_retries(
|
static int usb_bulk_with_retries(
|
||||||
int (*f)(libusb_device_handle *, int, char *, int, int, int *),
|
int (*f)(struct libusb_device_handle *, int, char *, int, int, int *),
|
||||||
libusb_device_handle *dev, int ep,
|
struct libusb_device_handle *dev, int ep,
|
||||||
char *bytes, int size, int timeout, int *transferred)
|
char *bytes, int size, int timeout, int *transferred)
|
||||||
{
|
{
|
||||||
int tries = 3, count = 0;
|
int tries = 3, count = 0;
|
||||||
|
@ -370,7 +371,7 @@ static int usb_bulk_with_retries(
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wrap_usb_bulk_write(libusb_device_handle *dev, int ep,
|
static int wrap_usb_bulk_write(struct libusb_device_handle *dev, int ep,
|
||||||
char *buff, int size, int timeout, int *transferred)
|
char *buff, int size, int timeout, int *transferred)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -380,7 +381,7 @@ static int wrap_usb_bulk_write(libusb_device_handle *dev, int ep,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int usb_bulk_write_ex(libusb_device_handle *dev, int ep,
|
static inline int usb_bulk_write_ex(struct libusb_device_handle *dev, int ep,
|
||||||
char *bytes, int size, int timeout)
|
char *bytes, int size, int timeout)
|
||||||
{
|
{
|
||||||
int tr = 0;
|
int tr = 0;
|
||||||
|
|
|
@ -137,6 +137,7 @@ static bool swd_mode;
|
||||||
|
|
||||||
/* CMSIS-DAP SWD Commands */
|
/* CMSIS-DAP SWD Commands */
|
||||||
#define CMD_DAP_SWD_CONFIGURE 0x13
|
#define CMD_DAP_SWD_CONFIGURE 0x13
|
||||||
|
#define CMD_DAP_SWD_SEQUENCE 0x1D
|
||||||
|
|
||||||
/* CMSIS-DAP JTAG Commands */
|
/* CMSIS-DAP JTAG Commands */
|
||||||
#define CMD_DAP_JTAG_SEQ 0x14
|
#define CMD_DAP_JTAG_SEQ 0x14
|
||||||
|
@ -222,6 +223,8 @@ static uint8_t output_pins = SWJ_PIN_SRST | SWJ_PIN_TRST;
|
||||||
static struct cmsis_dap *cmsis_dap_handle;
|
static struct cmsis_dap *cmsis_dap_handle;
|
||||||
|
|
||||||
|
|
||||||
|
static int cmsis_dap_quit(void);
|
||||||
|
|
||||||
static int cmsis_dap_open(void)
|
static int cmsis_dap_open(void)
|
||||||
{
|
{
|
||||||
const struct cmsis_dap_backend *backend = NULL;
|
const struct cmsis_dap_backend *backend = NULL;
|
||||||
|
@ -280,6 +283,21 @@ static void cmsis_dap_close(struct cmsis_dap *dap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cmsis_dap_flush_read(struct cmsis_dap *dap)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
/* Some CMSIS-DAP adapters keep buffered packets over
|
||||||
|
* USB close/open so we need to flush up to 64 old packets
|
||||||
|
* to be sure all buffers are empty */
|
||||||
|
for (i = 0; i < 64; i++) {
|
||||||
|
int retval = dap->backend->read(dap, 10);
|
||||||
|
if (retval == ERROR_TIMEOUT_REACHED)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i)
|
||||||
|
LOG_DEBUG("Flushed %u packets", i);
|
||||||
|
}
|
||||||
|
|
||||||
/* Send a message and receive the reply */
|
/* Send a message and receive the reply */
|
||||||
static int cmsis_dap_xfer(struct cmsis_dap *dap, int txlen)
|
static int cmsis_dap_xfer(struct cmsis_dap *dap, int txlen)
|
||||||
{
|
{
|
||||||
|
@ -293,6 +311,7 @@ static int cmsis_dap_xfer(struct cmsis_dap *dap, int txlen)
|
||||||
pending_fifo_get_idx = 0;
|
pending_fifo_get_idx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t current_cmd = cmsis_dap_handle->command[0];
|
||||||
int retval = dap->backend->write(dap, txlen, USB_TIMEOUT);
|
int retval = dap->backend->write(dap, txlen, USB_TIMEOUT);
|
||||||
if (retval < 0)
|
if (retval < 0)
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -302,6 +321,20 @@ static int cmsis_dap_xfer(struct cmsis_dap *dap, int txlen)
|
||||||
if (retval < 0)
|
if (retval < 0)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
uint8_t *resp = cmsis_dap_handle->response;
|
||||||
|
if (resp[0] == DAP_ERROR) {
|
||||||
|
LOG_ERROR("CMSIS-DAP command 0x%" PRIx8 " not implemented", current_cmd);
|
||||||
|
return ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resp[0] != current_cmd) {
|
||||||
|
LOG_ERROR("CMSIS-DAP command mismatch. Sent 0x%" PRIx8
|
||||||
|
" received 0x%" PRIx8, current_cmd, resp[0]);
|
||||||
|
|
||||||
|
cmsis_dap_flush_read(dap);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,6 +544,45 @@ static int cmsis_dap_cmd_DAP_Delay(uint16_t delay_us)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int cmsis_dap_metacmd_targetsel(uint32_t instance_id)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
uint8_t *command = cmsis_dap_handle->command;
|
||||||
|
const uint32_t SEQ_RD = 0x80, SEQ_WR = 0x00;
|
||||||
|
|
||||||
|
/* SWD multi-drop requires a transfer ala CMD_DAP_TFER,
|
||||||
|
but with no expectation of an SWD ACK response. In
|
||||||
|
CMSIS-DAP v1.20 and v2.00, CMD_DAP_SWD_SEQUENCE was
|
||||||
|
added to allow this special sequence to be generated.
|
||||||
|
The purpose of this operation is to select the target
|
||||||
|
corresponding to the instance_id that is written */
|
||||||
|
|
||||||
|
size_t idx = 0;
|
||||||
|
command[idx++] = CMD_DAP_SWD_SEQUENCE;
|
||||||
|
command[idx++] = 3; /* sequence count */
|
||||||
|
|
||||||
|
/* sequence 0: packet request for TARGETSEL */
|
||||||
|
command[idx++] = SEQ_WR | 8;
|
||||||
|
command[idx++] = SWD_CMD_START | swd_cmd(false, false, DP_TARGETSEL) | SWD_CMD_STOP | SWD_CMD_PARK;
|
||||||
|
|
||||||
|
/* sequence 1: read Trn ACK Trn, no expectation for target to ACK */
|
||||||
|
command[idx++] = SEQ_RD | 5;
|
||||||
|
|
||||||
|
/* sequence 2: WDATA plus parity */
|
||||||
|
command[idx++] = SEQ_WR | (32 + 1);
|
||||||
|
h_u32_to_le(command + idx, instance_id);
|
||||||
|
idx += 4;
|
||||||
|
command[idx++] = parity_u32(instance_id);
|
||||||
|
|
||||||
|
retval = cmsis_dap_xfer(cmsis_dap_handle, idx);
|
||||||
|
|
||||||
|
if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) {
|
||||||
|
LOG_ERROR("CMSIS-DAP command SWD_Sequence failed.");
|
||||||
|
return ERROR_JTAG_DEVICE_ERROR;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap)
|
static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap)
|
||||||
{
|
{
|
||||||
uint8_t *command = cmsis_dap_handle->command;
|
uint8_t *command = cmsis_dap_handle->command;
|
||||||
|
@ -606,6 +678,13 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *resp = dap->response;
|
uint8_t *resp = dap->response;
|
||||||
|
if (resp[0] != CMD_DAP_TFER) {
|
||||||
|
LOG_ERROR("CMSIS-DAP command mismatch. Expected 0x%" PRIx8
|
||||||
|
" received 0x%" PRIx8, CMD_DAP_TFER, resp[0]);
|
||||||
|
queued_retval = ERROR_FAIL;
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t transfer_count = resp[1];
|
uint8_t transfer_count = resp[1];
|
||||||
uint8_t ack = resp[2] & 0x07;
|
uint8_t ack = resp[2] & 0x07;
|
||||||
if (resp[2] & 0x08) {
|
if (resp[2] & 0x08) {
|
||||||
|
@ -617,6 +696,7 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms)
|
||||||
LOG_DEBUG("SWD ack not OK @ %d %s", transfer_count,
|
LOG_DEBUG("SWD ack not OK @ %d %s", transfer_count,
|
||||||
ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
|
ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
|
||||||
queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL;
|
queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL;
|
||||||
|
/* TODO: use results of transfers completed before the error occurred? */
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -676,7 +756,10 @@ static int cmsis_dap_swd_run_queue(void)
|
||||||
|
|
||||||
static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data)
|
static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data)
|
||||||
{
|
{
|
||||||
if (pending_fifo[pending_fifo_put_idx].transfer_count == pending_queue_len) {
|
bool targetsel_cmd = swd_cmd(false, false, DP_TARGETSEL) == cmd;
|
||||||
|
|
||||||
|
if (pending_fifo[pending_fifo_put_idx].transfer_count == pending_queue_len
|
||||||
|
|| targetsel_cmd) {
|
||||||
if (pending_fifo_block_count)
|
if (pending_fifo_block_count)
|
||||||
cmsis_dap_swd_read_process(cmsis_dap_handle, 0);
|
cmsis_dap_swd_read_process(cmsis_dap_handle, 0);
|
||||||
|
|
||||||
|
@ -690,6 +773,11 @@ static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data)
|
||||||
if (queued_retval != ERROR_OK)
|
if (queued_retval != ERROR_OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (targetsel_cmd) {
|
||||||
|
cmsis_dap_metacmd_targetsel(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
struct pending_request_block *block = &pending_fifo[pending_fifo_put_idx];
|
struct pending_request_block *block = &pending_fifo[pending_fifo_put_idx];
|
||||||
struct pending_transfer_result *transfer = &(block->transfers[block->transfer_count]);
|
struct pending_transfer_result *transfer = &(block->transfers[block->transfer_count]);
|
||||||
transfer->data = data;
|
transfer->data = data;
|
||||||
|
@ -807,7 +895,7 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq)
|
||||||
|
|
||||||
switch (seq) {
|
switch (seq) {
|
||||||
case LINE_RESET:
|
case LINE_RESET:
|
||||||
LOG_DEBUG("SWD line reset");
|
LOG_DEBUG_IO("SWD line reset");
|
||||||
s = swd_seq_line_reset;
|
s = swd_seq_line_reset;
|
||||||
s_len = swd_seq_line_reset_len;
|
s_len = swd_seq_line_reset_len;
|
||||||
break;
|
break;
|
||||||
|
@ -816,11 +904,26 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq)
|
||||||
s = swd_seq_jtag_to_swd;
|
s = swd_seq_jtag_to_swd;
|
||||||
s_len = swd_seq_jtag_to_swd_len;
|
s_len = swd_seq_jtag_to_swd_len;
|
||||||
break;
|
break;
|
||||||
|
case JTAG_TO_DORMANT:
|
||||||
|
LOG_DEBUG("JTAG-to-DORMANT");
|
||||||
|
s = swd_seq_jtag_to_dormant;
|
||||||
|
s_len = swd_seq_jtag_to_dormant_len;
|
||||||
|
break;
|
||||||
case SWD_TO_JTAG:
|
case SWD_TO_JTAG:
|
||||||
LOG_DEBUG("SWD-to-JTAG");
|
LOG_DEBUG("SWD-to-JTAG");
|
||||||
s = swd_seq_swd_to_jtag;
|
s = swd_seq_swd_to_jtag;
|
||||||
s_len = swd_seq_swd_to_jtag_len;
|
s_len = swd_seq_swd_to_jtag_len;
|
||||||
break;
|
break;
|
||||||
|
case SWD_TO_DORMANT:
|
||||||
|
LOG_DEBUG("SWD-to-DORMANT");
|
||||||
|
s = swd_seq_swd_to_dormant;
|
||||||
|
s_len = swd_seq_swd_to_dormant_len;
|
||||||
|
break;
|
||||||
|
case DORMANT_TO_SWD:
|
||||||
|
LOG_DEBUG("DORMANT-to-SWD");
|
||||||
|
s = swd_seq_dormant_to_swd;
|
||||||
|
s_len = swd_seq_dormant_to_swd_len;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_ERROR("Sequence %d not supported", seq);
|
LOG_ERROR("Sequence %d not supported", seq);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
@ -863,6 +966,8 @@ static int cmsis_dap_init(void)
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
cmsis_dap_flush_read(cmsis_dap_handle);
|
||||||
|
|
||||||
retval = cmsis_dap_get_caps_info();
|
retval = cmsis_dap_get_caps_info();
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -901,7 +1006,7 @@ static int cmsis_dap_init(void)
|
||||||
/* INFO_ID_PKT_SZ - short */
|
/* INFO_ID_PKT_SZ - short */
|
||||||
retval = cmsis_dap_cmd_DAP_Info(INFO_ID_PKT_SZ, &data);
|
retval = cmsis_dap_cmd_DAP_Info(INFO_ID_PKT_SZ, &data);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
goto init_err;
|
||||||
|
|
||||||
if (data[0] == 2) { /* short */
|
if (data[0] == 2) { /* short */
|
||||||
uint16_t pkt_sz = data[1] + (data[2] << 8);
|
uint16_t pkt_sz = data[1] + (data[2] << 8);
|
||||||
|
@ -915,7 +1020,7 @@ static int cmsis_dap_init(void)
|
||||||
free(cmsis_dap_handle->packet_buffer);
|
free(cmsis_dap_handle->packet_buffer);
|
||||||
retval = cmsis_dap_handle->backend->packet_buffer_alloc(cmsis_dap_handle, pkt_sz);
|
retval = cmsis_dap_handle->backend->packet_buffer_alloc(cmsis_dap_handle, pkt_sz);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
goto init_err;
|
||||||
|
|
||||||
LOG_DEBUG("CMSIS-DAP: Packet Size = %" PRIu16, pkt_sz);
|
LOG_DEBUG("CMSIS-DAP: Packet Size = %" PRIu16, pkt_sz);
|
||||||
}
|
}
|
||||||
|
@ -924,7 +1029,7 @@ static int cmsis_dap_init(void)
|
||||||
/* INFO_ID_PKT_CNT - byte */
|
/* INFO_ID_PKT_CNT - byte */
|
||||||
retval = cmsis_dap_cmd_DAP_Info(INFO_ID_PKT_CNT, &data);
|
retval = cmsis_dap_cmd_DAP_Info(INFO_ID_PKT_CNT, &data);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
goto init_err;
|
||||||
|
|
||||||
if (data[0] == 1) { /* byte */
|
if (data[0] == 1) { /* byte */
|
||||||
int pkt_cnt = data[1];
|
int pkt_cnt = data[1];
|
||||||
|
@ -939,43 +1044,40 @@ static int cmsis_dap_init(void)
|
||||||
pending_fifo[i].transfers = malloc(pending_queue_len * sizeof(struct pending_transfer_result));
|
pending_fifo[i].transfers = malloc(pending_queue_len * sizeof(struct pending_transfer_result));
|
||||||
if (!pending_fifo[i].transfers) {
|
if (!pending_fifo[i].transfers) {
|
||||||
LOG_ERROR("Unable to allocate memory for CMSIS-DAP queue");
|
LOG_ERROR("Unable to allocate memory for CMSIS-DAP queue");
|
||||||
return ERROR_FAIL;
|
retval = ERROR_FAIL;
|
||||||
|
goto init_err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Intentionally not checked for error, just logs an info message
|
||||||
retval = cmsis_dap_get_status();
|
* not vital for further debugging */
|
||||||
if (retval != ERROR_OK)
|
(void)cmsis_dap_get_status();
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
/* Now try to connect to the target
|
/* Now try to connect to the target
|
||||||
* TODO: This is all SWD only @ present */
|
* TODO: This is all SWD only @ present */
|
||||||
retval = cmsis_dap_cmd_DAP_SWJ_Clock(jtag_get_speed_khz());
|
retval = cmsis_dap_cmd_DAP_SWJ_Clock(jtag_get_speed_khz());
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
goto init_err;
|
||||||
|
|
||||||
/* Ask CMSIS-DAP to automatically retry on receiving WAIT for
|
/* Ask CMSIS-DAP to automatically retry on receiving WAIT for
|
||||||
* up to 64 times. This must be changed to 0 if sticky
|
* up to 64 times. This must be changed to 0 if sticky
|
||||||
* overrun detection is enabled. */
|
* overrun detection is enabled. */
|
||||||
retval = cmsis_dap_cmd_DAP_TFER_Configure(0, 64, 0);
|
retval = cmsis_dap_cmd_DAP_TFER_Configure(0, 64, 0);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
goto init_err;
|
||||||
|
|
||||||
if (swd_mode) {
|
if (swd_mode) {
|
||||||
/* Data Phase (bit 2) must be set to 1 if sticky overrun
|
/* Data Phase (bit 2) must be set to 1 if sticky overrun
|
||||||
* detection is enabled */
|
* detection is enabled */
|
||||||
retval = cmsis_dap_cmd_DAP_SWD_Configure(0); /* 1 TRN, no Data Phase */
|
retval = cmsis_dap_cmd_DAP_SWD_Configure(0); /* 1 TRN, no Data Phase */
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
goto init_err;
|
||||||
}
|
}
|
||||||
/* Both LEDs on */
|
/* Both LEDs on */
|
||||||
retval = cmsis_dap_cmd_DAP_LED(LED_ID_CONNECT, LED_ON);
|
/* Intentionally not checked for error, debugging will work
|
||||||
if (retval != ERROR_OK)
|
* without LEDs */
|
||||||
return ERROR_FAIL;
|
(void)cmsis_dap_cmd_DAP_LED(LED_ID_CONNECT, LED_ON);
|
||||||
|
(void)cmsis_dap_cmd_DAP_LED(LED_ID_RUN, LED_ON);
|
||||||
retval = cmsis_dap_cmd_DAP_LED(LED_ID_RUN, LED_ON);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
/* support connecting with srst asserted */
|
/* support connecting with srst asserted */
|
||||||
enum reset_types jtag_reset_config = jtag_get_reset_config();
|
enum reset_types jtag_reset_config = jtag_get_reset_config();
|
||||||
|
@ -984,13 +1086,16 @@ static int cmsis_dap_init(void)
|
||||||
if (jtag_reset_config & RESET_SRST_NO_GATING) {
|
if (jtag_reset_config & RESET_SRST_NO_GATING) {
|
||||||
retval = cmsis_dap_cmd_DAP_SWJ_Pins(0, SWJ_PIN_SRST, 0, NULL);
|
retval = cmsis_dap_cmd_DAP_SWJ_Pins(0, SWJ_PIN_SRST, 0, NULL);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
goto init_err;
|
||||||
LOG_INFO("Connecting under reset");
|
LOG_INFO("Connecting under reset");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG_INFO("CMSIS-DAP: Interface ready");
|
LOG_INFO("CMSIS-DAP: Interface ready");
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
||||||
|
init_err:
|
||||||
|
cmsis_dap_quit();
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmsis_dap_swd_init(void)
|
static int cmsis_dap_swd_init(void)
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <helper/system.h>
|
||||||
#include <libusb.h>
|
#include <libusb.h>
|
||||||
#include <helper/log.h>
|
#include <helper/log.h>
|
||||||
#include <helper/replacements.h>
|
#include <helper/replacements.h>
|
||||||
|
@ -42,8 +43,8 @@
|
||||||
#include "cmsis_dap.h"
|
#include "cmsis_dap.h"
|
||||||
|
|
||||||
struct cmsis_dap_backend_data {
|
struct cmsis_dap_backend_data {
|
||||||
libusb_context *usb_ctx;
|
struct libusb_context *usb_ctx;
|
||||||
libusb_device_handle *dev_handle;
|
struct libusb_device_handle *dev_handle;
|
||||||
unsigned int ep_out;
|
unsigned int ep_out;
|
||||||
unsigned int ep_in;
|
unsigned int ep_in;
|
||||||
int interface;
|
int interface;
|
||||||
|
@ -57,8 +58,8 @@ static int cmsis_dap_usb_alloc(struct cmsis_dap *dap, unsigned int pkt_sz);
|
||||||
static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], char *serial)
|
static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], char *serial)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
libusb_context *ctx;
|
struct libusb_context *ctx;
|
||||||
libusb_device **device_list;
|
struct libusb_device **device_list;
|
||||||
|
|
||||||
err = libusb_init(&ctx);
|
err = libusb_init(&ctx);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -74,7 +75,7 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < num_devices; i++) {
|
for (int i = 0; i < num_devices; i++) {
|
||||||
libusb_device *dev = device_list[i];
|
struct libusb_device *dev = device_list[i];
|
||||||
struct libusb_device_descriptor dev_desc;
|
struct libusb_device_descriptor dev_desc;
|
||||||
|
|
||||||
err = libusb_get_device_descriptor(dev, &dev_desc);
|
err = libusb_get_device_descriptor(dev, &dev_desc);
|
||||||
|
@ -102,7 +103,7 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p
|
||||||
if (dev_desc.iSerialNumber == 0 && serial && serial[0])
|
if (dev_desc.iSerialNumber == 0 && serial && serial[0])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
libusb_device_handle *dev_handle = NULL;
|
struct libusb_device_handle *dev_handle = NULL;
|
||||||
err = libusb_open(dev, &dev_handle);
|
err = libusb_open(dev, &dev_handle);
|
||||||
if (err) {
|
if (err) {
|
||||||
/* It's to be expected that most USB devices can't be opened
|
/* It's to be expected that most USB devices can't be opened
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
#include <hidapi.h>
|
#include <hidapi.h>
|
||||||
#include <helper/log.h>
|
#include <helper/log.h>
|
||||||
|
|
||||||
|
|
|
@ -547,7 +547,7 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
|
||||||
uint8_t last_bit = 0;
|
uint8_t last_bit = 0;
|
||||||
if (field->out_value)
|
if (field->out_value)
|
||||||
bit_copy(&last_bit, 0, field->out_value, field->num_bits - 1, 1);
|
bit_copy(&last_bit, 0, field->out_value, field->num_bits - 1, 1);
|
||||||
uint8_t tms_bits = 0x01;
|
uint8_t tms_bits = 0x03;
|
||||||
DO_CLOCK_TMS_CS(mpsse_ctx,
|
DO_CLOCK_TMS_CS(mpsse_ctx,
|
||||||
&tms_bits,
|
&tms_bits,
|
||||||
0,
|
0,
|
||||||
|
@ -557,13 +557,24 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
|
||||||
last_bit,
|
last_bit,
|
||||||
ftdi_jtag_mode);
|
ftdi_jtag_mode);
|
||||||
tap_set_state(tap_state_transition(tap_get_state(), 1));
|
tap_set_state(tap_state_transition(tap_get_state(), 1));
|
||||||
DO_CLOCK_TMS_CS_OUT(mpsse_ctx,
|
if (tap_get_end_state() == TAP_IDLE) {
|
||||||
&tms_bits,
|
DO_CLOCK_TMS_CS_OUT(mpsse_ctx,
|
||||||
1,
|
&tms_bits,
|
||||||
1,
|
1,
|
||||||
last_bit,
|
2,
|
||||||
ftdi_jtag_mode);
|
last_bit,
|
||||||
tap_set_state(tap_state_transition(tap_get_state(), 0));
|
ftdi_jtag_mode);
|
||||||
|
tap_set_state(tap_state_transition(tap_get_state(), 1));
|
||||||
|
tap_set_state(tap_state_transition(tap_get_state(), 0));
|
||||||
|
} else {
|
||||||
|
DO_CLOCK_TMS_CS_OUT(mpsse_ctx,
|
||||||
|
&tms_bits,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
last_bit,
|
||||||
|
ftdi_jtag_mode);
|
||||||
|
tap_set_state(tap_state_transition(tap_get_state(), 0));
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
DO_CLOCK_DATA(mpsse_ctx,
|
DO_CLOCK_DATA(mpsse_ctx,
|
||||||
field->out_value,
|
field->out_value,
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
#define MAX_USB_PORTS 7
|
#define MAX_USB_PORTS 7
|
||||||
|
|
||||||
static struct libusb_context *jtag_libusb_context; /**< Libusb context **/
|
static struct libusb_context *jtag_libusb_context; /**< Libusb context **/
|
||||||
static libusb_device **devs; /**< The usb device list **/
|
static struct libusb_device **devs; /**< The usb device list **/
|
||||||
|
|
||||||
static int jtag_libusb_error(int err)
|
static int jtag_libusb_error(int err)
|
||||||
{
|
{
|
||||||
|
@ -71,7 +71,7 @@ static bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS
|
#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS
|
||||||
static bool jtag_libusb_location_equal(libusb_device *device)
|
static bool jtag_libusb_location_equal(struct libusb_device *device)
|
||||||
{
|
{
|
||||||
uint8_t port_path[MAX_USB_PORTS];
|
uint8_t port_path[MAX_USB_PORTS];
|
||||||
uint8_t dev_bus;
|
uint8_t dev_bus;
|
||||||
|
@ -88,7 +88,7 @@ static bool jtag_libusb_location_equal(libusb_device *device)
|
||||||
return jtag_usb_location_equal(dev_bus, port_path, path_len);
|
return jtag_usb_location_equal(dev_bus, port_path, path_len);
|
||||||
}
|
}
|
||||||
#else /* HAVE_LIBUSB_GET_PORT_NUMBERS */
|
#else /* HAVE_LIBUSB_GET_PORT_NUMBERS */
|
||||||
static bool jtag_libusb_location_equal(libusb_device *device)
|
static bool jtag_libusb_location_equal(struct libusb_device *device)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ static bool jtag_libusb_location_equal(libusb_device *device)
|
||||||
|
|
||||||
|
|
||||||
/* Returns true if the string descriptor indexed by str_index in device matches string */
|
/* Returns true if the string descriptor indexed by str_index in device matches string */
|
||||||
static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_index,
|
static bool string_descriptor_equal(struct libusb_device_handle *device, uint8_t str_index,
|
||||||
const char *string)
|
const char *string)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
@ -123,7 +123,7 @@ static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_in
|
||||||
return matched;
|
return matched;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool jtag_libusb_match_serial(libusb_device_handle *device,
|
static bool jtag_libusb_match_serial(struct libusb_device_handle *device,
|
||||||
struct libusb_device_descriptor *dev_desc, const char *serial,
|
struct libusb_device_descriptor *dev_desc, const char *serial,
|
||||||
adapter_get_alternate_serial_fn adapter_get_alternate_serial)
|
adapter_get_alternate_serial_fn adapter_get_alternate_serial)
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
/* this callback should return a non NULL value only when the serial could not
|
/* this callback should return a non NULL value only when the serial could not
|
||||||
* be retrieved by the standard 'libusb_get_string_descriptor_ascii' */
|
* be retrieved by the standard 'libusb_get_string_descriptor_ascii' */
|
||||||
typedef char * (*adapter_get_alternate_serial_fn)(libusb_device_handle *device,
|
typedef char * (*adapter_get_alternate_serial_fn)(struct libusb_device_handle *device,
|
||||||
struct libusb_device_descriptor *dev_desc);
|
struct libusb_device_descriptor *dev_desc);
|
||||||
|
|
||||||
int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
|
int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
|
||||||
|
|
|
@ -63,8 +63,8 @@
|
||||||
#define SIO_RESET_PURGE_TX 2
|
#define SIO_RESET_PURGE_TX 2
|
||||||
|
|
||||||
struct mpsse_ctx {
|
struct mpsse_ctx {
|
||||||
libusb_context *usb_ctx;
|
struct libusb_context *usb_ctx;
|
||||||
libusb_device_handle *usb_dev;
|
struct libusb_device_handle *usb_dev;
|
||||||
unsigned int usb_write_timeout;
|
unsigned int usb_write_timeout;
|
||||||
unsigned int usb_read_timeout;
|
unsigned int usb_read_timeout;
|
||||||
uint8_t in_ep;
|
uint8_t in_ep;
|
||||||
|
@ -86,7 +86,7 @@ struct mpsse_ctx {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Returns true if the string descriptor indexed by str_index in device matches string */
|
/* Returns true if the string descriptor indexed by str_index in device matches string */
|
||||||
static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_index,
|
static bool string_descriptor_equal(struct libusb_device_handle *device, uint8_t str_index,
|
||||||
const char *string)
|
const char *string)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
@ -100,7 +100,7 @@ static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_in
|
||||||
return strncmp(string, desc_string, sizeof(desc_string)) == 0;
|
return strncmp(string, desc_string, sizeof(desc_string)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool device_location_equal(libusb_device *device, const char *location)
|
static bool device_location_equal(struct libusb_device *device, const char *location)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS
|
#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS
|
||||||
|
@ -162,7 +162,7 @@ static bool device_location_equal(libusb_device *device, const char *location)
|
||||||
static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, const uint16_t *pid,
|
static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, const uint16_t *pid,
|
||||||
const char *product, const char *serial, const char *location)
|
const char *product, const char *serial, const char *location)
|
||||||
{
|
{
|
||||||
libusb_device **list;
|
struct libusb_device **list;
|
||||||
struct libusb_device_descriptor desc;
|
struct libusb_device_descriptor desc;
|
||||||
struct libusb_config_descriptor *config0;
|
struct libusb_config_descriptor *config0;
|
||||||
int err;
|
int err;
|
||||||
|
@ -172,7 +172,7 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con
|
||||||
LOG_ERROR("libusb_get_device_list() failed with %s", libusb_error_name(cnt));
|
LOG_ERROR("libusb_get_device_list() failed with %s", libusb_error_name(cnt));
|
||||||
|
|
||||||
for (ssize_t i = 0; i < cnt; i++) {
|
for (ssize_t i = 0; i < cnt; i++) {
|
||||||
libusb_device *device = list[i];
|
struct libusb_device *device = list[i];
|
||||||
|
|
||||||
err = libusb_get_device_descriptor(device, &desc);
|
err = libusb_get_device_descriptor(device, &desc);
|
||||||
if (err != LIBUSB_SUCCESS) {
|
if (err != LIBUSB_SUCCESS) {
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
static char *remote_bitbang_host;
|
static char *remote_bitbang_host;
|
||||||
static char *remote_bitbang_port;
|
static char *remote_bitbang_port;
|
||||||
|
|
||||||
static FILE *remote_bitbang_file;
|
|
||||||
static int remote_bitbang_fd;
|
static int remote_bitbang_fd;
|
||||||
|
|
||||||
/* Circular buffer. When start == end, the buffer is empty. */
|
/* Circular buffer. When start == end, the buffer is empty. */
|
||||||
|
@ -65,7 +64,7 @@ static int remote_bitbang_fill_buf(void)
|
||||||
contiguous_available_space = remote_bitbang_start -
|
contiguous_available_space = remote_bitbang_start -
|
||||||
remote_bitbang_end - 1;
|
remote_bitbang_end - 1;
|
||||||
}
|
}
|
||||||
ssize_t count = read(remote_bitbang_fd,
|
ssize_t count = read_socket(remote_bitbang_fd,
|
||||||
remote_bitbang_buf + remote_bitbang_end,
|
remote_bitbang_buf + remote_bitbang_end,
|
||||||
contiguous_available_space);
|
contiguous_available_space);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
|
@ -75,11 +74,14 @@ static int remote_bitbang_fill_buf(void)
|
||||||
} else if (count == 0) {
|
} else if (count == 0) {
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
} else if (count < 0) {
|
} else if (count < 0) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (WSAGetLastError() == WSAEWOULDBLOCK) {
|
||||||
|
#else
|
||||||
if (errno == EAGAIN) {
|
if (errno == EAGAIN) {
|
||||||
|
#endif
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("remote_bitbang_fill_buf: %s (%d)",
|
log_socket_error("remote_bitbang_fill_buf");
|
||||||
strerror(errno), errno);
|
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,8 +92,10 @@ static int remote_bitbang_fill_buf(void)
|
||||||
|
|
||||||
static int remote_bitbang_putc(int c)
|
static int remote_bitbang_putc(int c)
|
||||||
{
|
{
|
||||||
if (EOF == fputc(c, remote_bitbang_file)) {
|
char buf = c;
|
||||||
LOG_ERROR("remote_bitbang_putc: %s", strerror(errno));
|
ssize_t count = write_socket(remote_bitbang_fd, &buf, sizeof(buf));
|
||||||
|
if (count < 0) {
|
||||||
|
log_socket_error("remote_bitbang_putc");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
@ -99,20 +103,11 @@ static int remote_bitbang_putc(int c)
|
||||||
|
|
||||||
static int remote_bitbang_quit(void)
|
static int remote_bitbang_quit(void)
|
||||||
{
|
{
|
||||||
if (EOF == fputc('Q', remote_bitbang_file)) {
|
if (remote_bitbang_putc('Q') == ERROR_FAIL)
|
||||||
LOG_ERROR("fputs: %s", strerror(errno));
|
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
if (EOF == fflush(remote_bitbang_file)) {
|
if (close_socket(remote_bitbang_fd) != 0) {
|
||||||
LOG_ERROR("fflush: %s", strerror(errno));
|
log_socket_error("close_socket");
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We only need to close one of the FILE*s, because they both use the same */
|
|
||||||
/* underlying file descriptor. */
|
|
||||||
if (EOF == fclose(remote_bitbang_file)) {
|
|
||||||
LOG_ERROR("fclose: %s", strerror(errno));
|
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,21 +135,16 @@ static bb_value_t char_to_int(int c)
|
||||||
/* Get the next read response. */
|
/* Get the next read response. */
|
||||||
static bb_value_t remote_bitbang_rread(void)
|
static bb_value_t remote_bitbang_rread(void)
|
||||||
{
|
{
|
||||||
if (EOF == fflush(remote_bitbang_file)) {
|
|
||||||
remote_bitbang_quit();
|
|
||||||
LOG_ERROR("fflush: %s", strerror(errno));
|
|
||||||
return BB_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Enable blocking access. */
|
/* Enable blocking access. */
|
||||||
socket_block(remote_bitbang_fd);
|
socket_block(remote_bitbang_fd);
|
||||||
char c;
|
char c;
|
||||||
ssize_t count = read(remote_bitbang_fd, &c, 1);
|
ssize_t count = read_socket(remote_bitbang_fd, &c, 1);
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
return char_to_int(c);
|
return char_to_int(c);
|
||||||
} else {
|
} else {
|
||||||
remote_bitbang_quit();
|
remote_bitbang_quit();
|
||||||
LOG_ERROR("read: count=%d, error=%s", (int) count, strerror(errno));
|
LOG_ERROR("read_socket: count=%d", (int) count);
|
||||||
|
log_socket_error("read_socket");
|
||||||
return BB_ERROR;
|
return BB_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,7 +230,7 @@ static int remote_bitbang_init_tcp(void)
|
||||||
freeaddrinfo(result); /* No longer needed */
|
freeaddrinfo(result); /* No longer needed */
|
||||||
|
|
||||||
if (rp == NULL) { /* No address succeeded */
|
if (rp == NULL) { /* No address succeeded */
|
||||||
LOG_ERROR("Failed to connect: %s", strerror(errno));
|
log_socket_error("Failed to connect");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,7 +247,7 @@ static int remote_bitbang_init_unix(void)
|
||||||
LOG_INFO("Connecting to unix socket %s", remote_bitbang_host);
|
LOG_INFO("Connecting to unix socket %s", remote_bitbang_host);
|
||||||
int fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
int fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
LOG_ERROR("socket: %s", strerror(errno));
|
log_socket_error("socket");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,7 +257,7 @@ static int remote_bitbang_init_unix(void)
|
||||||
addr.sun_path[sizeof(addr.sun_path)-1] = '\0';
|
addr.sun_path[sizeof(addr.sun_path)-1] = '\0';
|
||||||
|
|
||||||
if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
|
if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
|
||||||
LOG_ERROR("connect: %s", strerror(errno));
|
log_socket_error("connect");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,13 +280,6 @@ static int remote_bitbang_init(void)
|
||||||
if (remote_bitbang_fd < 0)
|
if (remote_bitbang_fd < 0)
|
||||||
return remote_bitbang_fd;
|
return remote_bitbang_fd;
|
||||||
|
|
||||||
remote_bitbang_file = fdopen(remote_bitbang_fd, "w+");
|
|
||||||
if (remote_bitbang_file == NULL) {
|
|
||||||
LOG_ERROR("fdopen: failed to open write stream");
|
|
||||||
close(remote_bitbang_fd);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_INFO("remote_bitbang driver initialized");
|
LOG_INFO("remote_bitbang driver initialized");
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,14 +97,14 @@
|
||||||
#define ST7_PC_TDO ST7_PC_IO9
|
#define ST7_PC_TDO ST7_PC_IO9
|
||||||
#define ST7_PA_DBGACK ST7_PA_IO10
|
#define ST7_PA_DBGACK ST7_PA_IO10
|
||||||
|
|
||||||
static libusb_device_handle *pHDev;
|
static struct libusb_device_handle *pHDev;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ep1 commands are up to USB_EP1OUT_SIZE bytes in length.
|
* ep1 commands are up to USB_EP1OUT_SIZE bytes in length.
|
||||||
* This function takes care of zeroing the unused bytes before sending the packet.
|
* This function takes care of zeroing the unused bytes before sending the packet.
|
||||||
* Any reply packet is not handled by this function.
|
* Any reply packet is not handled by this function.
|
||||||
*/
|
*/
|
||||||
static int ep1_generic_commandl(libusb_device_handle *pHDev_param, size_t length, ...)
|
static int ep1_generic_commandl(struct libusb_device_handle *pHDev_param, size_t length, ...)
|
||||||
{
|
{
|
||||||
uint8_t usb_buffer[USB_EP1OUT_SIZE];
|
uint8_t usb_buffer[USB_EP1OUT_SIZE];
|
||||||
uint8_t *usb_buffer_p;
|
uint8_t *usb_buffer_p;
|
||||||
|
@ -144,7 +144,7 @@ static int ep1_generic_commandl(libusb_device_handle *pHDev_param, size_t length
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static ssize_t ep1_memory_read(
|
static ssize_t ep1_memory_read(
|
||||||
libusb_device_handle *pHDev_param, uint16_t addr,
|
struct libusb_device_handle *pHDev_param, uint16_t addr,
|
||||||
size_t length, uint8_t *buffer)
|
size_t length, uint8_t *buffer)
|
||||||
{
|
{
|
||||||
uint8_t usb_buffer[USB_EP1OUT_SIZE];
|
uint8_t usb_buffer[USB_EP1OUT_SIZE];
|
||||||
|
@ -203,7 +203,7 @@ static ssize_t ep1_memory_read(
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static ssize_t ep1_memory_write(libusb_device_handle *pHDev_param, uint16_t addr,
|
static ssize_t ep1_memory_write(struct libusb_device_handle *pHDev_param, uint16_t addr,
|
||||||
size_t length, uint8_t const *buffer)
|
size_t length, uint8_t const *buffer)
|
||||||
{
|
{
|
||||||
uint8_t usb_buffer[USB_EP1OUT_SIZE];
|
uint8_t usb_buffer[USB_EP1OUT_SIZE];
|
||||||
|
@ -259,7 +259,7 @@ static ssize_t ep1_memory_write(libusb_device_handle *pHDev_param, uint16_t addr
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static ssize_t ep1_memory_writel(libusb_device_handle *pHDev_param, uint16_t addr,
|
static ssize_t ep1_memory_writel(struct libusb_device_handle *pHDev_param, uint16_t addr,
|
||||||
size_t length, ...)
|
size_t length, ...)
|
||||||
{
|
{
|
||||||
uint8_t buffer[USB_EP1OUT_SIZE - 4];
|
uint8_t buffer[USB_EP1OUT_SIZE - 4];
|
||||||
|
@ -296,7 +296,7 @@ static ssize_t ep1_memory_writel(libusb_device_handle *pHDev_param, uint16_t add
|
||||||
static uint8_t dtc_entry_download;
|
static uint8_t dtc_entry_download;
|
||||||
|
|
||||||
/* The buffer is specially formatted to represent a valid image to load into the DTC. */
|
/* The buffer is specially formatted to represent a valid image to load into the DTC. */
|
||||||
static int dtc_load_from_buffer(libusb_device_handle *pHDev_param, const uint8_t *buffer,
|
static int dtc_load_from_buffer(struct libusb_device_handle *pHDev_param, const uint8_t *buffer,
|
||||||
size_t length)
|
size_t length)
|
||||||
{
|
{
|
||||||
struct header_s {
|
struct header_s {
|
||||||
|
@ -470,7 +470,7 @@ static int dtc_start_download(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dtc_run_download(
|
static int dtc_run_download(
|
||||||
libusb_device_handle *pHDev_param,
|
struct libusb_device_handle *pHDev_param,
|
||||||
uint8_t *command_buffer,
|
uint8_t *command_buffer,
|
||||||
int command_buffer_size,
|
int command_buffer_size,
|
||||||
uint8_t *reply_buffer,
|
uint8_t *reply_buffer,
|
||||||
|
|
|
@ -3017,7 +3017,7 @@ static int stlink_close(void *handle)
|
||||||
* based on the length (0x1a = 26) we could easily decide if we have to fixup the serial
|
* based on the length (0x1a = 26) we could easily decide if we have to fixup the serial
|
||||||
* and then we have just to convert the raw data into printable characters using sprintf
|
* and then we have just to convert the raw data into printable characters using sprintf
|
||||||
*/
|
*/
|
||||||
static char *stlink_usb_get_alternate_serial(libusb_device_handle *device,
|
static char *stlink_usb_get_alternate_serial(struct libusb_device_handle *device,
|
||||||
struct libusb_device_descriptor *dev_desc)
|
struct libusb_device_descriptor *dev_desc)
|
||||||
{
|
{
|
||||||
int usb_retval;
|
int usb_retval;
|
||||||
|
|
|
@ -267,7 +267,7 @@ static int ulink_usb_open(struct ulink **device)
|
||||||
{
|
{
|
||||||
ssize_t num_devices, i;
|
ssize_t num_devices, i;
|
||||||
bool found;
|
bool found;
|
||||||
libusb_device **usb_devices;
|
struct libusb_device **usb_devices;
|
||||||
struct libusb_device_descriptor usb_desc;
|
struct libusb_device_descriptor usb_desc;
|
||||||
struct libusb_device_handle *usb_device_handle;
|
struct libusb_device_handle *usb_device_handle;
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,12 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "versaloon_include.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <libusb.h>
|
#include <libusb.h>
|
||||||
|
|
||||||
#include "versaloon_include.h"
|
|
||||||
#include "versaloon.h"
|
#include "versaloon.h"
|
||||||
#include "versaloon_internal.h"
|
#include "versaloon_internal.h"
|
||||||
#include "usbtoxxx/usbtoxxx.h"
|
#include "usbtoxxx/usbtoxxx.h"
|
||||||
|
@ -35,7 +36,7 @@ uint16_t versaloon_buf_size;
|
||||||
struct versaloon_pending_t versaloon_pending[VERSALOON_MAX_PENDING_NUMBER];
|
struct versaloon_pending_t versaloon_pending[VERSALOON_MAX_PENDING_NUMBER];
|
||||||
uint16_t versaloon_pending_idx;
|
uint16_t versaloon_pending_idx;
|
||||||
|
|
||||||
libusb_device_handle *versaloon_usb_device_handle;
|
struct libusb_device_handle *versaloon_usb_device_handle;
|
||||||
static uint32_t versaloon_usb_to = VERSALOON_TIMEOUT;
|
static uint32_t versaloon_usb_to = VERSALOON_TIMEOUT;
|
||||||
|
|
||||||
static RESULT versaloon_init(void);
|
static RESULT versaloon_init(void);
|
||||||
|
|
|
@ -107,6 +107,6 @@ struct versaloon_interface_t {
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct versaloon_interface_t versaloon_interface;
|
extern struct versaloon_interface_t versaloon_interface;
|
||||||
extern libusb_device_handle *versaloon_usb_device_handle;
|
extern struct libusb_device_handle *versaloon_usb_device_handle;
|
||||||
|
|
||||||
#endif /* OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_H */
|
#endif /* OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_H */
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#ifndef OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_INCLUDE_H
|
#ifndef OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_INCLUDE_H
|
||||||
#define OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_INCLUDE_H
|
#define OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_INCLUDE_H
|
||||||
|
|
||||||
|
#include "helper/system.h"
|
||||||
/* This file is used to include different header and macros */
|
/* This file is used to include different header and macros */
|
||||||
/* according to different platform */
|
/* according to different platform */
|
||||||
#include <jtag/interface.h>
|
#include <jtag/interface.h>
|
||||||
|
|
|
@ -812,7 +812,7 @@ static int vsllink_check_usb_strings(
|
||||||
static int vsllink_usb_open(struct vsllink *vsllink)
|
static int vsllink_usb_open(struct vsllink *vsllink)
|
||||||
{
|
{
|
||||||
ssize_t num_devices, i;
|
ssize_t num_devices, i;
|
||||||
libusb_device **usb_devices;
|
struct libusb_device **usb_devices;
|
||||||
struct libusb_device_descriptor usb_desc;
|
struct libusb_device_descriptor usb_desc;
|
||||||
struct libusb_device_handle *usb_device_handle;
|
struct libusb_device_handle *usb_device_handle;
|
||||||
int retval;
|
int retval;
|
||||||
|
@ -823,7 +823,7 @@ static int vsllink_usb_open(struct vsllink *vsllink)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
for (i = 0; i < num_devices; i++) {
|
for (i = 0; i < num_devices; i++) {
|
||||||
libusb_device *device = usb_devices[i];
|
struct libusb_device *device = usb_devices[i];
|
||||||
|
|
||||||
retval = libusb_get_device_descriptor(device, &usb_desc);
|
retval = libusb_get_device_descriptor(device, &usb_desc);
|
||||||
if (retval != 0)
|
if (retval != 0)
|
||||||
|
|
|
@ -213,8 +213,8 @@ struct scan_result {
|
||||||
|
|
||||||
struct xds110_info {
|
struct xds110_info {
|
||||||
/* USB connection handles and data buffers */
|
/* USB connection handles and data buffers */
|
||||||
libusb_context *ctx;
|
struct libusb_context *ctx;
|
||||||
libusb_device_handle *dev;
|
struct libusb_device_handle *dev;
|
||||||
unsigned char read_payload[USB_PAYLOAD_SIZE];
|
unsigned char read_payload[USB_PAYLOAD_SIZE];
|
||||||
unsigned char write_packet[3];
|
unsigned char write_packet[3];
|
||||||
unsigned char write_payload[USB_PAYLOAD_SIZE];
|
unsigned char write_payload[USB_PAYLOAD_SIZE];
|
||||||
|
@ -317,9 +317,9 @@ static inline uint16_t xds110_get_u16(uint8_t *buffer)
|
||||||
|
|
||||||
static bool usb_connect(void)
|
static bool usb_connect(void)
|
||||||
{
|
{
|
||||||
libusb_context *ctx = NULL;
|
struct libusb_context *ctx = NULL;
|
||||||
libusb_device **list = NULL;
|
struct libusb_device **list = NULL;
|
||||||
libusb_device_handle *dev = NULL;
|
struct libusb_device_handle *dev = NULL;
|
||||||
|
|
||||||
struct libusb_device_descriptor desc;
|
struct libusb_device_descriptor desc;
|
||||||
|
|
||||||
|
|
|
@ -108,8 +108,6 @@ static int Jim_Command_drscan(Jim_Interp *interp, int argc, Jim_Obj *const *args
|
||||||
|
|
||||||
endstate = TAP_IDLE;
|
endstate = TAP_IDLE;
|
||||||
|
|
||||||
script_debug(interp, argc, args);
|
|
||||||
|
|
||||||
/* validate arguments as numbers */
|
/* validate arguments as numbers */
|
||||||
e = JIM_OK;
|
e = JIM_OK;
|
||||||
for (i = 2; i < argc; i += 2) {
|
for (i = 2; i < argc; i += 2) {
|
||||||
|
@ -234,8 +232,6 @@ static int Jim_Command_pathmove(Jim_Interp *interp, int argc, Jim_Obj *const *ar
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
script_debug(interp, argc, args);
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < argc-1; i++) {
|
for (i = 0; i < argc-1; i++) {
|
||||||
const char *cp;
|
const char *cp;
|
||||||
|
@ -266,8 +262,6 @@ static int Jim_Command_pathmove(Jim_Interp *interp, int argc, Jim_Obj *const *ar
|
||||||
|
|
||||||
static int Jim_Command_flush_count(Jim_Interp *interp, int argc, Jim_Obj *const *args)
|
static int Jim_Command_flush_count(Jim_Interp *interp, int argc, Jim_Obj *const *args)
|
||||||
{
|
{
|
||||||
script_debug(interp, argc, args);
|
|
||||||
|
|
||||||
Jim_SetResult(interp, Jim_NewIntObj(interp, jtag_get_flush_queue_count()));
|
Jim_SetResult(interp, Jim_NewIntObj(interp, jtag_get_flush_queue_count()));
|
||||||
|
|
||||||
return JIM_OK;
|
return JIM_OK;
|
||||||
|
@ -693,10 +687,8 @@ static int jim_jtag_arp_init(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||||
struct command_context *context = current_command_context(interp);
|
struct command_context *context = current_command_context(interp);
|
||||||
int e = jtag_init_inner(context);
|
int e = jtag_init_inner(context);
|
||||||
if (e != ERROR_OK) {
|
if (e != ERROR_OK) {
|
||||||
Jim_Obj *eObj = Jim_NewIntObj(goi.interp, e);
|
Jim_Obj *obj = Jim_NewIntObj(goi.interp, e);
|
||||||
Jim_IncrRefCount(eObj);
|
Jim_SetResultFormatted(goi.interp, "error: %#s", obj);
|
||||||
Jim_SetResultFormatted(goi.interp, "error: %#s", eObj);
|
|
||||||
Jim_DecrRefCount(goi.interp, eObj);
|
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
}
|
}
|
||||||
return JIM_OK;
|
return JIM_OK;
|
||||||
|
@ -718,10 +710,8 @@ static int jim_jtag_arp_init_reset(Jim_Interp *interp, int argc, Jim_Obj *const
|
||||||
e = swd_init_reset(context);
|
e = swd_init_reset(context);
|
||||||
|
|
||||||
if (e != ERROR_OK) {
|
if (e != ERROR_OK) {
|
||||||
Jim_Obj *eObj = Jim_NewIntObj(goi.interp, e);
|
Jim_Obj *obj = Jim_NewIntObj(goi.interp, e);
|
||||||
Jim_IncrRefCount(eObj);
|
Jim_SetResultFormatted(goi.interp, "error: %#s", obj);
|
||||||
Jim_SetResultFormatted(goi.interp, "error: %#s", eObj);
|
|
||||||
Jim_DecrRefCount(goi.interp, eObj);
|
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
}
|
}
|
||||||
return JIM_OK;
|
return JIM_OK;
|
||||||
|
@ -767,7 +757,8 @@ static bool jtag_tap_disable(struct jtag_tap *t)
|
||||||
|
|
||||||
int jim_jtag_tap_enabler(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
int jim_jtag_tap_enabler(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||||
{
|
{
|
||||||
const char *cmd_name = Jim_GetString(argv[0], NULL);
|
struct command *c = jim_to_command(interp);
|
||||||
|
const char *cmd_name = c->name;
|
||||||
Jim_GetOptInfo goi;
|
Jim_GetOptInfo goi;
|
||||||
Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1);
|
Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1);
|
||||||
if (goi.argc != 1) {
|
if (goi.argc != 1) {
|
||||||
|
@ -804,7 +795,8 @@ int jim_jtag_tap_enabler(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||||
|
|
||||||
int jim_jtag_configure(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
int jim_jtag_configure(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||||
{
|
{
|
||||||
const char *cmd_name = Jim_GetString(argv[0], NULL);
|
struct command *c = jim_to_command(interp);
|
||||||
|
const char *cmd_name = c->name;
|
||||||
Jim_GetOptInfo goi;
|
Jim_GetOptInfo goi;
|
||||||
Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1);
|
Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1);
|
||||||
goi.isconfigure = !strcmp(cmd_name, "configure");
|
goi.isconfigure = !strcmp(cmd_name, "configure");
|
||||||
|
|
|
@ -361,6 +361,7 @@ int openocd_main(int argc, char *argv[])
|
||||||
server_free();
|
server_free();
|
||||||
|
|
||||||
unregister_all_commands(cmd_ctx, NULL);
|
unregister_all_commands(cmd_ctx, NULL);
|
||||||
|
help_del_all_commands(cmd_ctx);
|
||||||
|
|
||||||
/* free all DAP and CTI objects */
|
/* free all DAP and CTI objects */
|
||||||
dap_cleanup_all();
|
dap_cleanup_all();
|
||||||
|
|
|
@ -188,8 +188,7 @@ static int pld_init(struct command_context *cmd_ctx)
|
||||||
if (!pld_devices)
|
if (!pld_devices)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
||||||
struct command *parent = command_find_in_context(cmd_ctx, "pld");
|
return register_commands(cmd_ctx, "pld", pld_exec_command_handlers);
|
||||||
return register_commands(cmd_ctx, parent, pld_exec_command_handlers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_pld_init_command)
|
COMMAND_HANDLER(handle_pld_init_command)
|
||||||
|
|
|
@ -81,7 +81,7 @@ static int cortex_m_stacking(struct rtos *rtos, const struct rtos_register_stack
|
||||||
int cm4_fpu_enabled = 0;
|
int cm4_fpu_enabled = 0;
|
||||||
struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
|
struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
|
||||||
if (is_armv7m(armv7m_target)) {
|
if (is_armv7m(armv7m_target)) {
|
||||||
if (armv7m_target->fp_feature == FPv4_SP) {
|
if (armv7m_target->fp_feature == FPV4_SP) {
|
||||||
/* Found ARM v7m target which includes a FPU */
|
/* Found ARM v7m target which includes a FPU */
|
||||||
uint32_t cpacr;
|
uint32_t cpacr;
|
||||||
|
|
||||||
|
|
|
@ -350,7 +350,7 @@ static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
|
||||||
bool cm4_fpu_enabled = false;
|
bool cm4_fpu_enabled = false;
|
||||||
struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
|
struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
|
||||||
if (is_armv7m(armv7m_target)) {
|
if (is_armv7m(armv7m_target)) {
|
||||||
if (armv7m_target->fp_feature == FPv4_SP) {
|
if (armv7m_target->fp_feature == FPV4_SP) {
|
||||||
/* Found ARM v7m target which includes a FPU */
|
/* Found ARM v7m target which includes a FPU */
|
||||||
uint32_t cpacr;
|
uint32_t cpacr;
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "telnet_server.h"
|
#include "telnet_server.h"
|
||||||
#include <target/target_request.h>
|
#include <target/target_request.h>
|
||||||
#include <helper/configuration.h>
|
#include <helper/configuration.h>
|
||||||
|
#include <helper/list.h>
|
||||||
|
|
||||||
static char *telnet_port;
|
static char *telnet_port;
|
||||||
|
|
||||||
|
@ -58,6 +59,13 @@ static int telnet_write(struct connection *connection, const void *data,
|
||||||
return ERROR_SERVER_REMOTE_CLOSED;
|
return ERROR_SERVER_REMOTE_CLOSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* output an audible bell */
|
||||||
|
static int telnet_bell(struct connection *connection)
|
||||||
|
{
|
||||||
|
/* ("\a" does not work, at least on windows) */
|
||||||
|
return telnet_write(connection, "\x07", 1);
|
||||||
|
}
|
||||||
|
|
||||||
static int telnet_prompt(struct connection *connection)
|
static int telnet_prompt(struct connection *connection)
|
||||||
{
|
{
|
||||||
struct telnet_connection *t_con = connection->priv;
|
struct telnet_connection *t_con = connection->priv;
|
||||||
|
@ -366,6 +374,217 @@ static void telnet_move_cursor(struct connection *connection, size_t pos)
|
||||||
tc->line_cursor = pos;
|
tc->line_cursor = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check buffer size leaving one spare character for string null termination */
|
||||||
|
static inline bool telnet_can_insert(struct connection *connection, size_t len)
|
||||||
|
{
|
||||||
|
struct telnet_connection *t_con = connection->priv;
|
||||||
|
|
||||||
|
return t_con->line_size + len < TELNET_LINE_MAX_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write to telnet console, and update the telnet_connection members
|
||||||
|
* this function is capable of inserting in the middle of a line
|
||||||
|
* please ensure that data does not contain special characters (\n, \r, \t, \b ...)
|
||||||
|
*
|
||||||
|
* returns false when it fails to insert the requested data
|
||||||
|
*/
|
||||||
|
static bool telnet_insert(struct connection *connection, const void *data, size_t len)
|
||||||
|
{
|
||||||
|
struct telnet_connection *t_con = connection->priv;
|
||||||
|
|
||||||
|
if (!telnet_can_insert(connection, len)) {
|
||||||
|
telnet_bell(connection);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t_con->line_cursor < t_con->line_size) {
|
||||||
|
/* we have some content after the cursor */
|
||||||
|
memmove(t_con->line + t_con->line_cursor + len,
|
||||||
|
t_con->line + t_con->line_cursor,
|
||||||
|
t_con->line_size - t_con->line_cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(t_con->line + t_con->line_cursor, data, len);
|
||||||
|
|
||||||
|
telnet_write(connection,
|
||||||
|
t_con->line + t_con->line_cursor,
|
||||||
|
t_con->line_size + len - t_con->line_cursor);
|
||||||
|
|
||||||
|
t_con->line_size += len;
|
||||||
|
t_con->line_cursor += len;
|
||||||
|
|
||||||
|
for (size_t i = t_con->line_cursor; i < t_con->line_size; i++)
|
||||||
|
telnet_write(connection, "\b", 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void telnet_auto_complete(struct connection *connection)
|
||||||
|
{
|
||||||
|
struct telnet_connection *t_con = connection->priv;
|
||||||
|
struct command_context *command_context = connection->cmd_ctx;
|
||||||
|
|
||||||
|
struct cmd_match {
|
||||||
|
char *cmd;
|
||||||
|
struct list_head lh;
|
||||||
|
};
|
||||||
|
|
||||||
|
LIST_HEAD(matches);
|
||||||
|
|
||||||
|
/* user command sequence, either at line beginning
|
||||||
|
* or we start over after these characters ';', '[', '{' */
|
||||||
|
size_t seq_start = (t_con->line_cursor == 0) ? 0 : (t_con->line_cursor - 1);
|
||||||
|
while (seq_start > 0) {
|
||||||
|
char c = t_con->line[seq_start];
|
||||||
|
if (c == ';' || c == '[' || c == '{') {
|
||||||
|
seq_start++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
seq_start--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* user command position in the line, ignore leading spaces */
|
||||||
|
size_t usr_cmd_pos = seq_start;
|
||||||
|
while ((usr_cmd_pos < t_con->line_cursor) && isspace(t_con->line[usr_cmd_pos]))
|
||||||
|
usr_cmd_pos++;
|
||||||
|
|
||||||
|
/* user command length */
|
||||||
|
size_t usr_cmd_len = t_con->line_cursor - usr_cmd_pos;
|
||||||
|
|
||||||
|
/* optimize multiple spaces in the user command,
|
||||||
|
* because info commands does not tolerate multiple spaces */
|
||||||
|
size_t optimized_spaces = 0;
|
||||||
|
char query[usr_cmd_len + 1];
|
||||||
|
for (size_t i = 0; i < usr_cmd_len; i++) {
|
||||||
|
if ((i < usr_cmd_len - 1) && isspace(t_con->line[usr_cmd_pos + i])
|
||||||
|
&& isspace(t_con->line[usr_cmd_pos + i + 1])) {
|
||||||
|
optimized_spaces++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
query[i - optimized_spaces] = t_con->line[usr_cmd_pos + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
usr_cmd_len -= optimized_spaces;
|
||||||
|
query[usr_cmd_len] = '\0';
|
||||||
|
|
||||||
|
/* filter commands */
|
||||||
|
char *query_cmd = alloc_printf("lsort [info commands {%s*}]", query);
|
||||||
|
|
||||||
|
if (!query_cmd) {
|
||||||
|
LOG_ERROR("Out of memory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int retval = Jim_EvalSource(command_context->interp, __FILE__, __LINE__, query_cmd);
|
||||||
|
free(query_cmd);
|
||||||
|
if (retval != JIM_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Jim_Obj *list = Jim_GetResult(command_context->interp);
|
||||||
|
Jim_IncrRefCount(list);
|
||||||
|
|
||||||
|
/* common prefix length of the matched commands */
|
||||||
|
size_t common_len = 0;
|
||||||
|
char *first_match = NULL; /* used to compute the common prefix length */
|
||||||
|
|
||||||
|
int len = Jim_ListLength(command_context->interp, list);
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
Jim_Obj *elem = Jim_ListGetIndex(command_context->interp, list, i);
|
||||||
|
Jim_IncrRefCount(elem);
|
||||||
|
|
||||||
|
char *name = (char *)Jim_GetString(elem, NULL);
|
||||||
|
|
||||||
|
/* validate the command */
|
||||||
|
bool ignore_cmd = false;
|
||||||
|
Jim_Cmd *jim_cmd = Jim_GetCommand(command_context->interp, elem, JIM_NONE);
|
||||||
|
|
||||||
|
if (!jim_cmd)
|
||||||
|
ignore_cmd = true;
|
||||||
|
else {
|
||||||
|
if (!jim_cmd->isproc) {
|
||||||
|
/* ignore commands without handler
|
||||||
|
* and those with COMMAND_CONFIG mode */
|
||||||
|
/* FIXME it's better to use jimcmd_is_ocd_command(jim_cmd)
|
||||||
|
* or command_find_from_name(command_context->interp, name) */
|
||||||
|
struct command *cmd = jim_cmd->u.native.privData;
|
||||||
|
if (!cmd)
|
||||||
|
ignore_cmd = true;
|
||||||
|
/* make Valgrind happy by checking that cmd is not NULL */
|
||||||
|
else if (cmd != NULL && !cmd->handler && !cmd->jim_handler)
|
||||||
|
ignore_cmd = true;
|
||||||
|
else if (cmd != NULL && cmd->mode == COMMAND_CONFIG)
|
||||||
|
ignore_cmd = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save the command in the prediction list */
|
||||||
|
if (!ignore_cmd) {
|
||||||
|
struct cmd_match *match = calloc(1, sizeof(struct cmd_match));
|
||||||
|
if (!match) {
|
||||||
|
LOG_ERROR("Out of memory");
|
||||||
|
Jim_DecrRefCount(command_context->interp, elem);
|
||||||
|
break; /* break the for loop */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list_empty(&matches)) {
|
||||||
|
common_len = strlen(name);
|
||||||
|
first_match = name;
|
||||||
|
} else {
|
||||||
|
size_t new_common_len = usr_cmd_len; /* save some loops */
|
||||||
|
|
||||||
|
while (new_common_len < common_len && first_match[new_common_len] == name[new_common_len])
|
||||||
|
new_common_len++;
|
||||||
|
|
||||||
|
common_len = new_common_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
match->cmd = name;
|
||||||
|
list_add_tail(&match->lh, &matches);
|
||||||
|
}
|
||||||
|
|
||||||
|
Jim_DecrRefCount(command_context->interp, elem);
|
||||||
|
}
|
||||||
|
/* end of command filtering */
|
||||||
|
|
||||||
|
/* proceed with auto-completion */
|
||||||
|
if (list_empty(&matches))
|
||||||
|
telnet_bell(connection);
|
||||||
|
else if (common_len == usr_cmd_len && list_is_singular(&matches) && t_con->line_cursor == t_con->line_size)
|
||||||
|
telnet_insert(connection, " ", 1);
|
||||||
|
else if (common_len > usr_cmd_len) {
|
||||||
|
int completion_size = common_len - usr_cmd_len;
|
||||||
|
if (telnet_insert(connection, first_match + usr_cmd_len, completion_size)) {
|
||||||
|
/* in bash this extra space is only added when the cursor in at the end of line */
|
||||||
|
if (list_is_singular(&matches) && t_con->line_cursor == t_con->line_size)
|
||||||
|
telnet_insert(connection, " ", 1);
|
||||||
|
}
|
||||||
|
} else if (!list_is_singular(&matches)) {
|
||||||
|
telnet_write(connection, "\n\r", 2);
|
||||||
|
|
||||||
|
struct cmd_match *match;
|
||||||
|
list_for_each_entry(match, &matches, lh) {
|
||||||
|
telnet_write(connection, match->cmd, strlen(match->cmd));
|
||||||
|
telnet_write(connection, "\n\r", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
telnet_prompt(connection);
|
||||||
|
telnet_write(connection, t_con->line, t_con->line_size);
|
||||||
|
|
||||||
|
/* restore the terminal visible cursor location */
|
||||||
|
for (size_t i = t_con->line_cursor; i < t_con->line_size; i++)
|
||||||
|
telnet_write(connection, "\b", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* destroy the command_list */
|
||||||
|
struct cmd_match *tmp, *match;
|
||||||
|
list_for_each_entry_safe(match, tmp, &matches, lh)
|
||||||
|
free(match);
|
||||||
|
|
||||||
|
Jim_DecrRefCount(command_context->interp, list);
|
||||||
|
}
|
||||||
|
|
||||||
static int telnet_input(struct connection *connection)
|
static int telnet_input(struct connection *connection)
|
||||||
{
|
{
|
||||||
int bytes_read;
|
int bytes_read;
|
||||||
|
@ -391,30 +610,7 @@ static int telnet_input(struct connection *connection)
|
||||||
t_con->state = TELNET_STATE_IAC;
|
t_con->state = TELNET_STATE_IAC;
|
||||||
else {
|
else {
|
||||||
if (isprint(*buf_p)) { /* printable character */
|
if (isprint(*buf_p)) { /* printable character */
|
||||||
/* watch buffer size leaving one spare character for
|
telnet_insert(connection, buf_p, 1);
|
||||||
* string null termination */
|
|
||||||
if (t_con->line_size == TELNET_LINE_MAX_SIZE-1) {
|
|
||||||
/* output audible bell if buffer is full
|
|
||||||
* "\a" does not work, at least on windows */
|
|
||||||
telnet_write(connection, "\x07", 1);
|
|
||||||
} else if (t_con->line_cursor == t_con->line_size) {
|
|
||||||
telnet_write(connection, buf_p, 1);
|
|
||||||
t_con->line[t_con->line_size++] = *buf_p;
|
|
||||||
t_con->line_cursor++;
|
|
||||||
} else {
|
|
||||||
size_t i;
|
|
||||||
memmove(t_con->line + t_con->line_cursor + 1,
|
|
||||||
t_con->line + t_con->line_cursor,
|
|
||||||
t_con->line_size - t_con->line_cursor);
|
|
||||||
t_con->line[t_con->line_cursor] = *buf_p;
|
|
||||||
t_con->line_size++;
|
|
||||||
telnet_write(connection,
|
|
||||||
t_con->line + t_con->line_cursor,
|
|
||||||
t_con->line_size - t_con->line_cursor);
|
|
||||||
t_con->line_cursor++;
|
|
||||||
for (i = t_con->line_cursor; i < t_con->line_size; i++)
|
|
||||||
telnet_write(connection, "\b", 1);
|
|
||||||
}
|
|
||||||
} else { /* non-printable */
|
} else { /* non-printable */
|
||||||
if (*buf_p == 0x1b) { /* escape */
|
if (*buf_p == 0x1b) { /* escape */
|
||||||
t_con->state = TELNET_STATE_ESCAPE;
|
t_con->state = TELNET_STATE_ESCAPE;
|
||||||
|
@ -548,7 +744,9 @@ static int telnet_input(struct connection *connection)
|
||||||
t_con->line[t_con->line_cursor] = '\0';
|
t_con->line[t_con->line_cursor] = '\0';
|
||||||
t_con->line_size = t_con->line_cursor;
|
t_con->line_size = t_con->line_cursor;
|
||||||
}
|
}
|
||||||
} else
|
} else if (*buf_p == '\t')
|
||||||
|
telnet_auto_complete(connection);
|
||||||
|
else
|
||||||
LOG_DEBUG("unhandled nonprintable: %2.2x", *buf_p);
|
LOG_DEBUG("unhandled nonprintable: %2.2x", *buf_p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,6 +133,7 @@ static int aarch64_mmu_modify(struct target *target, int enable)
|
||||||
struct aarch64_common *aarch64 = target_to_aarch64(target);
|
struct aarch64_common *aarch64 = target_to_aarch64(target);
|
||||||
struct armv8_common *armv8 = &aarch64->armv8_common;
|
struct armv8_common *armv8 = &aarch64->armv8_common;
|
||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
|
enum arm_mode target_mode = ARM_MODE_ANY;
|
||||||
uint32_t instr = 0;
|
uint32_t instr = 0;
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
|
@ -158,6 +159,8 @@ static int aarch64_mmu_modify(struct target *target, int enable)
|
||||||
|
|
||||||
switch (armv8->arm.core_mode) {
|
switch (armv8->arm.core_mode) {
|
||||||
case ARMV8_64_EL0T:
|
case ARMV8_64_EL0T:
|
||||||
|
target_mode = ARMV8_64_EL1H;
|
||||||
|
/* fall through */
|
||||||
case ARMV8_64_EL1T:
|
case ARMV8_64_EL1T:
|
||||||
case ARMV8_64_EL1H:
|
case ARMV8_64_EL1H:
|
||||||
instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL1, 0);
|
instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL1, 0);
|
||||||
|
@ -184,9 +187,15 @@ static int aarch64_mmu_modify(struct target *target, int enable)
|
||||||
LOG_DEBUG("unknown cpu state 0x%x", armv8->arm.core_mode);
|
LOG_DEBUG("unknown cpu state 0x%x", armv8->arm.core_mode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (target_mode != ARM_MODE_ANY)
|
||||||
|
armv8_dpm_modeswitch(&armv8->dpm, target_mode);
|
||||||
|
|
||||||
retval = armv8->dpm.instr_write_data_r0(&armv8->dpm, instr,
|
retval = armv8->dpm.instr_write_data_r0(&armv8->dpm, instr,
|
||||||
aarch64->system_control_reg_curr);
|
aarch64->system_control_reg_curr);
|
||||||
|
|
||||||
|
if (target_mode != ARM_MODE_ANY)
|
||||||
|
armv8_dpm_modeswitch(&armv8->dpm, ARM_MODE_ANY);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2957,6 +2966,7 @@ COMMAND_HANDLER(aarch64_mask_interrupts_command)
|
||||||
|
|
||||||
static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
||||||
{
|
{
|
||||||
|
struct command *c = jim_to_command(interp);
|
||||||
struct command_context *context;
|
struct command_context *context;
|
||||||
struct target *target;
|
struct target *target;
|
||||||
struct arm *arm;
|
struct arm *arm;
|
||||||
|
@ -2964,7 +2974,7 @@ static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
||||||
bool is_mcr = false;
|
bool is_mcr = false;
|
||||||
int arg_cnt = 0;
|
int arg_cnt = 0;
|
||||||
|
|
||||||
if (Jim_CompareStringImmediate(interp, argv[0], "mcr")) {
|
if (!strcmp(c->name, "mcr")) {
|
||||||
is_mcr = true;
|
is_mcr = true;
|
||||||
arg_cnt = 7;
|
arg_cnt = 7;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -74,7 +74,7 @@ static void swd_clear_sticky_errors(struct adiv5_dap *dap)
|
||||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||||
assert(swd);
|
assert(swd);
|
||||||
|
|
||||||
swd->write_reg(swd_cmd(false, false, DP_ABORT),
|
swd->write_reg(swd_cmd(false, false, DP_ABORT),
|
||||||
STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0);
|
STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ static int swd_connect(struct adiv5_dap *dap)
|
||||||
|
|
||||||
dap->do_reconnect = false;
|
dap->do_reconnect = false;
|
||||||
|
|
||||||
swd->write_reg(swd_cmd(false, false, DP_ABORT),
|
swd->write_reg(swd_cmd(false, false, DP_ABORT),
|
||||||
DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0);
|
DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0);
|
||||||
status = swd_run_inner(dap);
|
status = swd_run_inner(dap);
|
||||||
}
|
}
|
||||||
|
@ -325,7 +325,7 @@ static int swd_queue_ap_read(struct adiv5_ap *ap, unsigned reg,
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
swd->read_reg(swd_cmd(true, true, reg), dap->last_read, ap->memaccess_tck);
|
swd->read_reg(swd_cmd(true, true, reg), dap->last_read, ap->memaccess_tck);
|
||||||
dap->last_read = data;
|
dap->last_read = data;
|
||||||
|
|
||||||
return check_sync(dap);
|
return check_sync(dap);
|
||||||
|
@ -347,7 +347,7 @@ static int swd_queue_ap_write(struct adiv5_ap *ap, unsigned reg,
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
swd->write_reg(swd_cmd(false, true, reg), data, ap->memaccess_tck);
|
swd->write_reg(swd_cmd(false, true, reg), data, ap->memaccess_tck);
|
||||||
|
|
||||||
return check_sync(dap);
|
return check_sync(dap);
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,15 @@
|
||||||
#define CSYSPWRUPREQ (1UL << 30)
|
#define CSYSPWRUPREQ (1UL << 30)
|
||||||
#define CSYSPWRUPACK (1UL << 31)
|
#define CSYSPWRUPACK (1UL << 31)
|
||||||
|
|
||||||
|
#define DP_SELECT_APSEL 0xFF000000
|
||||||
|
#define DP_SELECT_APBANK 0x000000F0
|
||||||
|
#define DP_SELECT_DPBANK 0x0000000F
|
||||||
|
#define DP_SELECT_INVALID 0x00FFFF00 /* Reserved bits one */
|
||||||
|
|
||||||
|
#define DP_APSEL_MAX (255)
|
||||||
|
#define DP_APSEL_INVALID (-1)
|
||||||
|
|
||||||
|
|
||||||
/* MEM-AP register addresses */
|
/* MEM-AP register addresses */
|
||||||
#define MEM_AP_REG_CSW 0x00
|
#define MEM_AP_REG_CSW 0x00
|
||||||
#define MEM_AP_REG_TAR 0x04
|
#define MEM_AP_REG_TAR 0x04
|
||||||
|
@ -150,18 +159,11 @@
|
||||||
|
|
||||||
#define IDR_JEP106_ARM 0x04760000
|
#define IDR_JEP106_ARM 0x04760000
|
||||||
|
|
||||||
#define DP_SELECT_APSEL 0xFF000000
|
|
||||||
#define DP_SELECT_APBANK 0x000000F0
|
|
||||||
#define DP_SELECT_DPBANK 0x0000000F
|
|
||||||
#define DP_SELECT_INVALID 0x00FFFF00 /* Reserved bits one */
|
|
||||||
|
|
||||||
#define DP_APSEL_MAX (255)
|
|
||||||
#define DP_APSEL_INVALID (-1)
|
|
||||||
|
|
||||||
/* FIXME: not SWD specific; should be renamed, e.g. adiv5_special_seq */
|
/* FIXME: not SWD specific; should be renamed, e.g. adiv5_special_seq */
|
||||||
enum swd_special_seq {
|
enum swd_special_seq {
|
||||||
LINE_RESET,
|
LINE_RESET,
|
||||||
JTAG_TO_SWD,
|
JTAG_TO_SWD,
|
||||||
|
JTAG_TO_DORMANT,
|
||||||
SWD_TO_JTAG,
|
SWD_TO_JTAG,
|
||||||
SWD_TO_DORMANT,
|
SWD_TO_DORMANT,
|
||||||
DORMANT_TO_SWD,
|
DORMANT_TO_SWD,
|
||||||
|
|
|
@ -507,17 +507,13 @@ static int cti_create(Jim_GetOptInfo *goi)
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
e = register_commands(cmd_ctx, NULL, cti_commands);
|
e = register_commands_with_data(cmd_ctx, NULL, cti_commands, cti);
|
||||||
if (ERROR_OK != e)
|
if (ERROR_OK != e)
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
|
|
||||||
struct command *c = command_find_in_context(cmd_ctx, cp);
|
|
||||||
assert(c);
|
|
||||||
command_set_handler_data(c, cti);
|
|
||||||
|
|
||||||
list_add_tail(&cti->lh, &all_cti);
|
list_add_tail(&cti->lh, &all_cti);
|
||||||
|
|
||||||
return (ERROR_OK == e) ? JIM_OK : JIM_ERR;
|
return JIM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int jim_cti_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
static int jim_cti_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||||
|
|
|
@ -265,17 +265,13 @@ static int dap_create(Jim_GetOptInfo *goi)
|
||||||
if (transport_is_hla())
|
if (transport_is_hla())
|
||||||
dap_commands[0].chain = NULL;
|
dap_commands[0].chain = NULL;
|
||||||
|
|
||||||
e = register_commands(cmd_ctx, NULL, dap_commands);
|
e = register_commands_with_data(cmd_ctx, NULL, dap_commands, dap);
|
||||||
if (ERROR_OK != e)
|
if (ERROR_OK != e)
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
|
|
||||||
struct command *c = command_find_in_context(cmd_ctx, cp);
|
|
||||||
assert(c);
|
|
||||||
command_set_handler_data(c, dap);
|
|
||||||
|
|
||||||
list_add_tail(&dap->lh, &all_dap);
|
list_add_tail(&dap->lh, &all_dap);
|
||||||
|
|
||||||
return (ERROR_OK == e) ? JIM_OK : JIM_ERR;
|
return JIM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int jim_dap_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
static int jim_dap_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||||
|
|
|
@ -550,16 +550,17 @@ err_no_params:
|
||||||
|
|
||||||
static int jim_arm_tpiu_swo_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
static int jim_arm_tpiu_swo_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
||||||
{
|
{
|
||||||
|
struct command *c = jim_to_command(interp);
|
||||||
Jim_GetOptInfo goi;
|
Jim_GetOptInfo goi;
|
||||||
|
|
||||||
Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
|
Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
|
||||||
goi.isconfigure = !strcmp(Jim_GetString(argv[0], NULL), "configure");
|
goi.isconfigure = !strcmp(c->name, "configure");
|
||||||
if (goi.argc < 1) {
|
if (goi.argc < 1) {
|
||||||
Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv,
|
Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv,
|
||||||
"missing: -option ...");
|
"missing: -option ...");
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
}
|
}
|
||||||
struct arm_tpiu_swo_object *obj = Jim_CmdPrivData(interp);
|
struct arm_tpiu_swo_object *obj = c->jim_handler_data;
|
||||||
return arm_tpiu_swo_configure(&goi, obj);
|
return arm_tpiu_swo_configure(&goi, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -583,7 +584,8 @@ static int wrap_read_u32(struct target *target, struct adiv5_ap *tpiu_ap,
|
||||||
|
|
||||||
static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||||
{
|
{
|
||||||
struct arm_tpiu_swo_object *obj = Jim_CmdPrivData(interp);
|
struct command *c = jim_to_command(interp);
|
||||||
|
struct arm_tpiu_swo_object *obj = c->jim_handler_data;
|
||||||
struct command_context *cmd_ctx = current_command_context(interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
struct adiv5_ap *tpiu_ap = dap_ap(obj->spot.dap, obj->spot.ap_num);
|
struct adiv5_ap *tpiu_ap = dap_ap(obj->spot.dap, obj->spot.ap_num);
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
|
@ -786,7 +788,8 @@ error_exit:
|
||||||
|
|
||||||
static int jim_arm_tpiu_swo_disable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
static int jim_arm_tpiu_swo_disable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||||
{
|
{
|
||||||
struct arm_tpiu_swo_object *obj = Jim_CmdPrivData(interp);
|
struct command *c = jim_to_command(interp);
|
||||||
|
struct arm_tpiu_swo_object *obj = c->jim_handler_data;
|
||||||
|
|
||||||
if (argc != 1) {
|
if (argc != 1) {
|
||||||
Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
|
Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
|
||||||
|
@ -883,14 +886,10 @@ static int arm_tpiu_swo_create(Jim_Interp *interp, struct arm_tpiu_swo_object *o
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
e = register_commands(cmd_ctx, NULL, obj_commands);
|
e = register_commands_with_data(cmd_ctx, NULL, obj_commands, obj);
|
||||||
if (ERROR_OK != e)
|
if (ERROR_OK != e)
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
|
|
||||||
struct command *c = command_find_in_context(cmd_ctx, obj->name);
|
|
||||||
assert(c);
|
|
||||||
command_set_handler_data(c, obj);
|
|
||||||
|
|
||||||
list_add_tail(&obj->lh, &all_tpiu_swo);
|
list_add_tail(&obj->lh, &all_tpiu_swo);
|
||||||
|
|
||||||
return JIM_OK;
|
return JIM_OK;
|
||||||
|
|
|
@ -164,18 +164,22 @@ enum {
|
||||||
/* Floating-point status register */
|
/* Floating-point status register */
|
||||||
ARMV7M_FPSCR,
|
ARMV7M_FPSCR,
|
||||||
|
|
||||||
|
/* for convenience add registers' block delimiters */
|
||||||
ARMV7M_LAST_REG,
|
ARMV7M_LAST_REG,
|
||||||
|
ARMV7M_CORE_FIRST_REG = ARMV7M_R0,
|
||||||
|
ARMV7M_CORE_LAST_REG = ARMV7M_xPSR,
|
||||||
|
ARMV7M_FPU_FIRST_REG = ARMV7M_D0,
|
||||||
|
ARMV7M_FPU_LAST_REG = ARMV7M_FPSCR,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
FP_NONE = 0,
|
FP_NONE = 0,
|
||||||
FPv4_SP,
|
FPV4_SP,
|
||||||
FPv5_SP,
|
FPV5_SP,
|
||||||
FPv5_DP,
|
FPV5_DP,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ARMV7M_NUM_CORE_REGS (ARMV7M_xPSR + 1)
|
#define ARMV7M_NUM_CORE_REGS (ARMV7M_CORE_LAST_REG - ARMV7M_CORE_FIRST_REG + 1)
|
||||||
#define ARMV7M_NUM_CORE_REGS_NOFP (ARMV7M_CONTROL + 1)
|
|
||||||
|
|
||||||
#define ARMV7M_COMMON_MAGIC 0x2A452A45
|
#define ARMV7M_COMMON_MAGIC 0x2A452A45
|
||||||
|
|
||||||
|
|
|
@ -1596,6 +1596,35 @@ int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpo
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cortex_m_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint)
|
||||||
|
{
|
||||||
|
if (target->debug_reason != DBG_REASON_WATCHPOINT)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||||
|
|
||||||
|
for (struct watchpoint *wp = target->watchpoints; wp; wp = wp->next) {
|
||||||
|
if (!wp->set)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
unsigned int dwt_num = wp->set - 1;
|
||||||
|
struct cortex_m_dwt_comparator *comparator = cortex_m->dwt_comparator_list + dwt_num;
|
||||||
|
|
||||||
|
uint32_t dwt_function;
|
||||||
|
int retval = target_read_u32(target, comparator->dwt_comparator_address + 8, &dwt_function);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
/* check the MATCHED bit */
|
||||||
|
if (dwt_function & BIT(24)) {
|
||||||
|
*hit_watchpoint = wp;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
void cortex_m_enable_watchpoints(struct target *target)
|
void cortex_m_enable_watchpoints(struct target *target)
|
||||||
{
|
{
|
||||||
struct watchpoint *watchpoint = target->watchpoints;
|
struct watchpoint *watchpoint = target->watchpoints;
|
||||||
|
@ -2019,7 +2048,7 @@ int cortex_m_examine(struct target *target)
|
||||||
/* test for floating point feature on Cortex-M4 */
|
/* test for floating point feature on Cortex-M4 */
|
||||||
if ((mvfr0 == MVFR0_DEFAULT_M4) && (mvfr1 == MVFR1_DEFAULT_M4)) {
|
if ((mvfr0 == MVFR0_DEFAULT_M4) && (mvfr1 == MVFR1_DEFAULT_M4)) {
|
||||||
LOG_DEBUG("Cortex-M%d floating point feature FPv4_SP found", i);
|
LOG_DEBUG("Cortex-M%d floating point feature FPv4_SP found", i);
|
||||||
armv7m->fp_feature = FPv4_SP;
|
armv7m->fp_feature = FPV4_SP;
|
||||||
}
|
}
|
||||||
} else if (i == 7 || i == 33 || i == 35 || i == 55) {
|
} else if (i == 7 || i == 33 || i == 35 || i == 55) {
|
||||||
target_read_u32(target, MVFR0, &mvfr0);
|
target_read_u32(target, MVFR0, &mvfr0);
|
||||||
|
@ -2028,29 +2057,21 @@ int cortex_m_examine(struct target *target)
|
||||||
/* test for floating point features on Cortex-M7 */
|
/* test for floating point features on Cortex-M7 */
|
||||||
if ((mvfr0 == MVFR0_DEFAULT_M7_SP) && (mvfr1 == MVFR1_DEFAULT_M7_SP)) {
|
if ((mvfr0 == MVFR0_DEFAULT_M7_SP) && (mvfr1 == MVFR1_DEFAULT_M7_SP)) {
|
||||||
LOG_DEBUG("Cortex-M%d floating point feature FPv5_SP found", i);
|
LOG_DEBUG("Cortex-M%d floating point feature FPv5_SP found", i);
|
||||||
armv7m->fp_feature = FPv5_SP;
|
armv7m->fp_feature = FPV5_SP;
|
||||||
} else if ((mvfr0 == MVFR0_DEFAULT_M7_DP) && (mvfr1 == MVFR1_DEFAULT_M7_DP)) {
|
} else if ((mvfr0 == MVFR0_DEFAULT_M7_DP) && (mvfr1 == MVFR1_DEFAULT_M7_DP)) {
|
||||||
LOG_DEBUG("Cortex-M%d floating point feature FPv5_DP found", i);
|
LOG_DEBUG("Cortex-M%d floating point feature FPv5_DP found", i);
|
||||||
armv7m->fp_feature = FPv5_DP;
|
armv7m->fp_feature = FPV5_DP;
|
||||||
}
|
}
|
||||||
} else if (i == 0) {
|
} else if (i == 0) {
|
||||||
/* Cortex-M0 does not support unaligned memory access */
|
/* Cortex-M0 does not support unaligned memory access */
|
||||||
armv7m->arm.is_armv6m = true;
|
armv7m->arm.is_armv6m = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (armv7m->fp_feature == FP_NONE &&
|
/* Check for FPU, otherwise mark FPU register as non-existent */
|
||||||
armv7m->arm.core_cache->num_regs > ARMV7M_NUM_CORE_REGS_NOFP) {
|
if (armv7m->fp_feature == FP_NONE)
|
||||||
/* free unavailable FPU registers */
|
for (size_t idx = ARMV7M_FPU_FIRST_REG; idx <= ARMV7M_FPU_LAST_REG; idx++)
|
||||||
size_t idx;
|
armv7m->arm.core_cache->reg_list[idx].exist = false;
|
||||||
|
|
||||||
for (idx = ARMV7M_NUM_CORE_REGS_NOFP;
|
|
||||||
idx < armv7m->arm.core_cache->num_regs;
|
|
||||||
idx++) {
|
|
||||||
free(armv7m->arm.core_cache->reg_list[idx].feature);
|
|
||||||
free(armv7m->arm.core_cache->reg_list[idx].reg_data_type);
|
|
||||||
}
|
|
||||||
armv7m->arm.core_cache->num_regs = ARMV7M_NUM_CORE_REGS_NOFP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!armv7m->stlink) {
|
if (!armv7m->stlink) {
|
||||||
if (i == 3 || i == 4)
|
if (i == 3 || i == 4)
|
||||||
|
@ -2531,6 +2552,7 @@ struct target_type cortexm_target = {
|
||||||
.remove_breakpoint = cortex_m_remove_breakpoint,
|
.remove_breakpoint = cortex_m_remove_breakpoint,
|
||||||
.add_watchpoint = cortex_m_add_watchpoint,
|
.add_watchpoint = cortex_m_add_watchpoint,
|
||||||
.remove_watchpoint = cortex_m_remove_watchpoint,
|
.remove_watchpoint = cortex_m_remove_watchpoint,
|
||||||
|
.hit_watchpoint = cortex_m_hit_watchpoint,
|
||||||
|
|
||||||
.commands = cortex_m_command_handlers,
|
.commands = cortex_m_command_handlers,
|
||||||
.target_create = cortex_m_target_create,
|
.target_create = cortex_m_target_create,
|
||||||
|
|
|
@ -2107,6 +2107,5 @@ static const struct command_registration etm_exec_command_handlers[] = {
|
||||||
|
|
||||||
static int etm_register_user_commands(struct command_context *cmd_ctx)
|
static int etm_register_user_commands(struct command_context *cmd_ctx)
|
||||||
{
|
{
|
||||||
struct command *etm_cmd = command_find_in_context(cmd_ctx, "etm");
|
return register_commands(cmd_ctx, "etm", etm_exec_command_handlers);
|
||||||
return register_commands(cmd_ctx, etm_cmd, etm_exec_command_handlers);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
* Copyright (C) 2009 by Franck Hereson *
|
* Copyright (C) 2009 by Franck Hereson *
|
||||||
* franck.hereson@secad.fr *
|
* franck.hereson@secad.fr *
|
||||||
* *
|
* *
|
||||||
|
* Copyright (C) 2018 by Advantest *
|
||||||
|
* florian.meister@advantest.com *
|
||||||
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU General Public License as published by *
|
* it under the terms of the GNU General Public License as published by *
|
||||||
* the Free Software Foundation; either version 2 of the License, or *
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
@ -42,6 +45,10 @@
|
||||||
((elf->endianness == ELFDATA2LSB) ? \
|
((elf->endianness == ELFDATA2LSB) ? \
|
||||||
le_to_h_u32((uint8_t *)&field) : be_to_h_u32((uint8_t *)&field))
|
le_to_h_u32((uint8_t *)&field) : be_to_h_u32((uint8_t *)&field))
|
||||||
|
|
||||||
|
#define field64(elf, field) \
|
||||||
|
((elf->endianness == ELFDATA2LSB) ? \
|
||||||
|
le_to_h_u64((uint8_t *)&field) : be_to_h_u64((uint8_t *)&field))
|
||||||
|
|
||||||
static int autodetect_image_type(struct image *image, const char *url)
|
static int autodetect_image_type(struct image *image, const char *url)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
@ -49,7 +56,7 @@ static int autodetect_image_type(struct image *image, const char *url)
|
||||||
size_t read_bytes;
|
size_t read_bytes;
|
||||||
uint8_t buffer[9];
|
uint8_t buffer[9];
|
||||||
|
|
||||||
/* read the first 4 bytes of image */
|
/* read the first 9 bytes of image */
|
||||||
retval = fileio_open(&fileio, url, FILEIO_READ, FILEIO_BINARY);
|
retval = fileio_open(&fileio, url, FILEIO_READ, FILEIO_BINARY);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -350,22 +357,29 @@ static int image_ihex_buffer_complete(struct image *image)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int image_elf_read_headers(struct image *image)
|
static int image_elf32_read_headers(struct image *image)
|
||||||
{
|
{
|
||||||
struct image_elf *elf = image->type_private;
|
struct image_elf *elf = image->type_private;
|
||||||
size_t read_bytes;
|
size_t read_bytes;
|
||||||
uint32_t i, j;
|
uint32_t i, j;
|
||||||
int retval;
|
int retval;
|
||||||
uint32_t nload, load_to_vaddr = 0;
|
uint32_t nload;
|
||||||
|
bool load_to_vaddr = false;
|
||||||
|
|
||||||
elf->header = malloc(sizeof(Elf32_Ehdr));
|
retval = fileio_seek(elf->fileio, 0);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("cannot seek to ELF file header, read failed");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
if (elf->header == NULL) {
|
elf->header32 = malloc(sizeof(Elf32_Ehdr));
|
||||||
LOG_ERROR("insufficient memory to perform operation ");
|
|
||||||
|
if (elf->header32 == NULL) {
|
||||||
|
LOG_ERROR("insufficient memory to perform operation");
|
||||||
return ERROR_FILEIO_OPERATION_FAILED;
|
return ERROR_FILEIO_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = fileio_read(elf->fileio, sizeof(Elf32_Ehdr), (uint8_t *)elf->header, &read_bytes);
|
retval = fileio_read(elf->fileio, sizeof(Elf32_Ehdr), (uint8_t *)elf->header32, &read_bytes);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
LOG_ERROR("cannot read ELF file header, read failed");
|
LOG_ERROR("cannot read ELF file header, read failed");
|
||||||
return ERROR_FILEIO_OPERATION_FAILED;
|
return ERROR_FILEIO_OPERATION_FAILED;
|
||||||
|
@ -375,42 +389,26 @@ static int image_elf_read_headers(struct image *image)
|
||||||
return ERROR_FILEIO_OPERATION_FAILED;
|
return ERROR_FILEIO_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp((char *)elf->header->e_ident, ELFMAG, SELFMAG) != 0) {
|
elf->segment_count = field16(elf, elf->header32->e_phnum);
|
||||||
LOG_ERROR("invalid ELF file, bad magic number");
|
|
||||||
return ERROR_IMAGE_FORMAT_ERROR;
|
|
||||||
}
|
|
||||||
if (elf->header->e_ident[EI_CLASS] != ELFCLASS32) {
|
|
||||||
LOG_ERROR("invalid ELF file, only 32bits files are supported");
|
|
||||||
return ERROR_IMAGE_FORMAT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
elf->endianness = elf->header->e_ident[EI_DATA];
|
|
||||||
if ((elf->endianness != ELFDATA2LSB)
|
|
||||||
&& (elf->endianness != ELFDATA2MSB)) {
|
|
||||||
LOG_ERROR("invalid ELF file, unknown endianness setting");
|
|
||||||
return ERROR_IMAGE_FORMAT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
elf->segment_count = field16(elf, elf->header->e_phnum);
|
|
||||||
if (elf->segment_count == 0) {
|
if (elf->segment_count == 0) {
|
||||||
LOG_ERROR("invalid ELF file, no program headers");
|
LOG_ERROR("invalid ELF file, no program headers");
|
||||||
return ERROR_IMAGE_FORMAT_ERROR;
|
return ERROR_IMAGE_FORMAT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = fileio_seek(elf->fileio, field32(elf, elf->header->e_phoff));
|
retval = fileio_seek(elf->fileio, field32(elf, elf->header32->e_phoff));
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
LOG_ERROR("cannot seek to ELF program header table, read failed");
|
LOG_ERROR("cannot seek to ELF program header table, read failed");
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
elf->segments = malloc(elf->segment_count*sizeof(Elf32_Phdr));
|
elf->segments32 = malloc(elf->segment_count*sizeof(Elf32_Phdr));
|
||||||
if (elf->segments == NULL) {
|
if (elf->segments32 == NULL) {
|
||||||
LOG_ERROR("insufficient memory to perform operation ");
|
LOG_ERROR("insufficient memory to perform operation");
|
||||||
return ERROR_FILEIO_OPERATION_FAILED;
|
return ERROR_FILEIO_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = fileio_read(elf->fileio, elf->segment_count*sizeof(Elf32_Phdr),
|
retval = fileio_read(elf->fileio, elf->segment_count*sizeof(Elf32_Phdr),
|
||||||
(uint8_t *)elf->segments, &read_bytes);
|
(uint8_t *)elf->segments32, &read_bytes);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
LOG_ERROR("cannot read ELF segment headers, read failed");
|
LOG_ERROR("cannot read ELF segment headers, read failed");
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -424,11 +422,14 @@ static int image_elf_read_headers(struct image *image)
|
||||||
image->num_sections = 0;
|
image->num_sections = 0;
|
||||||
for (i = 0; i < elf->segment_count; i++)
|
for (i = 0; i < elf->segment_count; i++)
|
||||||
if ((field32(elf,
|
if ((field32(elf,
|
||||||
elf->segments[i].p_type) == PT_LOAD) &&
|
elf->segments32[i].p_type) == PT_LOAD) &&
|
||||||
(field32(elf, elf->segments[i].p_filesz) != 0))
|
(field32(elf, elf->segments32[i].p_filesz) != 0))
|
||||||
image->num_sections++;
|
image->num_sections++;
|
||||||
|
|
||||||
assert(image->num_sections > 0);
|
if (image->num_sections == 0) {
|
||||||
|
LOG_ERROR("invalid ELF file, no loadable segments");
|
||||||
|
return ERROR_IMAGE_FORMAT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* some ELF linkers produce binaries with *all* the program header
|
* some ELF linkers produce binaries with *all* the program header
|
||||||
|
@ -441,44 +442,220 @@ static int image_elf_read_headers(struct image *image)
|
||||||
* when obtaining lma - look at elf.c of BDF)
|
* when obtaining lma - look at elf.c of BDF)
|
||||||
*/
|
*/
|
||||||
for (nload = 0, i = 0; i < elf->segment_count; i++)
|
for (nload = 0, i = 0; i < elf->segment_count; i++)
|
||||||
if (elf->segments[i].p_paddr != 0)
|
if (elf->segments32[i].p_paddr != 0)
|
||||||
break;
|
break;
|
||||||
else if ((field32(elf,
|
else if ((field32(elf,
|
||||||
elf->segments[i].p_type) == PT_LOAD) &&
|
elf->segments32[i].p_type) == PT_LOAD) &&
|
||||||
(field32(elf, elf->segments[i].p_memsz) != 0))
|
(field32(elf, elf->segments32[i].p_memsz) != 0))
|
||||||
++nload;
|
++nload;
|
||||||
|
|
||||||
if (i >= elf->segment_count && nload > 1)
|
if (i >= elf->segment_count && nload > 1)
|
||||||
load_to_vaddr = 1;
|
load_to_vaddr = true;
|
||||||
|
|
||||||
/* alloc and fill sections array with loadable segments */
|
/* alloc and fill sections array with loadable segments */
|
||||||
image->sections = malloc(image->num_sections * sizeof(struct imagesection));
|
image->sections = malloc(image->num_sections * sizeof(struct imagesection));
|
||||||
|
if (image->sections == NULL) {
|
||||||
|
LOG_ERROR("insufficient memory to perform operation");
|
||||||
|
return ERROR_FILEIO_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0, j = 0; i < elf->segment_count; i++) {
|
for (i = 0, j = 0; i < elf->segment_count; i++) {
|
||||||
if ((field32(elf,
|
if ((field32(elf,
|
||||||
elf->segments[i].p_type) == PT_LOAD) &&
|
elf->segments32[i].p_type) == PT_LOAD) &&
|
||||||
(field32(elf, elf->segments[i].p_filesz) != 0)) {
|
(field32(elf, elf->segments32[i].p_filesz) != 0)) {
|
||||||
image->sections[j].size = field32(elf, elf->segments[i].p_filesz);
|
image->sections[j].size = field32(elf, elf->segments32[i].p_filesz);
|
||||||
if (load_to_vaddr)
|
if (load_to_vaddr)
|
||||||
image->sections[j].base_address = field32(elf,
|
image->sections[j].base_address = field32(elf,
|
||||||
elf->segments[i].p_vaddr);
|
elf->segments32[i].p_vaddr);
|
||||||
else
|
else
|
||||||
image->sections[j].base_address = field32(elf,
|
image->sections[j].base_address = field32(elf,
|
||||||
elf->segments[i].p_paddr);
|
elf->segments32[i].p_paddr);
|
||||||
image->sections[j].private = &elf->segments[i];
|
image->sections[j].private = &elf->segments32[i];
|
||||||
image->sections[j].flags = field32(elf, elf->segments[i].p_flags);
|
image->sections[j].flags = field32(elf, elf->segments32[i].p_flags);
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
image->start_address_set = true;
|
image->start_address_set = true;
|
||||||
image->start_address = field32(elf, elf->header->e_entry);
|
image->start_address = field32(elf, elf->header32->e_entry);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int image_elf_read_section(struct image *image,
|
static int image_elf64_read_headers(struct image *image)
|
||||||
|
{
|
||||||
|
struct image_elf *elf = image->type_private;
|
||||||
|
size_t read_bytes;
|
||||||
|
uint32_t i, j;
|
||||||
|
int retval;
|
||||||
|
uint32_t nload;
|
||||||
|
bool load_to_vaddr = false;
|
||||||
|
|
||||||
|
retval = fileio_seek(elf->fileio, 0);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("cannot seek to ELF file header, read failed");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
elf->header64 = malloc(sizeof(Elf64_Ehdr));
|
||||||
|
|
||||||
|
if (elf->header64 == NULL) {
|
||||||
|
LOG_ERROR("insufficient memory to perform operation");
|
||||||
|
return ERROR_FILEIO_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = fileio_read(elf->fileio, sizeof(Elf64_Ehdr), (uint8_t *)elf->header64, &read_bytes);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("cannot read ELF file header, read failed");
|
||||||
|
return ERROR_FILEIO_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
if (read_bytes != sizeof(Elf64_Ehdr)) {
|
||||||
|
LOG_ERROR("cannot read ELF file header, only partially read");
|
||||||
|
return ERROR_FILEIO_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
elf->segment_count = field16(elf, elf->header64->e_phnum);
|
||||||
|
if (elf->segment_count == 0) {
|
||||||
|
LOG_ERROR("invalid ELF file, no program headers");
|
||||||
|
return ERROR_IMAGE_FORMAT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = fileio_seek(elf->fileio, field64(elf, elf->header64->e_phoff));
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("cannot seek to ELF program header table, read failed");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
elf->segments64 = malloc(elf->segment_count*sizeof(Elf64_Phdr));
|
||||||
|
if (elf->segments64 == NULL) {
|
||||||
|
LOG_ERROR("insufficient memory to perform operation");
|
||||||
|
return ERROR_FILEIO_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = fileio_read(elf->fileio, elf->segment_count*sizeof(Elf64_Phdr),
|
||||||
|
(uint8_t *)elf->segments64, &read_bytes);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("cannot read ELF segment headers, read failed");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
if (read_bytes != elf->segment_count*sizeof(Elf64_Phdr)) {
|
||||||
|
LOG_ERROR("cannot read ELF segment headers, only partially read");
|
||||||
|
return ERROR_FILEIO_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* count useful segments (loadable), ignore BSS section */
|
||||||
|
image->num_sections = 0;
|
||||||
|
for (i = 0; i < elf->segment_count; i++)
|
||||||
|
if ((field32(elf,
|
||||||
|
elf->segments64[i].p_type) == PT_LOAD) &&
|
||||||
|
(field64(elf, elf->segments64[i].p_filesz) != 0))
|
||||||
|
image->num_sections++;
|
||||||
|
|
||||||
|
if (image->num_sections == 0) {
|
||||||
|
LOG_ERROR("invalid ELF file, no loadable segments");
|
||||||
|
return ERROR_IMAGE_FORMAT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* some ELF linkers produce binaries with *all* the program header
|
||||||
|
* p_paddr fields zero (there can be however one loadable segment
|
||||||
|
* that has valid physical address 0x0).
|
||||||
|
* If we have such a binary with more than
|
||||||
|
* one PT_LOAD header, then use p_vaddr instead of p_paddr
|
||||||
|
* (ARM ELF standard demands p_paddr = 0 anyway, and BFD
|
||||||
|
* library uses this approach to workaround zero-initialized p_paddrs
|
||||||
|
* when obtaining lma - look at elf.c of BDF)
|
||||||
|
*/
|
||||||
|
for (nload = 0, i = 0; i < elf->segment_count; i++)
|
||||||
|
if (elf->segments64[i].p_paddr != 0)
|
||||||
|
break;
|
||||||
|
else if ((field32(elf,
|
||||||
|
elf->segments64[i].p_type) == PT_LOAD) &&
|
||||||
|
(field64(elf, elf->segments64[i].p_memsz) != 0))
|
||||||
|
++nload;
|
||||||
|
|
||||||
|
if (i >= elf->segment_count && nload > 1)
|
||||||
|
load_to_vaddr = true;
|
||||||
|
|
||||||
|
/* alloc and fill sections array with loadable segments */
|
||||||
|
image->sections = malloc(image->num_sections * sizeof(struct imagesection));
|
||||||
|
if (image->sections == NULL) {
|
||||||
|
LOG_ERROR("insufficient memory to perform operation");
|
||||||
|
return ERROR_FILEIO_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, j = 0; i < elf->segment_count; i++) {
|
||||||
|
if ((field32(elf,
|
||||||
|
elf->segments64[i].p_type) == PT_LOAD) &&
|
||||||
|
(field64(elf, elf->segments64[i].p_filesz) != 0)) {
|
||||||
|
image->sections[j].size = field64(elf, elf->segments64[i].p_filesz);
|
||||||
|
if (load_to_vaddr)
|
||||||
|
image->sections[j].base_address = field64(elf,
|
||||||
|
elf->segments64[i].p_vaddr);
|
||||||
|
else
|
||||||
|
image->sections[j].base_address = field64(elf,
|
||||||
|
elf->segments64[i].p_paddr);
|
||||||
|
image->sections[j].private = &elf->segments64[i];
|
||||||
|
image->sections[j].flags = field32(elf, elf->segments64[i].p_flags);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
image->start_address_set = true;
|
||||||
|
image->start_address = field64(elf, elf->header64->e_entry);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int image_elf_read_headers(struct image *image)
|
||||||
|
{
|
||||||
|
struct image_elf *elf = image->type_private;
|
||||||
|
size_t read_bytes;
|
||||||
|
unsigned char e_ident[EI_NIDENT];
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
retval = fileio_read(elf->fileio, EI_NIDENT, e_ident, &read_bytes);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("cannot read ELF file header, read failed");
|
||||||
|
return ERROR_FILEIO_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
if (read_bytes != EI_NIDENT) {
|
||||||
|
LOG_ERROR("cannot read ELF file header, only partially read");
|
||||||
|
return ERROR_FILEIO_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp((char *)e_ident, ELFMAG, SELFMAG) != 0) {
|
||||||
|
LOG_ERROR("invalid ELF file, bad magic number");
|
||||||
|
return ERROR_IMAGE_FORMAT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
elf->endianness = e_ident[EI_DATA];
|
||||||
|
if ((elf->endianness != ELFDATA2LSB)
|
||||||
|
&& (elf->endianness != ELFDATA2MSB)) {
|
||||||
|
LOG_ERROR("invalid ELF file, unknown endianness setting");
|
||||||
|
return ERROR_IMAGE_FORMAT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (e_ident[EI_CLASS]) {
|
||||||
|
case ELFCLASS32:
|
||||||
|
LOG_DEBUG("ELF32 image detected.");
|
||||||
|
elf->is_64_bit = false;
|
||||||
|
return image_elf32_read_headers(image);
|
||||||
|
|
||||||
|
case ELFCLASS64:
|
||||||
|
LOG_DEBUG("ELF64 image detected.");
|
||||||
|
elf->is_64_bit = true;
|
||||||
|
return image_elf64_read_headers(image);
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG_ERROR("invalid ELF file, only 32/64 bit ELF files are supported");
|
||||||
|
return ERROR_IMAGE_FORMAT_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int image_elf32_read_section(struct image *image,
|
||||||
int section,
|
int section,
|
||||||
uint32_t offset,
|
target_addr_t offset,
|
||||||
uint32_t size,
|
uint32_t size,
|
||||||
uint8_t *buffer,
|
uint8_t *buffer,
|
||||||
size_t *size_read)
|
size_t *size_read)
|
||||||
|
@ -490,13 +667,13 @@ static int image_elf_read_section(struct image *image,
|
||||||
|
|
||||||
*size_read = 0;
|
*size_read = 0;
|
||||||
|
|
||||||
LOG_DEBUG("load segment %d at 0x%" PRIx32 " (sz = 0x%" PRIx32 ")", section, offset, size);
|
LOG_DEBUG("load segment %d at 0x%" TARGET_PRIxADDR " (sz = 0x%" PRIx32 ")", section, offset, size);
|
||||||
|
|
||||||
/* read initialized data in current segment if any */
|
/* read initialized data in current segment if any */
|
||||||
if (offset < field32(elf, segment->p_filesz)) {
|
if (offset < field32(elf, segment->p_filesz)) {
|
||||||
/* maximal size present in file for the current segment */
|
/* maximal size present in file for the current segment */
|
||||||
read_size = MIN(size, field32(elf, segment->p_filesz) - offset);
|
read_size = MIN(size, field32(elf, segment->p_filesz) - offset);
|
||||||
LOG_DEBUG("read elf: size = 0x%zx at 0x%" PRIx32 "", read_size,
|
LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", read_size,
|
||||||
field32(elf, segment->p_offset) + offset);
|
field32(elf, segment->p_offset) + offset);
|
||||||
/* read initialized area of the segment */
|
/* read initialized area of the segment */
|
||||||
retval = fileio_seek(elf->fileio, field32(elf, segment->p_offset) + offset);
|
retval = fileio_seek(elf->fileio, field32(elf, segment->p_offset) + offset);
|
||||||
|
@ -519,6 +696,64 @@ static int image_elf_read_section(struct image *image,
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int image_elf64_read_section(struct image *image,
|
||||||
|
int section,
|
||||||
|
target_addr_t offset,
|
||||||
|
uint32_t size,
|
||||||
|
uint8_t *buffer,
|
||||||
|
size_t *size_read)
|
||||||
|
{
|
||||||
|
struct image_elf *elf = image->type_private;
|
||||||
|
Elf64_Phdr *segment = (Elf64_Phdr *)image->sections[section].private;
|
||||||
|
size_t read_size, really_read;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
*size_read = 0;
|
||||||
|
|
||||||
|
LOG_DEBUG("load segment %d at 0x%" TARGET_PRIxADDR " (sz = 0x%" PRIx32 ")", section, offset, size);
|
||||||
|
|
||||||
|
/* read initialized data in current segment if any */
|
||||||
|
if (offset < field64(elf, segment->p_filesz)) {
|
||||||
|
/* maximal size present in file for the current segment */
|
||||||
|
read_size = MIN(size, field64(elf, segment->p_filesz) - offset);
|
||||||
|
LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", read_size,
|
||||||
|
field64(elf, segment->p_offset) + offset);
|
||||||
|
/* read initialized area of the segment */
|
||||||
|
retval = fileio_seek(elf->fileio, field64(elf, segment->p_offset) + offset);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("cannot find ELF segment content, seek failed");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
retval = fileio_read(elf->fileio, read_size, buffer, &really_read);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("cannot read ELF segment content, read failed");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
size -= read_size;
|
||||||
|
*size_read += read_size;
|
||||||
|
/* need more data ? */
|
||||||
|
if (!size)
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int image_elf_read_section(struct image *image,
|
||||||
|
int section,
|
||||||
|
target_addr_t offset,
|
||||||
|
uint32_t size,
|
||||||
|
uint8_t *buffer,
|
||||||
|
size_t *size_read)
|
||||||
|
{
|
||||||
|
struct image_elf *elf = image->type_private;
|
||||||
|
|
||||||
|
if (elf->is_64_bit)
|
||||||
|
return image_elf64_read_section(image, section, offset, size, buffer, size_read);
|
||||||
|
else
|
||||||
|
return image_elf32_read_section(image, section, offset, size, buffer, size_read);
|
||||||
|
}
|
||||||
|
|
||||||
static int image_mot_buffer_complete_inner(struct image *image,
|
static int image_mot_buffer_complete_inner(struct image *image,
|
||||||
char *lpszLine,
|
char *lpszLine,
|
||||||
struct imagesection *section)
|
struct imagesection *section)
|
||||||
|
@ -840,7 +1075,7 @@ int image_open(struct image *image, const char *url, const char *type_string)
|
||||||
|
|
||||||
int image_read_section(struct image *image,
|
int image_read_section(struct image *image,
|
||||||
int section,
|
int section,
|
||||||
uint32_t offset,
|
target_addr_t offset,
|
||||||
uint32_t size,
|
uint32_t size,
|
||||||
uint8_t *buffer,
|
uint8_t *buffer,
|
||||||
size_t *size_read)
|
size_t *size_read)
|
||||||
|
@ -850,7 +1085,7 @@ int image_read_section(struct image *image,
|
||||||
/* don't read past the end of a section */
|
/* don't read past the end of a section */
|
||||||
if (offset + size > image->sections[section].size) {
|
if (offset + size > image->sections[section].size) {
|
||||||
LOG_DEBUG(
|
LOG_DEBUG(
|
||||||
"read past end of section: 0x%8.8" PRIx32 " + 0x%8.8" PRIx32 " > 0x%8.8" PRIx32 "",
|
"read past end of section: 0x%8.8" TARGET_PRIxADDR " + 0x%8.8" PRIx32 " > 0x%8.8" PRIx32 "",
|
||||||
offset,
|
offset,
|
||||||
size,
|
size,
|
||||||
image->sections[section].size);
|
image->sections[section].size);
|
||||||
|
@ -878,9 +1113,9 @@ int image_read_section(struct image *image,
|
||||||
*size_read = size;
|
*size_read = size;
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
} else if (image->type == IMAGE_ELF)
|
} else if (image->type == IMAGE_ELF) {
|
||||||
return image_elf_read_section(image, section, offset, size, buffer, size_read);
|
return image_elf_read_section(image, section, offset, size, buffer, size_read);
|
||||||
else if (image->type == IMAGE_MEMORY) {
|
} else if (image->type == IMAGE_MEMORY) {
|
||||||
struct image_memory *image_memory = image->type_private;
|
struct image_memory *image_memory = image->type_private;
|
||||||
uint32_t address = image->sections[section].base_address + offset;
|
uint32_t address = image->sections[section].base_address + offset;
|
||||||
|
|
||||||
|
@ -933,7 +1168,7 @@ int image_read_section(struct image *image,
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int image_add_section(struct image *image, uint32_t base, uint32_t size, int flags, uint8_t const *data)
|
int image_add_section(struct image *image, target_addr_t base, uint32_t size, int flags, uint8_t const *data)
|
||||||
{
|
{
|
||||||
struct imagesection *section;
|
struct imagesection *section;
|
||||||
|
|
||||||
|
@ -988,11 +1223,19 @@ void image_close(struct image *image)
|
||||||
|
|
||||||
fileio_close(image_elf->fileio);
|
fileio_close(image_elf->fileio);
|
||||||
|
|
||||||
free(image_elf->header);
|
if (image_elf->is_64_bit) {
|
||||||
image_elf->header = NULL;
|
free(image_elf->header64);
|
||||||
|
image_elf->header64 = NULL;
|
||||||
|
|
||||||
free(image_elf->segments);
|
free(image_elf->segments64);
|
||||||
image_elf->segments = NULL;
|
image_elf->segments64 = NULL;
|
||||||
|
} else {
|
||||||
|
free(image_elf->header32);
|
||||||
|
image_elf->header32 = NULL;
|
||||||
|
|
||||||
|
free(image_elf->segments32);
|
||||||
|
image_elf->segments32 = NULL;
|
||||||
|
}
|
||||||
} else if (image->type == IMAGE_MEMORY) {
|
} else if (image->type == IMAGE_MEMORY) {
|
||||||
struct image_memory *image_memory = image->type_private;
|
struct image_memory *image_memory = image->type_private;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
* Copyright (C) 2008 by Spencer Oliver *
|
* Copyright (C) 2008 by Spencer Oliver *
|
||||||
* spen@spen-soft.co.uk *
|
* spen@spen-soft.co.uk *
|
||||||
* *
|
* *
|
||||||
|
* Copyright (C) 2018 by Advantest *
|
||||||
|
* florian.meister@advantest.com *
|
||||||
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU General Public License as published by *
|
* it under the terms of the GNU General Public License as published by *
|
||||||
* the Free Software Foundation; either version 2 of the License, or *
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
@ -81,8 +84,15 @@ struct image_memory {
|
||||||
|
|
||||||
struct image_elf {
|
struct image_elf {
|
||||||
struct fileio *fileio;
|
struct fileio *fileio;
|
||||||
Elf32_Ehdr *header;
|
bool is_64_bit;
|
||||||
Elf32_Phdr *segments;
|
union {
|
||||||
|
Elf32_Ehdr *header32;
|
||||||
|
Elf64_Ehdr *header64;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
Elf32_Phdr *segments32;
|
||||||
|
Elf64_Phdr *segments64;
|
||||||
|
};
|
||||||
uint32_t segment_count;
|
uint32_t segment_count;
|
||||||
uint8_t endianness;
|
uint8_t endianness;
|
||||||
};
|
};
|
||||||
|
@ -93,11 +103,11 @@ struct image_mot {
|
||||||
};
|
};
|
||||||
|
|
||||||
int image_open(struct image *image, const char *url, const char *type_string);
|
int image_open(struct image *image, const char *url, const char *type_string);
|
||||||
int image_read_section(struct image *image, int section, uint32_t offset,
|
int image_read_section(struct image *image, int section, target_addr_t offset,
|
||||||
uint32_t size, uint8_t *buffer, size_t *size_read);
|
uint32_t size, uint8_t *buffer, size_t *size_read);
|
||||||
void image_close(struct image *image);
|
void image_close(struct image *image);
|
||||||
|
|
||||||
int image_add_section(struct image *image, uint32_t base, uint32_t size,
|
int image_add_section(struct image *image, target_addr_t base, uint32_t size,
|
||||||
int flags, uint8_t const *data);
|
int flags, uint8_t const *data);
|
||||||
|
|
||||||
int image_calculate_checksum(const uint8_t *buffer, uint32_t nbytes,
|
int image_calculate_checksum(const uint8_t *buffer, uint32_t nbytes,
|
||||||
|
|
|
@ -722,7 +722,9 @@ static int jim_nds32_bulk_write(Jim_Interp *interp, int argc, Jim_Obj * const *a
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct target *target = Jim_CmdPrivData(goi.interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
|
assert(cmd_ctx);
|
||||||
|
struct target *target = get_current_target(cmd_ctx);
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
result = target_write_buffer(target, address, count * 4, (const uint8_t *)data);
|
result = target_write_buffer(target, address, count * 4, (const uint8_t *)data);
|
||||||
|
@ -751,7 +753,9 @@ static int jim_nds32_multi_write(Jim_Interp *interp, int argc, Jim_Obj * const *
|
||||||
if (e != JIM_OK)
|
if (e != JIM_OK)
|
||||||
return e;
|
return e;
|
||||||
|
|
||||||
struct target *target = Jim_CmdPrivData(goi.interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
|
assert(cmd_ctx);
|
||||||
|
struct target *target = get_current_target(cmd_ctx);
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
struct aice_port_s *aice = target_to_aice(target);
|
||||||
int result;
|
int result;
|
||||||
uint32_t address;
|
uint32_t address;
|
||||||
|
@ -812,7 +816,9 @@ static int jim_nds32_bulk_read(Jim_Interp *interp, int argc, Jim_Obj * const *ar
|
||||||
if (goi.argc != 0)
|
if (goi.argc != 0)
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
|
|
||||||
struct target *target = Jim_CmdPrivData(goi.interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
|
assert(cmd_ctx);
|
||||||
|
struct target *target = get_current_target(cmd_ctx);
|
||||||
uint32_t *data = malloc(count * sizeof(uint32_t));
|
uint32_t *data = malloc(count * sizeof(uint32_t));
|
||||||
int result;
|
int result;
|
||||||
result = target_read_buffer(target, address, count * 4, (uint8_t *)data);
|
result = target_read_buffer(target, address, count * 4, (uint8_t *)data);
|
||||||
|
@ -863,7 +869,9 @@ static int jim_nds32_read_edm_sr(Jim_Interp *interp, int argc, Jim_Obj * const *
|
||||||
else
|
else
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
struct target *target = Jim_CmdPrivData(goi.interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
|
assert(cmd_ctx);
|
||||||
|
struct target *target = get_current_target(cmd_ctx);
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
struct aice_port_s *aice = target_to_aice(target);
|
||||||
char data_str[11];
|
char data_str[11];
|
||||||
|
|
||||||
|
@ -911,7 +919,9 @@ static int jim_nds32_write_edm_sr(Jim_Interp *interp, int argc, Jim_Obj * const
|
||||||
else
|
else
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
struct target *target = Jim_CmdPrivData(goi.interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
|
assert(cmd_ctx);
|
||||||
|
struct target *target = get_current_target(cmd_ctx);
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
struct aice_port_s *aice = target_to_aice(target);
|
||||||
|
|
||||||
aice_write_debug_reg(aice, edm_sr_number, value);
|
aice_write_debug_reg(aice, edm_sr_number, value);
|
||||||
|
|
|
@ -131,26 +131,6 @@ COMMAND_HANDLER(default_handle_smp_command)
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND_HANDLER(deprecated_handle_smp_on_command)
|
|
||||||
{
|
|
||||||
const char *argv[] = {"on", NULL};
|
|
||||||
|
|
||||||
LOG_WARNING("\'smp_on\' is deprecated, please use \'smp on\' instead.");
|
|
||||||
CMD_ARGC = 1;
|
|
||||||
CMD_ARGV = argv;
|
|
||||||
return CALL_COMMAND_HANDLER(default_handle_smp_command);
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_HANDLER(deprecated_handle_smp_off_command)
|
|
||||||
{
|
|
||||||
const char *argv[] = {"off", NULL};
|
|
||||||
|
|
||||||
LOG_WARNING("\'smp_off\' is deprecated, please use \'smp off\' instead.");
|
|
||||||
CMD_ARGC = 1;
|
|
||||||
CMD_ARGV = argv;
|
|
||||||
return CALL_COMMAND_HANDLER(default_handle_smp_command);
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_smp_gdb_command)
|
COMMAND_HANDLER(handle_smp_gdb_command)
|
||||||
{
|
{
|
||||||
struct target *target = get_current_target(CMD_CTX);
|
struct target *target = get_current_target(CMD_CTX);
|
||||||
|
@ -180,20 +160,6 @@ const struct command_registration smp_command_handlers[] = {
|
||||||
.help = "smp handling",
|
.help = "smp handling",
|
||||||
.usage = "[on|off]",
|
.usage = "[on|off]",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
.name = "smp_on",
|
|
||||||
.handler = deprecated_handle_smp_on_command,
|
|
||||||
.mode = COMMAND_EXEC,
|
|
||||||
.help = "Restart smp handling",
|
|
||||||
.usage = "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "smp_off",
|
|
||||||
.handler = deprecated_handle_smp_off_command,
|
|
||||||
.mode = COMMAND_EXEC,
|
|
||||||
.help = "Stop smp handling",
|
|
||||||
.usage = "",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
.name = "smp_gdb",
|
.name = "smp_gdb",
|
||||||
.handler = handle_smp_gdb_command,
|
.handler = handle_smp_gdb_command,
|
||||||
|
|
|
@ -206,3 +206,34 @@ proc init_target_events {} {
|
||||||
# Additionally board config scripts can define a procedure init_board that will be executed after init and init_targets
|
# Additionally board config scripts can define a procedure init_board that will be executed after init and init_targets
|
||||||
proc init_board {} {
|
proc init_board {} {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# smp_on/smp_off were already DEPRECATED in v0.11.0 through http://openocd.zylin.com/4615
|
||||||
|
proc "aarch64 smp_on" {args} {
|
||||||
|
echo "DEPRECATED! use 'aarch64 smp on' not 'aarch64 smp_on'"
|
||||||
|
eval aarch64 smp on $args
|
||||||
|
}
|
||||||
|
|
||||||
|
proc "aarch64 smp_off" {args} {
|
||||||
|
echo "DEPRECATED! use 'aarch64 smp off' not 'aarch64 smp_off'"
|
||||||
|
eval aarch64 smp off $args
|
||||||
|
}
|
||||||
|
|
||||||
|
proc "cortex_a smp_on" {args} {
|
||||||
|
echo "DEPRECATED! use 'cortex_a smp on' not 'cortex_a smp_on'"
|
||||||
|
eval cortex_a smp on $args
|
||||||
|
}
|
||||||
|
|
||||||
|
proc "cortex_a smp_off" {args} {
|
||||||
|
echo "DEPRECATED! use 'cortex_a smp off' not 'cortex_a smp_off'"
|
||||||
|
eval cortex_a smp off $args
|
||||||
|
}
|
||||||
|
|
||||||
|
proc "mips_m4k smp_on" {args} {
|
||||||
|
echo "DEPRECATED! use 'mips_m4k smp on' not 'mips_m4k smp_on'"
|
||||||
|
eval mips_m4k smp on $args
|
||||||
|
}
|
||||||
|
|
||||||
|
proc "mips_m4k smp_off" {args} {
|
||||||
|
echo "DEPRECATED! use 'mips_m4k smp off' not 'mips_m4k smp_off'"
|
||||||
|
eval mips_m4k smp off $args
|
||||||
|
}
|
||||||
|
|
|
@ -5229,30 +5229,37 @@ no_params:
|
||||||
|
|
||||||
static int jim_target_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
static int jim_target_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
||||||
{
|
{
|
||||||
|
struct command *c = jim_to_command(interp);
|
||||||
Jim_GetOptInfo goi;
|
Jim_GetOptInfo goi;
|
||||||
|
|
||||||
Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
|
Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
|
||||||
goi.isconfigure = !strcmp(Jim_GetString(argv[0], NULL), "configure");
|
goi.isconfigure = !strcmp(c->name, "configure");
|
||||||
if (goi.argc < 1) {
|
if (goi.argc < 1) {
|
||||||
Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv,
|
Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv,
|
||||||
"missing: -option ...");
|
"missing: -option ...");
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
}
|
}
|
||||||
struct target *target = Jim_CmdPrivData(goi.interp);
|
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);
|
return target_configure(&goi, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int jim_target_mem2array(Jim_Interp *interp,
|
static int jim_target_mem2array(Jim_Interp *interp,
|
||||||
int argc, Jim_Obj *const *argv)
|
int argc, Jim_Obj *const *argv)
|
||||||
{
|
{
|
||||||
struct target *target = Jim_CmdPrivData(interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
|
assert(cmd_ctx);
|
||||||
|
struct target *target = get_current_target(cmd_ctx);
|
||||||
return target_mem2array(interp, target, argc - 1, argv + 1);
|
return target_mem2array(interp, target, argc - 1, argv + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int jim_target_array2mem(Jim_Interp *interp,
|
static int jim_target_array2mem(Jim_Interp *interp,
|
||||||
int argc, Jim_Obj *const *argv)
|
int argc, Jim_Obj *const *argv)
|
||||||
{
|
{
|
||||||
struct target *target = Jim_CmdPrivData(interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
|
assert(cmd_ctx);
|
||||||
|
struct target *target = get_current_target(cmd_ctx);
|
||||||
return target_array2mem(interp, target, argc - 1, argv + 1);
|
return target_array2mem(interp, target, argc - 1, argv + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5284,7 +5291,9 @@ static int jim_target_examine(Jim_Interp *interp, int argc, Jim_Obj *const *argv
|
||||||
allow_defer = true;
|
allow_defer = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct target *target = Jim_CmdPrivData(interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
|
assert(cmd_ctx);
|
||||||
|
struct target *target = get_current_target(cmd_ctx);
|
||||||
if (!target->tap->enabled)
|
if (!target->tap->enabled)
|
||||||
return jim_target_tap_disabled(interp);
|
return jim_target_tap_disabled(interp);
|
||||||
|
|
||||||
|
@ -5302,7 +5311,9 @@ static int jim_target_examine(Jim_Interp *interp, int argc, Jim_Obj *const *argv
|
||||||
|
|
||||||
static int jim_target_was_examined(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
static int jim_target_was_examined(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
||||||
{
|
{
|
||||||
struct target *target = Jim_CmdPrivData(interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
|
assert(cmd_ctx);
|
||||||
|
struct target *target = get_current_target(cmd_ctx);
|
||||||
|
|
||||||
Jim_SetResultBool(interp, target_was_examined(target));
|
Jim_SetResultBool(interp, target_was_examined(target));
|
||||||
return JIM_OK;
|
return JIM_OK;
|
||||||
|
@ -5310,7 +5321,9 @@ static int jim_target_was_examined(Jim_Interp *interp, int argc, Jim_Obj * const
|
||||||
|
|
||||||
static int jim_target_examine_deferred(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
static int jim_target_examine_deferred(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
||||||
{
|
{
|
||||||
struct target *target = Jim_CmdPrivData(interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
|
assert(cmd_ctx);
|
||||||
|
struct target *target = get_current_target(cmd_ctx);
|
||||||
|
|
||||||
Jim_SetResultBool(interp, target->defer_examine);
|
Jim_SetResultBool(interp, target->defer_examine);
|
||||||
return JIM_OK;
|
return JIM_OK;
|
||||||
|
@ -5322,7 +5335,9 @@ static int jim_target_halt_gdb(Jim_Interp *interp, int argc, Jim_Obj *const *arg
|
||||||
Jim_WrongNumArgs(interp, 1, argv, "[no parameters]");
|
Jim_WrongNumArgs(interp, 1, argv, "[no parameters]");
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
}
|
}
|
||||||
struct target *target = Jim_CmdPrivData(interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
|
assert(cmd_ctx);
|
||||||
|
struct target *target = get_current_target(cmd_ctx);
|
||||||
|
|
||||||
if (target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT) != ERROR_OK)
|
if (target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT) != ERROR_OK)
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
|
@ -5336,7 +5351,9 @@ static int jim_target_poll(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||||
Jim_WrongNumArgs(interp, 1, argv, "[no parameters]");
|
Jim_WrongNumArgs(interp, 1, argv, "[no parameters]");
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
}
|
}
|
||||||
struct target *target = Jim_CmdPrivData(interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
|
assert(cmd_ctx);
|
||||||
|
struct target *target = get_current_target(cmd_ctx);
|
||||||
if (!target->tap->enabled)
|
if (!target->tap->enabled)
|
||||||
return jim_target_tap_disabled(interp);
|
return jim_target_tap_disabled(interp);
|
||||||
|
|
||||||
|
@ -5373,7 +5390,9 @@ static int jim_target_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||||
if (e != JIM_OK)
|
if (e != JIM_OK)
|
||||||
return e;
|
return e;
|
||||||
|
|
||||||
struct target *target = Jim_CmdPrivData(goi.interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
|
assert(cmd_ctx);
|
||||||
|
struct target *target = get_current_target(cmd_ctx);
|
||||||
if (!target->tap->enabled)
|
if (!target->tap->enabled)
|
||||||
return jim_target_tap_disabled(interp);
|
return jim_target_tap_disabled(interp);
|
||||||
|
|
||||||
|
@ -5406,7 +5425,9 @@ static int jim_target_halt(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||||
Jim_WrongNumArgs(interp, 1, argv, "[no parameters]");
|
Jim_WrongNumArgs(interp, 1, argv, "[no parameters]");
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
}
|
}
|
||||||
struct target *target = Jim_CmdPrivData(interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
|
assert(cmd_ctx);
|
||||||
|
struct target *target = get_current_target(cmd_ctx);
|
||||||
if (!target->tap->enabled)
|
if (!target->tap->enabled)
|
||||||
return jim_target_tap_disabled(interp);
|
return jim_target_tap_disabled(interp);
|
||||||
int e = target->type->halt(target);
|
int e = target->type->halt(target);
|
||||||
|
@ -5436,7 +5457,9 @@ static int jim_target_wait_state(Jim_Interp *interp, int argc, Jim_Obj *const *a
|
||||||
e = Jim_GetOpt_Wide(&goi, &a);
|
e = Jim_GetOpt_Wide(&goi, &a);
|
||||||
if (e != JIM_OK)
|
if (e != JIM_OK)
|
||||||
return e;
|
return e;
|
||||||
struct target *target = Jim_CmdPrivData(interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
|
assert(cmd_ctx);
|
||||||
|
struct target *target = get_current_target(cmd_ctx);
|
||||||
if (!target->tap->enabled)
|
if (!target->tap->enabled)
|
||||||
return jim_target_tap_disabled(interp);
|
return jim_target_tap_disabled(interp);
|
||||||
|
|
||||||
|
@ -5480,7 +5503,9 @@ static int jim_target_current_state(Jim_Interp *interp, int argc, Jim_Obj *const
|
||||||
Jim_WrongNumArgs(interp, 1, argv, "[no parameters]");
|
Jim_WrongNumArgs(interp, 1, argv, "[no parameters]");
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
}
|
}
|
||||||
struct target *target = Jim_CmdPrivData(interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
|
assert(cmd_ctx);
|
||||||
|
struct target *target = get_current_target(cmd_ctx);
|
||||||
Jim_SetResultString(interp, target_state_name(target), -1);
|
Jim_SetResultString(interp, target_state_name(target), -1);
|
||||||
return JIM_OK;
|
return JIM_OK;
|
||||||
}
|
}
|
||||||
|
@ -5499,7 +5524,9 @@ static int jim_target_invoke_event(Jim_Interp *interp, int argc, Jim_Obj *const
|
||||||
Jim_GetOpt_NvpUnknown(&goi, nvp_target_event, 1);
|
Jim_GetOpt_NvpUnknown(&goi, nvp_target_event, 1);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
struct target *target = Jim_CmdPrivData(interp);
|
struct command_context *cmd_ctx = current_command_context(interp);
|
||||||
|
assert(cmd_ctx);
|
||||||
|
struct target *target = get_current_target(cmd_ctx);
|
||||||
target_handle_event(target, n->value);
|
target_handle_event(target, n->value);
|
||||||
return JIM_OK;
|
return JIM_OK;
|
||||||
}
|
}
|
||||||
|
@ -5877,7 +5904,7 @@ static int target_create(Jim_GetOptInfo *goi)
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
e = register_commands(cmd_ctx, NULL, target_commands);
|
e = register_commands_override_target(cmd_ctx, NULL, target_commands, target);
|
||||||
if (e != ERROR_OK) {
|
if (e != ERROR_OK) {
|
||||||
if (target->type->deinit_target)
|
if (target->type->deinit_target)
|
||||||
target->type->deinit_target(target);
|
target->type->deinit_target(target);
|
||||||
|
@ -5890,10 +5917,6 @@ static int target_create(Jim_GetOptInfo *goi)
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct command *c = command_find_in_context(cmd_ctx, cp);
|
|
||||||
assert(c);
|
|
||||||
command_set_handler_data(c, target);
|
|
||||||
|
|
||||||
/* append to end of list */
|
/* append to end of list */
|
||||||
append_to_list_all_targets(target);
|
append_to_list_all_targets(target);
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ proc init_l2cc { } {
|
||||||
; #orr r0, r0, #(1 << 22) /* disable write allocate */
|
; #orr r0, r0, #(1 << 22) /* disable write allocate */
|
||||||
|
|
||||||
; #mcr 15, 1, r0, c9, c0, 2
|
; #mcr 15, 1, r0, c9, c0, 2
|
||||||
arm mcr 15 1 9 0 2 [expr 0xC4 | (1<<24) | (1<<23) | (1<22)]
|
arm mcr 15 1 9 0 2 [expr 0xC4 | (1<<24) | (1<<23) | (1<<22)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ proc init_l2cc { } {
|
||||||
; #orr r0, r0, #(1 << 22) /* disable write allocate */
|
; #orr r0, r0, #(1 << 22) /* disable write allocate */
|
||||||
|
|
||||||
; #mcr 15, 1, r0, c9, c0, 2
|
; #mcr 15, 1, r0, c9, c0, 2
|
||||||
arm mcr 15 1 9 0 2 [expr 0xC4 | (1<<24) | (1<<23) | (1<22)]
|
arm mcr 15 1 9 0 2 [expr 0xC4 | (1<<24) | (1<<23) | (1<<22)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,7 @@ proc init_l2cc { } {
|
||||||
; #orr r0, r0, #(1 << 22) /* disable write allocate */
|
; #orr r0, r0, #(1 << 22) /* disable write allocate */
|
||||||
|
|
||||||
; #mcr 15, 1, r0, c9, c0, 2
|
; #mcr 15, 1, r0, c9, c0, 2
|
||||||
arm mcr 15 1 9 0 2 [expr 0xC4 | (1<<24) | (1<<23) | (1<22)]
|
arm mcr 15 1 9 0 2 [expr 0xC4 | (1<<24) | (1<<23) | (1<<22)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
# pico-debug is a virtual CMSIS-DAP debug adapter
|
||||||
|
# it runs on the very same RP2040 target being debugged without additional hardware
|
||||||
|
# https://github.com/majbthrd/pico-debug
|
||||||
|
|
||||||
|
source [find interface/cmsis-dap.cfg]
|
||||||
|
adapter speed 4000
|
||||||
|
|
||||||
|
set CHIPNAME rp2040
|
||||||
|
source [find target/rp2040-core0.cfg]
|
||||||
|
|
|
@ -26,30 +26,30 @@
|
||||||
# tdf_cycles
|
# tdf_cycles
|
||||||
proc sam9_smc_config { cs smc_config } {
|
proc sam9_smc_config { cs smc_config } {
|
||||||
;# Setup Register for CS n
|
;# Setup Register for CS n
|
||||||
set AT91_SMC_SETUP [expr ($::AT91_SMC + 0x00 + ((cs)*0x10))]
|
set AT91_SMC_SETUP [expr {$::AT91_SMC + 0x00 + $cs * 0x10}]
|
||||||
set val [expr ($smc_config(nwe_setup) << 0)]
|
set val [expr {$smc_config(nwe_setup) << 0}]
|
||||||
set val [expr ($val | $smc_config(ncs_write_setup) << 8]
|
set val [expr {$val | $smc_config(ncs_write_setup) << 8}]
|
||||||
set val [expr ($val | $smc_config(nrd_setup)) << 16]
|
set val [expr {$val | $smc_config(nrd_setup)) << 16}]
|
||||||
set val [expr ($val | $smc_config(ncs_read_setup) << 24]
|
set val [expr {$val | $smc_config(ncs_read_setup) << 24}]
|
||||||
mww $AT91_SMC_SETUP $val
|
mww $AT91_SMC_SETUP $val
|
||||||
|
|
||||||
;# Pulse Register for CS n
|
;# Pulse Register for CS n
|
||||||
set AT91_SMC_PULSE [expr ($::AT91_SMC + 0x04 + ((cs)*0x10))]
|
set AT91_SMC_PULSE [expr {$::AT91_SMC + 0x04 + $cs * 0x10}]
|
||||||
set val [expr ($smc_config(nwe_pulse) << 0)]
|
set val [expr {$smc_config(nwe_pulse) << 0}]
|
||||||
set val [expr ($val | $smc_config(ncs_write_pulse) << 8]
|
set val [expr {$val | $smc_config(ncs_write_pulse) << 8}]
|
||||||
set val [expr ($val | $smc_config(nrd_pulse) << 16]
|
set val [expr {$val | $smc_config(nrd_pulse) << 16}]
|
||||||
set val [expr ($val | $smc_config(ncs_read_pulse) << 24]
|
set val [expr {$val | $smc_config(ncs_read_pulse) << 24}]
|
||||||
mww $AT91_SMC_PULSE $val
|
mww $AT91_SMC_PULSE $val
|
||||||
|
|
||||||
;# Cycle Register for CS n
|
;# Cycle Register for CS n
|
||||||
set AT91_SMC_CYCLE [expr ($::AT91_SMC + 0x08 + ((cs)*0x10))]
|
set AT91_SMC_CYCLE [expr {$::AT91_SMC + 0x08 + $cs * 0x10}]
|
||||||
set val [expr ($smc_config(write_cycle) << 0)]
|
set val [expr {$smc_config(write_cycle) << 0}]
|
||||||
set val [expr ($val | $smc_config(read_cycle) << 16]
|
set val [expr {$val | $smc_config(read_cycle) << 16}]
|
||||||
mww $AT91_SMC_CYCLE $val
|
mww $AT91_SMC_CYCLE $val
|
||||||
|
|
||||||
;# Mode Register for CS n
|
;# Mode Register for CS n
|
||||||
set AT91_SMC_MODE [expr ($::AT91_SMC + 0x0c + ((cs)*0x10))]
|
set AT91_SMC_MODE [expr {$::AT91_SMC + 0x0c + $cs * 0x10}]
|
||||||
set val [expr ($smc_config(mode) << 0)]
|
set val [expr {$smc_config(mode) << 0}]
|
||||||
set val [expr ($val | $smc_config(tdf_cycles) << 16]
|
set val [expr {$val | $smc_config(tdf_cycles) << 16}]
|
||||||
mww $AT91_SMC_MODE $val
|
mww $AT91_SMC_MODE $val
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
#
|
||||||
|
# NXP i.MX8QuadMax
|
||||||
|
#
|
||||||
|
|
||||||
|
if { [info exists CHIPNAME] } {
|
||||||
|
set _CHIPNAME $CHIPNAME
|
||||||
|
} else {
|
||||||
|
set _CHIPNAME imx8qm
|
||||||
|
}
|
||||||
|
|
||||||
|
# CoreSight Debug Access Port (DAP)
|
||||||
|
if { [info exists DAP_TAPID] } {
|
||||||
|
set _DAP_TAPID $DAP_TAPID
|
||||||
|
} else {
|
||||||
|
# TAPID is from FreeScale!
|
||||||
|
set _DAP_TAPID 0x1890101d
|
||||||
|
}
|
||||||
|
|
||||||
|
jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \
|
||||||
|
-expected-id $_DAP_TAPID
|
||||||
|
|
||||||
|
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
|
||||||
|
|
||||||
|
# AXI: Main SOC bus on AP #0
|
||||||
|
target create ${_CHIPNAME}.axi mem_ap -dap ${_CHIPNAME}.dap -ap-num 0
|
||||||
|
|
||||||
|
# 4x Cortex-A53 on AP #6
|
||||||
|
set _A53_DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000}
|
||||||
|
set _A53_CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000}
|
||||||
|
|
||||||
|
cti create $_CHIPNAME.a53_cti.0 -dap $_CHIPNAME.dap \
|
||||||
|
-ap-num 6 -baseaddr [lindex $_A53_CTIBASE 0]
|
||||||
|
cti create $_CHIPNAME.a53_cti.1 -dap $_CHIPNAME.dap \
|
||||||
|
-ap-num 6 -baseaddr [lindex $_A53_CTIBASE 1]
|
||||||
|
cti create $_CHIPNAME.a53_cti.2 -dap $_CHIPNAME.dap \
|
||||||
|
-ap-num 6 -baseaddr [lindex $_A53_CTIBASE 2]
|
||||||
|
cti create $_CHIPNAME.a53_cti.3 -dap $_CHIPNAME.dap \
|
||||||
|
-ap-num 6 -baseaddr [lindex $_A53_CTIBASE 3]
|
||||||
|
target create $_CHIPNAME.a53.0 aarch64 -dap $_CHIPNAME.dap \
|
||||||
|
-cti $_CHIPNAME.a53_cti.0 -dbgbase [lindex $_A53_DBGBASE 0]
|
||||||
|
target create $_CHIPNAME.a53.1 aarch64 -dap $_CHIPNAME.dap \
|
||||||
|
-cti $_CHIPNAME.a53_cti.1 -dbgbase [lindex $_A53_DBGBASE 1] -defer-examine
|
||||||
|
target create $_CHIPNAME.a53.2 aarch64 -dap $_CHIPNAME.dap \
|
||||||
|
-cti $_CHIPNAME.a53_cti.2 -dbgbase [lindex $_A53_DBGBASE 2] -defer-examine
|
||||||
|
target create $_CHIPNAME.a53.3 aarch64 -dap $_CHIPNAME.dap \
|
||||||
|
-cti $_CHIPNAME.a53_cti.3 -dbgbase [lindex $_A53_DBGBASE 3] -defer-examine
|
||||||
|
|
||||||
|
# 2x Cortex-A72 on AP #6
|
||||||
|
set _A72_DBGBASE {0x80210000 0x80310000}
|
||||||
|
set _A72_CTIBASE {0x80220000 0x80220000}
|
||||||
|
|
||||||
|
cti create $_CHIPNAME.a72_cti.0 -dap $_CHIPNAME.dap \
|
||||||
|
-ap-num 6 -baseaddr [lindex $_A72_CTIBASE 0]
|
||||||
|
cti create $_CHIPNAME.a72_cti.1 -dap $_CHIPNAME.dap \
|
||||||
|
-ap-num 6 -baseaddr [lindex $_A72_CTIBASE 1]
|
||||||
|
target create $_CHIPNAME.a72.0 aarch64 -dap $_CHIPNAME.dap \
|
||||||
|
-cti $_CHIPNAME.a72_cti.0 -dbgbase [lindex $_A72_DBGBASE 0] -defer-examine
|
||||||
|
target create $_CHIPNAME.a72.1 aarch64 -dap $_CHIPNAME.dap \
|
||||||
|
-cti $_CHIPNAME.a72_cti.1 -dbgbase [lindex $_A72_DBGBASE 1] -defer-examine
|
||||||
|
|
||||||
|
# All Cortex-A in SMP
|
||||||
|
target smp \
|
||||||
|
$_CHIPNAME.a53.0 \
|
||||||
|
$_CHIPNAME.a53.1 \
|
||||||
|
$_CHIPNAME.a53.2 \
|
||||||
|
$_CHIPNAME.a53.3 \
|
||||||
|
$_CHIPNAME.a72.0 \
|
||||||
|
$_CHIPNAME.a72.1
|
||||||
|
|
||||||
|
# SCU: Cortex-M4 core
|
||||||
|
# always running imx SC firmware
|
||||||
|
target create ${_CHIPNAME}.scu cortex_m -dap ${_CHIPNAME}.dap -ap-num 1
|
||||||
|
|
||||||
|
# AHB from SCU perspective
|
||||||
|
target create ${_CHIPNAME}.scu_ahb mem_ap -dap ${_CHIPNAME}.dap -ap-num 4
|
||||||
|
|
||||||
|
# Cortex-M4 M4_0 core on AP #2 (default off)
|
||||||
|
target create ${_CHIPNAME}.m4_0 cortex_m -dap ${_CHIPNAME}.dap -ap-num 2 \
|
||||||
|
-defer-examine
|
||||||
|
|
||||||
|
# Cortex-M4 M4_1 core on AP #3 (default off)
|
||||||
|
target create ${_CHIPNAME}.m4_1 cortex_m -dap ${_CHIPNAME}.dap -ap-num 3 \
|
||||||
|
-defer-examine
|
||||||
|
|
||||||
|
# Debug APB bus
|
||||||
|
target create ${_CHIPNAME}.apb mem_ap -dap ${_CHIPNAME}.dap -ap-num 6
|
||||||
|
|
||||||
|
# Default target is boot core a53.0
|
||||||
|
targets $_CHIPNAME.a53.0
|
|
@ -0,0 +1,38 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
transport select swd
|
||||||
|
|
||||||
|
source [find target/swj-dp.tcl]
|
||||||
|
|
||||||
|
if { [info exists CHIPNAME] } {
|
||||||
|
set _CHIPNAME $CHIPNAME
|
||||||
|
} else {
|
||||||
|
set _CHIPNAME rp2040
|
||||||
|
}
|
||||||
|
|
||||||
|
if { [info exists WORKAREASIZE] } {
|
||||||
|
set _WORKAREASIZE $WORKAREASIZE
|
||||||
|
} else {
|
||||||
|
set _WORKAREASIZE 0x10000
|
||||||
|
}
|
||||||
|
|
||||||
|
if { [info exists CPUTAPID] } {
|
||||||
|
set _CPUTAPID $CPUTAPID
|
||||||
|
} else {
|
||||||
|
set _CPUTAPID 0x01002927
|
||||||
|
}
|
||||||
|
|
||||||
|
swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID
|
||||||
|
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
|
||||||
|
set _TARGETNAME $_CHIPNAME.cpu
|
||||||
|
target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap
|
||||||
|
$_TARGETNAME configure -work-area-phys 0x20010000 -work-area-size $_WORKAREASIZE
|
||||||
|
|
||||||
|
set _FLASHNAME $_CHIPNAME.flash
|
||||||
|
set _FLASHSIZE 0x200000
|
||||||
|
set _FLASHBASE 0x10000000
|
||||||
|
flash bank $_FLASHNAME rp2040_flash $_FLASHBASE $_FLASHSIZE 1 32 $_TARGETNAME
|
||||||
|
|
||||||
|
# srst does not exist; use SYSRESETREQ to perform a soft reset
|
||||||
|
cortex_m reset_config sysresetreq
|
||||||
|
|
Loading…
Reference in New Issue