aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/flash/nor/Makefile.am6
-rw-r--r--src/flash/nor/at91sam4.c81
-rw-r--r--src/flash/nor/at91samd.c5
-rw-r--r--src/flash/nor/cc26xx.c567
-rw-r--r--src/flash/nor/cc26xx.h101
-rw-r--r--src/flash/nor/drivers.c4
-rw-r--r--src/flash/nor/msp432.c1103
-rw-r--r--src/flash/nor/msp432.h127
-rw-r--r--src/flash/nor/nrf5.c75
-rw-r--r--src/flash/nor/psoc5lp.c34
-rw-r--r--src/flash/nor/stm32f1x.c4
-rw-r--r--src/flash/nor/stm32f2x.c6
-rw-r--r--src/flash/nor/stm32h7x.c10
-rw-r--r--src/flash/nor/stm32l4x.c6
-rw-r--r--src/flash/nor/stm32lx.c2
-rw-r--r--src/flash/nor/tcl.c58
-rw-r--r--src/flash/nor/tms470.c36
-rw-r--r--src/jtag/aice/aice_usb.c52
-rw-r--r--src/jtag/aice/aice_usb.h1
-rw-r--r--src/jtag/core.c2
-rw-r--r--src/jtag/drivers/cmsis_dap_usb.c67
-rw-r--r--src/jtag/drivers/jlink.c4
-rw-r--r--src/jtag/drivers/jtag_vpi.c13
-rw-r--r--src/jtag/drivers/stlink_usb.c5
-rw-r--r--src/jtag/drivers/usb_blaster/usb_blaster.c41
-rw-r--r--src/jtag/hla/hla_interface.c2
-rw-r--r--src/jtag/hla/hla_layout.h2
-rw-r--r--src/jtag/interface.h4
-rw-r--r--src/jtag/zy1000/zy1000.c2
-rw-r--r--src/rtos/Makefile.am2
-rw-r--r--src/rtos/nuttx.c405
-rw-r--r--src/rtos/nuttx_header.h71
-rw-r--r--src/rtos/rtos.c2
-rw-r--r--src/server/gdb_server.c13
-rw-r--r--src/server/server.c97
-rw-r--r--src/server/server.h1
-rw-r--r--src/target/aarch64.c21
-rw-r--r--src/target/adi_v5_swd.c11
-rw-r--r--src/target/arm_adi_v5.c89
-rw-r--r--src/target/arm_adi_v5.h3
-rw-r--r--src/target/arm_dap.c5
-rw-r--r--src/target/arm_disassembler.c75
-rw-r--r--src/target/arm_semihosting.c87
-rw-r--r--src/target/armv4_5.c6
-rw-r--r--src/target/armv7a.c7
-rw-r--r--src/target/armv7a.h1
-rw-r--r--src/target/armv7a_cache.c27
-rw-r--r--src/target/armv7m.c6
-rw-r--r--src/target/armv7m_trace.c20
-rw-r--r--src/target/armv7m_trace.h16
-rw-r--r--src/target/armv8.c15
-rw-r--r--src/target/armv8.h14
-rw-r--r--src/target/cortex_a.c19
-rw-r--r--src/target/cortex_m.c43
-rw-r--r--src/target/image.c3
-rw-r--r--src/target/mips_m4k.c2
-rw-r--r--src/target/riscv/riscv-011.c3
-rw-r--r--src/target/semihosting_common.c34
-rw-r--r--src/target/target.c5
59 files changed, 3122 insertions, 401 deletions
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index db936b8..9a58239 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -20,6 +20,7 @@ NOR_DRIVERS = \
%D%/avrf.c \
%D%/bluenrg-x.c \
%D%/cc3220sf.c \
+ %D%/cc26xx.c \
%D%/cfi.c \
%D%/dsp5680xx_flash.c \
%D%/efm32.c \
@@ -36,6 +37,7 @@ NOR_DRIVERS = \
%D%/lpc2900.c \
%D%/lpcspifi.c \
%D%/mdr.c \
+ %D%/msp432.c \
%D%/mrvlqspi.c \
%D%/niietcm4.c \
%D%/non_cfi.c \
@@ -67,9 +69,11 @@ NOR_DRIVERS = \
NORHEADERS = \
%D%/core.h \
%D%/cc3220sf.h \
+ %D%/cc26xx.h \
%D%/cfi.h \
%D%/driver.h \
%D%/imp.h \
%D%/non_cfi.h \
%D%/ocl.h \
- %D%/spi.h
+ %D%/spi.h \
+ %D%/msp432.h
diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c
index 0475216..c5b31e9 100644
--- a/src/flash/nor/at91sam4.c
+++ b/src/flash/nor/at91sam4.c
@@ -682,6 +682,40 @@ static const struct sam4_chip_details all_sam4_details[] = {
},
},
},
+ /*at91sam4sa16c - TFBGA100/VFBGA100/LQFP100*/
+ {
+ .chipid_cidr = 0x28a70ce0,
+ .name = "at91sam4sa16c",
+ .total_flash_size = 1024 * 1024,
+ .total_sram_size = 160 * 1024,
+ .n_gpnvms = 2,
+ .n_banks = 1,
+
+/* .bank[0] = { */
+ {
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 0,
+ .base_address = FLASH_BANK_BASE_S,
+ .controller_address = 0x400e0a00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 1024 * 1024,
+ .nsectors = 128,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+/* .bank[1] = {*/
+ {
+ .present = 0,
+ .probed = 0,
+ .bank_number = 1,
+
+ },
+ },
+ },
/*atsam4s16b - LQFP64/QFN64/WLCSP64*/
{
.chipid_cidr = 0x289C0CE0,
@@ -1261,50 +1295,6 @@ static const struct sam4_chip_details all_sam4_details[] = {
},
},
- /*at91sam4sa16c*/
- {
- .chipid_cidr = 0x28a70ce0,
- .name = "at91sam4sa16c",
- .total_flash_size = 1024 * 1024,
- .total_sram_size = 160 * 1024,
- .n_gpnvms = 3,
- .n_banks = 2,
-
-/* .bank[0] = { */
- {
- {
- .probed = 0,
- .pChip = NULL,
- .pBank = NULL,
- .bank_number = 0,
- .base_address = FLASH_BANK0_BASE_SD,
- .controller_address = 0x400e0a00,
- .flash_wait_states = 5,
- .present = 1,
- .size_bytes = 512 * 1024,
- .nsectors = 64,
- .sector_size = 8192,
- .page_size = 512,
- },
-
-/* .bank[1] = { */
- {
- .probed = 0,
- .pChip = NULL,
- .pBank = NULL,
- .bank_number = 1,
- .base_address = FLASH_BANK1_BASE_1024K_SD,
- .controller_address = 0x400e0c00,
- .flash_wait_states = 5,
- .present = 1,
- .size_bytes = 512 * 1024,
- .nsectors = 64,
- .sector_size = 8192,
- .page_size = 512,
- },
- },
- },
-
/* atsamg53n19 */
{
.chipid_cidr = 0x247e0ae0,
@@ -2554,6 +2544,8 @@ static int sam4_GetDetails(struct sam4_bank_private *pPrivate)
pPrivate->pChip->cfg.CHIPID_CIDR);
sam4_explain_chipid_cidr(pPrivate->pChip);
return ERROR_FAIL;
+ } else {
+ LOG_INFO("SAM4 Found chip %s, CIDR 0x%08x", pDetails->name, pDetails->chipid_cidr);
}
/* DANGER: THERE ARE DRAGONS HERE */
@@ -2624,6 +2616,7 @@ static int _sam4_probe(struct flash_bank *bank, int noise)
for (x = 0; x < SAM4_MAX_FLASH_BANKS; x++) {
if (bank->base == pPrivate->pChip->details.bank[x].base_address) {
bank->size = pPrivate->pChip->details.bank[x].size_bytes;
+ LOG_INFO("SAM4 Set flash bank to %08X - %08X, idx %d", bank->base, bank->base + bank->size, x);
break;
}
}
diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c
index 8553ee8..017d144 100644
--- a/src/flash/nor/at91samd.c
+++ b/src/flash/nor/at91samd.c
@@ -115,15 +115,16 @@ static const struct samd_part samd10_parts[] = {
/* Known SAMD11 parts */
static const struct samd_part samd11_parts[] = {
- { 0x0, "SAMD11D14AMU", 16, 4 },
+ { 0x0, "SAMD11D14AM", 16, 4 },
{ 0x1, "SAMD11D13AMU", 8, 4 },
{ 0x2, "SAMD11D12AMU", 4, 4 },
- { 0x3, "SAMD11D14ASU", 16, 4 },
+ { 0x3, "SAMD11D14ASS", 16, 4 },
{ 0x4, "SAMD11D13ASU", 8, 4 },
{ 0x5, "SAMD11D12ASU", 4, 4 },
{ 0x6, "SAMD11C14A", 16, 4 },
{ 0x7, "SAMD11C13A", 8, 4 },
{ 0x8, "SAMD11C12A", 4, 4 },
+ { 0x9, "SAMD11D14AU", 16, 4 },
};
/* Known SAMD20 parts. See Table 12-8 in 42129F–SAM–10/2013 */
diff --git a/src/flash/nor/cc26xx.c b/src/flash/nor/cc26xx.c
new file mode 100644
index 0000000..e6e9e59
--- /dev/null
+++ b/src/flash/nor/cc26xx.c
@@ -0,0 +1,567 @@
+/***************************************************************************
+ * Copyright (C) 2017 by Texas Instruments, Inc. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include "cc26xx.h"
+#include <helper/binarybuffer.h>
+#include <helper/time_support.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+#include <target/image.h>
+
+#define FLASH_TIMEOUT 8000
+
+struct cc26xx_bank {
+ const char *family_name;
+ uint32_t icepick_id;
+ uint32_t user_id;
+ uint32_t device_type;
+ uint32_t sector_length;
+ bool probed;
+ struct working_area *working_area;
+ struct armv7m_algorithm armv7m_info;
+ const uint8_t *algo_code;
+ uint32_t algo_size;
+ uint32_t algo_working_size;
+ uint32_t buffer_addr[2];
+ uint32_t params_addr[2];
+};
+
+static int cc26xx_auto_probe(struct flash_bank *bank);
+
+static uint32_t cc26xx_device_type(uint32_t icepick_id, uint32_t user_id)
+{
+ uint32_t device_type = 0;
+
+ switch (icepick_id & ICEPICK_ID_MASK) {
+ case CC26X0_ICEPICK_ID:
+ device_type = CC26X0_TYPE;
+ break;
+ case CC26X1_ICEPICK_ID:
+ device_type = CC26X1_TYPE;
+ break;
+ case CC13X0_ICEPICK_ID:
+ device_type = CC13X0_TYPE;
+ break;
+ case CC13X2_CC26X2_ICEPICK_ID:
+ default:
+ if ((user_id & USER_ID_CC13_MASK) != 0)
+ device_type = CC13X2_TYPE;
+ else
+ device_type = CC26X2_TYPE;
+ break;
+ }
+
+ return device_type;
+}
+
+static uint32_t cc26xx_sector_length(uint32_t icepick_id)
+{
+ uint32_t sector_length;
+
+ switch (icepick_id & ICEPICK_ID_MASK) {
+ case CC26X0_ICEPICK_ID:
+ case CC26X1_ICEPICK_ID:
+ case CC13X0_ICEPICK_ID:
+ /* Chameleon family device */
+ sector_length = CC26X0_SECTOR_LENGTH;
+ break;
+ case CC13X2_CC26X2_ICEPICK_ID:
+ default:
+ /* Agama family device */
+ sector_length = CC26X2_SECTOR_LENGTH;
+ break;
+ }
+
+ return sector_length;
+}
+
+static int cc26xx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr)
+{
+ struct target *target = bank->target;
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+
+ uint32_t status_addr = params_addr + CC26XX_STATUS_OFFSET;
+ uint32_t status = CC26XX_BUFFER_FULL;
+ long long start_ms;
+ long long elapsed_ms;
+
+ int retval = ERROR_OK;
+
+ start_ms = timeval_ms();
+ while (CC26XX_BUFFER_FULL == status) {
+ retval = target_read_u32(target, status_addr, &status);
+ if (ERROR_OK != retval)
+ return retval;
+
+ elapsed_ms = timeval_ms() - start_ms;
+ if (elapsed_ms > 500)
+ keep_alive();
+ if (elapsed_ms > FLASH_TIMEOUT)
+ break;
+ };
+
+ if (CC26XX_BUFFER_EMPTY != status) {
+ LOG_ERROR("%s: Flash operation failed", cc26xx_bank->family_name);
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static int cc26xx_init(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+
+ int retval;
+
+ /* Make sure we've probed the flash to get the device and size */
+ retval = cc26xx_auto_probe(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Check for working area to use for flash helper algorithm */
+ if (NULL != cc26xx_bank->working_area)
+ target_free_working_area(target, cc26xx_bank->working_area);
+ retval = target_alloc_working_area(target, cc26xx_bank->algo_working_size,
+ &cc26xx_bank->working_area);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Confirm the defined working address is the area we need to use */
+ if (CC26XX_ALGO_BASE_ADDRESS != cc26xx_bank->working_area->address)
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+
+ /* Write flash helper algorithm into target memory */
+ retval = target_write_buffer(target, CC26XX_ALGO_BASE_ADDRESS,
+ cc26xx_bank->algo_size, cc26xx_bank->algo_code);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("%s: Failed to load flash helper algorithm",
+ cc26xx_bank->family_name);
+ target_free_working_area(target, cc26xx_bank->working_area);
+ return retval;
+ }
+
+ /* Initialize the ARMv7 specific info to run the algorithm */
+ cc26xx_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+ cc26xx_bank->armv7m_info.core_mode = ARM_MODE_THREAD;
+
+ /* Begin executing the flash helper algorithm */
+ retval = target_start_algorithm(target, 0, NULL, 0, NULL,
+ CC26XX_ALGO_BASE_ADDRESS, 0, &cc26xx_bank->armv7m_info);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("%s: Failed to start flash helper algorithm",
+ cc26xx_bank->family_name);
+ target_free_working_area(target, cc26xx_bank->working_area);
+ return retval;
+ }
+
+ /*
+ * At this point, the algorithm is running on the target and
+ * ready to receive commands and data to flash the target
+ */
+
+ return retval;
+}
+
+static int cc26xx_quit(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+
+ int retval;
+
+ /* Regardless of the algo's status, attempt to halt the target */
+ (void)target_halt(target);
+
+ /* Now confirm target halted and clean up from flash helper algorithm */
+ retval = target_wait_algorithm(target, 0, NULL, 0, NULL, 0, FLASH_TIMEOUT,
+ &cc26xx_bank->armv7m_info);
+
+ target_free_working_area(target, cc26xx_bank->working_area);
+ cc26xx_bank->working_area = NULL;
+
+ return retval;
+}
+
+static int cc26xx_mass_erase(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+ struct cc26xx_algo_params algo_params;
+
+ int retval;
+
+ if (TARGET_HALTED != target->state) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ retval = cc26xx_init(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Initialize algorithm parameters */
+ buf_set_u32(algo_params.address, 0, 32, 0);
+ buf_set_u32(algo_params.length, 0, 32, 4);
+ buf_set_u32(algo_params.command, 0, 32, CC26XX_CMD_ERASE_ALL);
+ buf_set_u32(algo_params.status, 0, 32, CC26XX_BUFFER_FULL);
+
+ /* Issue flash helper algorithm parameters for mass erase */
+ retval = target_write_buffer(target, cc26xx_bank->params_addr[0],
+ sizeof(algo_params), (uint8_t *)&algo_params);
+
+ /* Wait for command to complete */
+ if (ERROR_OK == retval)
+ retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[0]);
+
+ /* Regardless of errors, try to close down algo */
+ (void)cc26xx_quit(bank);
+
+ return retval;
+}
+
+FLASH_BANK_COMMAND_HANDLER(cc26xx_flash_bank_command)
+{
+ struct cc26xx_bank *cc26xx_bank;
+
+ if (CMD_ARGC < 6)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ cc26xx_bank = malloc(sizeof(struct cc26xx_bank));
+ if (NULL == cc26xx_bank)
+ return ERROR_FAIL;
+
+ /* Initialize private flash information */
+ memset((void *)cc26xx_bank, 0x00, sizeof(struct cc26xx_bank));
+ cc26xx_bank->family_name = "cc26xx";
+ cc26xx_bank->device_type = CC26XX_NO_TYPE;
+ cc26xx_bank->sector_length = 0x1000;
+
+ /* Finish initialization of bank */
+ bank->driver_priv = cc26xx_bank;
+ bank->next = NULL;
+
+ return ERROR_OK;
+}
+
+static int cc26xx_erase(struct flash_bank *bank, int first, int last)
+{
+ struct target *target = bank->target;
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+ struct cc26xx_algo_params algo_params;
+
+ uint32_t address;
+ uint32_t length;
+ int retval;
+
+ if (TARGET_HALTED != target->state) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* Do a mass erase if user requested all sectors of flash */
+ if ((first == 0) && (last == (bank->num_sectors - 1))) {
+ /* Request mass erase of flash */
+ return cc26xx_mass_erase(bank);
+ }
+
+ address = first * cc26xx_bank->sector_length;
+ length = (last - first + 1) * cc26xx_bank->sector_length;
+
+ retval = cc26xx_init(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Set up algorithm parameters for erase command */
+ buf_set_u32(algo_params.address, 0, 32, address);
+ buf_set_u32(algo_params.length, 0, 32, length);
+ buf_set_u32(algo_params.command, 0, 32, CC26XX_CMD_ERASE_SECTORS);
+ buf_set_u32(algo_params.status, 0, 32, CC26XX_BUFFER_FULL);
+
+ /* Issue flash helper algorithm parameters for erase */
+ retval = target_write_buffer(target, cc26xx_bank->params_addr[0],
+ sizeof(algo_params), (uint8_t *)&algo_params);
+
+ /* If no error, wait for erase to finish */
+ if (ERROR_OK == retval)
+ retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[0]);
+
+ /* Regardless of errors, try to close down algo */
+ (void)cc26xx_quit(bank);
+
+ return retval;
+}
+
+static int cc26xx_protect(struct flash_bank *bank, int set, int first,
+ int last)
+{
+ return ERROR_OK;
+}
+
+static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct target *target = bank->target;
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+ struct cc26xx_algo_params algo_params[2];
+ uint32_t size = 0;
+ long long start_ms;
+ long long elapsed_ms;
+ uint32_t address;
+
+ uint32_t index;
+ int retval;
+
+ if (TARGET_HALTED != target->state) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ retval = cc26xx_init(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Initialize algorithm parameters to default values */
+ buf_set_u32(algo_params[0].command, 0, 32, CC26XX_CMD_PROGRAM);
+ buf_set_u32(algo_params[1].command, 0, 32, CC26XX_CMD_PROGRAM);
+
+ /* Write requested data, ping-ponging between two buffers */
+ index = 0;
+ start_ms = timeval_ms();
+ address = bank->base + offset;
+ while (count > 0) {
+
+ if (count > cc26xx_bank->sector_length)
+ size = cc26xx_bank->sector_length;
+ else
+ size = count;
+
+ /* Put next block of data to flash into buffer */
+ retval = target_write_buffer(target, cc26xx_bank->buffer_addr[index],
+ size, buffer);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("Unable to write data to target memory");
+ break;
+ }
+
+ /* Update algo parameters for next block */
+ buf_set_u32(algo_params[index].address, 0, 32, address);
+ buf_set_u32(algo_params[index].length, 0, 32, size);
+ buf_set_u32(algo_params[index].status, 0, 32, CC26XX_BUFFER_FULL);
+
+ /* Issue flash helper algorithm parameters for block write */
+ retval = target_write_buffer(target, cc26xx_bank->params_addr[index],
+ sizeof(algo_params[index]), (uint8_t *)&algo_params[index]);
+ if (ERROR_OK != retval)
+ break;
+
+ /* Wait for next ping pong buffer to be ready */
+ index ^= 1;
+ retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[index]);
+ if (ERROR_OK != retval)
+ break;
+
+ count -= size;
+ buffer += size;
+ address += size;
+
+ elapsed_ms = timeval_ms() - start_ms;
+ if (elapsed_ms > 500)
+ keep_alive();
+ }
+
+ /* If no error yet, wait for last buffer to finish */
+ if (ERROR_OK == retval) {
+ index ^= 1;
+ retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[index]);
+ }
+
+ /* Regardless of errors, try to close down algo */
+ (void)cc26xx_quit(bank);
+
+ return retval;
+}
+
+static int cc26xx_probe(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+
+ uint32_t sector_length;
+ uint32_t value;
+ int num_sectors;
+ int max_sectors;
+
+ int retval;
+
+ retval = target_read_u32(target, FCFG1_ICEPICK_ID, &value);
+ if (ERROR_OK != retval)
+ return retval;
+ cc26xx_bank->icepick_id = value;
+
+ retval = target_read_u32(target, FCFG1_USER_ID, &value);
+ if (ERROR_OK != retval)
+ return retval;
+ cc26xx_bank->user_id = value;
+
+ cc26xx_bank->device_type = cc26xx_device_type(cc26xx_bank->icepick_id,
+ cc26xx_bank->user_id);
+
+ sector_length = cc26xx_sector_length(cc26xx_bank->icepick_id);
+
+ /* Set up appropriate flash helper algorithm */
+ switch (cc26xx_bank->icepick_id & ICEPICK_ID_MASK) {
+ case CC26X0_ICEPICK_ID:
+ case CC26X1_ICEPICK_ID:
+ case CC13X0_ICEPICK_ID:
+ /* Chameleon family device */
+ cc26xx_bank->algo_code = cc26x0_algo;
+ cc26xx_bank->algo_size = sizeof(cc26x0_algo);
+ cc26xx_bank->algo_working_size = CC26X0_WORKING_SIZE;
+ cc26xx_bank->buffer_addr[0] = CC26X0_ALGO_BUFFER_0;
+ cc26xx_bank->buffer_addr[1] = CC26X0_ALGO_BUFFER_1;
+ cc26xx_bank->params_addr[0] = CC26X0_ALGO_PARAMS_0;
+ cc26xx_bank->params_addr[1] = CC26X0_ALGO_PARAMS_1;
+ max_sectors = CC26X0_MAX_SECTORS;
+ break;
+ case CC13X2_CC26X2_ICEPICK_ID:
+ default:
+ /* Agama family device */
+ cc26xx_bank->algo_code = cc26x2_algo;
+ cc26xx_bank->algo_size = sizeof(cc26x2_algo);
+ cc26xx_bank->algo_working_size = CC26X2_WORKING_SIZE;
+ cc26xx_bank->buffer_addr[0] = CC26X2_ALGO_BUFFER_0;
+ cc26xx_bank->buffer_addr[1] = CC26X2_ALGO_BUFFER_1;
+ cc26xx_bank->params_addr[0] = CC26X2_ALGO_PARAMS_0;
+ cc26xx_bank->params_addr[1] = CC26X2_ALGO_PARAMS_1;
+ max_sectors = CC26X2_MAX_SECTORS;
+ break;
+ }
+
+ retval = target_read_u32(target, CC26XX_FLASH_SIZE_INFO, &value);
+ if (ERROR_OK != retval)
+ return retval;
+ num_sectors = value & 0xff;
+ if (num_sectors > max_sectors)
+ num_sectors = max_sectors;
+
+ bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
+ if (NULL == bank->sectors)
+ return ERROR_FAIL;
+
+ bank->base = CC26XX_FLASH_BASE_ADDR;
+ bank->num_sectors = num_sectors;
+ bank->size = num_sectors * sector_length;
+ bank->write_start_alignment = 0;
+ bank->write_end_alignment = 0;
+ cc26xx_bank->sector_length = sector_length;
+
+ for (int i = 0; i < num_sectors; i++) {
+ bank->sectors[i].offset = i * sector_length;
+ bank->sectors[i].size = sector_length;
+ bank->sectors[i].is_erased = -1;
+ bank->sectors[i].is_protected = 0;
+ }
+
+ /* We've successfully determined the stats on the flash bank */
+ cc26xx_bank->probed = true;
+
+ /* If we fall through to here, then all went well */
+
+ return ERROR_OK;
+}
+
+static int cc26xx_auto_probe(struct flash_bank *bank)
+{
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+
+ int retval = ERROR_OK;
+
+ if (bank->bank_number != 0) {
+ /* Invalid bank number somehow */
+ return ERROR_FAIL;
+ }
+
+ if (!cc26xx_bank->probed)
+ retval = cc26xx_probe(bank);
+
+ return retval;
+}
+
+static int cc26xx_protect_check(struct flash_bank *bank)
+{
+ return ERROR_OK;
+}
+
+static int cc26xx_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+ int printed = 0;
+ const char *device;
+
+ switch (cc26xx_bank->device_type) {
+ case CC26X0_TYPE:
+ device = "CC26x0";
+ break;
+ case CC26X1_TYPE:
+ device = "CC26x1";
+ break;
+ case CC13X0_TYPE:
+ device = "CC13x0";
+ break;
+ case CC13X2_TYPE:
+ device = "CC13x2";
+ break;
+ case CC26X2_TYPE:
+ device = "CC26x2";
+ break;
+ case CC26XX_NO_TYPE:
+ default:
+ device = "Unrecognized";
+ break;
+ }
+
+ printed = snprintf(buf, buf_size,
+ "%s device: ICEPick ID 0x%08x, USER ID 0x%08x\n",
+ device, cc26xx_bank->icepick_id, cc26xx_bank->user_id);
+
+ if (printed >= buf_size)
+ return ERROR_BUF_TOO_SMALL;
+
+ return ERROR_OK;
+}
+
+struct flash_driver cc26xx_flash = {
+ .name = "cc26xx",
+ .flash_bank_command = cc26xx_flash_bank_command,
+ .erase = cc26xx_erase,
+ .protect = cc26xx_protect,
+ .write = cc26xx_write,
+ .read = default_flash_read,
+ .probe = cc26xx_probe,
+ .auto_probe = cc26xx_auto_probe,
+ .erase_check = default_flash_blank_check,
+ .protect_check = cc26xx_protect_check,
+ .info = cc26xx_info,
+ .free_driver_priv = default_flash_free_driver_priv,
+};
diff --git a/src/flash/nor/cc26xx.h b/src/flash/nor/cc26xx.h
new file mode 100644
index 0000000..51a09f1
--- /dev/null
+++ b/src/flash/nor/cc26xx.h
@@ -0,0 +1,101 @@
+/***************************************************************************
+ * Copyright (C) 2017 by Texas Instruments, Inc. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef OPENOCD_FLASH_NOR_CC26XX_H
+#define OPENOCD_FLASH_NOR_CC26XX_H
+
+/* Addresses of FCFG1 registers to access ICEPick Device ID and User ID */
+#define FCFG1_ICEPICK_ID 0x50001318
+#define FCFG1_USER_ID 0x50001294
+
+/* ICEPick device ID mask and values */
+#define ICEPICK_ID_MASK 0x0fffffff
+#define ICEPICK_REV_MASK 0xf0000000
+#define CC26X0_ICEPICK_ID 0x0b99a02f
+#define CC26X1_ICEPICK_ID 0x0b9bd02f
+#define CC13X0_ICEPICK_ID 0x0b9be02f
+#define CC13X2_CC26X2_ICEPICK_ID 0x0bb4102f
+
+/* User ID mask for Agama CC13x2 vs CC26x2 */
+#define USER_ID_CC13_MASK 0x00800000
+
+/* Common CC26xx/CC13xx flash and memory parameters */
+#define CC26XX_FLASH_BASE_ADDR 0x00000000
+#define CC26XX_FLASH_SIZE_INFO 0x4003002c
+#define CC26XX_SRAM_SIZE_INFO 0x40082250
+#define CC26XX_ALGO_BASE_ADDRESS 0x20000000
+
+/* Chameleon CC26x0/CC13x0 specific parameters */
+#define CC26X0_MAX_SECTORS 32
+#define CC26X0_SECTOR_LENGTH 0x1000
+#define CC26X0_ALGO_BUFFER_0 0x20001c00
+#define CC26X0_ALGO_BUFFER_1 0x20002c00
+#define CC26X0_ALGO_PARAMS_0 0x20001bd8
+#define CC26X0_ALGO_PARAMS_1 0x20001bec
+#define CC26X0_WORKING_SIZE (CC26X0_ALGO_BUFFER_1 + CC26X0_SECTOR_LENGTH - \
+ CC26XX_ALGO_BASE_ADDRESS)
+
+/* Agama CC26x2/CC13x2 specific parameters */
+#define CC26X2_MAX_SECTORS 128
+#define CC26X2_SECTOR_LENGTH 0x2000
+#define CC26X2_ALGO_BUFFER_0 0x20002000
+#define CC26X2_ALGO_BUFFER_1 0x20004000
+#define CC26X2_ALGO_PARAMS_0 0x20001fd8
+#define CC26X2_ALGO_PARAMS_1 0x20001fec
+#define CC26X2_WORKING_SIZE (CC26X2_ALGO_BUFFER_1 + CC26X2_SECTOR_LENGTH - \
+ CC26XX_ALGO_BASE_ADDRESS)
+
+/* CC26xx flash helper algorithm buffer flags */
+#define CC26XX_BUFFER_EMPTY 0x00000000
+#define CC26XX_BUFFER_FULL 0xffffffff
+
+/* CC26XX flash helper algorithm commands */
+#define CC26XX_CMD_NO_ACTION 0
+#define CC26XX_CMD_ERASE_ALL 1
+#define CC26XX_CMD_PROGRAM 2
+#define CC26XX_CMD_ERASE_AND_PROGRAM 3
+#define CC26XX_CMD_ERASE_AND_PROGRAM_WITH_RETAIN 4
+#define CC26XX_CMD_ERASE_SECTORS 5
+
+/* CC26xx and CC13xx device types */
+#define CC26XX_NO_TYPE 0 /* Device type not determined yet */
+#define CC26X0_TYPE 1 /* CC26x0 Chameleon device */
+#define CC26X1_TYPE 2 /* CC26x1 Chameleon device */
+#define CC26X2_TYPE 3 /* CC26x2 Agama device */
+#define CC13X0_TYPE 4 /* CC13x0 Chameleon device */
+#define CC13X2_TYPE 5 /* CC13x2 Agama device */
+
+/* Flash helper algorithm parameter block struct */
+#define CC26XX_STATUS_OFFSET 0x0c
+struct cc26xx_algo_params {
+ uint8_t address[4];
+ uint8_t length[4];
+ uint8_t command[4];
+ uint8_t status[4];
+};
+
+/* Flash helper algorithm for CC26x0 Chameleon targets */
+const uint8_t cc26x0_algo[] = {
+#include "../../../contrib/loaders/flash/cc26xx/cc26x0_algo.inc"
+};
+
+/* Flash helper algorithm for CC26x2 Agama targets */
+const uint8_t cc26x2_algo[] = {
+#include "../../../contrib/loaders/flash/cc26xx/cc26x2_algo.inc"
+};
+
+#endif /* OPENOCD_FLASH_NOR_CC26XX_H */
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index a094c20..2b3146d 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -33,6 +33,7 @@ extern struct flash_driver atsamv_flash;
extern struct flash_driver avr_flash;
extern struct flash_driver bluenrgx_flash;
extern struct flash_driver cc3220sf_flash;
+extern struct flash_driver cc26xx_flash;
extern struct flash_driver cfi_flash;
extern struct flash_driver dsp5680xx_flash;
extern struct flash_driver efm32_flash;
@@ -50,6 +51,7 @@ extern struct flash_driver lpc2900_flash;
extern struct flash_driver lpcspifi_flash;
extern struct flash_driver mdr_flash;
extern struct flash_driver mrvlqspi_flash;
+extern struct flash_driver msp432_flash;
extern struct flash_driver niietcm4_flash;
extern struct flash_driver nrf5_flash;
extern struct flash_driver nrf51_flash;
@@ -96,6 +98,7 @@ static struct flash_driver *flash_drivers[] = {
&avr_flash,
&bluenrgx_flash,
&cc3220sf_flash,
+ &cc26xx_flash,
&cfi_flash,
&dsp5680xx_flash,
&efm32_flash,
@@ -113,6 +116,7 @@ static struct flash_driver *flash_drivers[] = {
&lpcspifi_flash,
&mdr_flash,
&mrvlqspi_flash,
+ &msp432_flash,
&niietcm4_flash,
&nrf5_flash,
&nrf51_flash,
diff --git a/src/flash/nor/msp432.c b/src/flash/nor/msp432.c
new file mode 100644
index 0000000..5caa052
--- /dev/null
+++ b/src/flash/nor/msp432.c
@@ -0,0 +1,1103 @@
+/***************************************************************************
+ * Copyright (C) 2018 by Texas Instruments, Inc. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include "msp432.h"
+#include <helper/binarybuffer.h>
+#include <helper/time_support.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+#include <target/image.h>
+
+/* MSP432P4 hardware registers */
+#define P4_FLASH_MAIN_SIZE_REG 0xE0043020
+#define P4_FLASH_INFO_SIZE_REG 0xE0043024
+#define P4_DEVICE_ID_REG 0x0020100C
+#define P4_HARDWARE_REV_REG 0x00201010
+
+/* MSP432E4 hardware registers */
+#define E4_DID0_REG 0x400FE000
+#define E4_DID1_REG 0x400FE004
+
+#define FLASH_TIMEOUT 8000
+
+#define SUPPORT_MESSAGE \
+ "Your pre-production MSP432P401x silicon is not fully supported\n" \
+ "You can find more information at www.ti.com/product/MSP432P401R"
+
+struct msp432_bank {
+ uint32_t device_id;
+ uint32_t hardware_rev;
+ int family_type;
+ int device_type;
+ uint32_t sector_length;
+ bool probed[2];
+ bool unlock_bsl;
+ struct working_area *working_area;
+ struct armv7m_algorithm armv7m_info;
+};
+
+static int msp432_auto_probe(struct flash_bank *bank);
+
+static int msp432_device_type(uint32_t family_type, uint32_t device_id,
+ uint32_t hardware_rev)
+{
+ int device_type = MSP432_NO_TYPE;
+
+ if (MSP432E4 == family_type) {
+ /* MSP432E4 device family */
+
+ if (device_id == 0x180C0002) {
+ if (hardware_rev == 0x102DC06E) {
+ /* The 01Y variant */
+ device_type = MSP432E401Y;
+ } else if (hardware_rev == 0x1032E076) {
+ /* The 11Y variant */
+ device_type = MSP432E411Y;
+ } else {
+ /* Reasonable guess that this is a new variant */
+ device_type = MSP432E4X_GUESS;
+ }
+ } else {
+ /* Wild guess that this is an MSP432E4 */
+ device_type = MSP432E4X_GUESS;
+ }
+ } else {
+ /* MSP432P4 device family */
+
+ /* Examine the device ID and hardware revision to get the device type */
+ switch (device_id) {
+ case 0xA000:
+ case 0xA001:
+ case 0xA002:
+ case 0xA003:
+ case 0xA004:
+ case 0xA005:
+ /* Device is definitely MSP432P401x, check hardware revision */
+ if (hardware_rev == 0x41 || hardware_rev == 0x42) {
+ /* Rev A or B of the silicon has been deprecated */
+ device_type = MSP432P401X_DEPR;
+ } else if (hardware_rev >= 0x43 && hardware_rev <= 0x49) {
+ /* Current and future revisions of the MSP432P401x device */
+ device_type = MSP432P401X;
+ } else {
+ /* Unknown or unanticipated hardware revision */
+ device_type = MSP432P401X_GUESS;
+ }
+ break;
+ case 0xA010:
+ case 0xA012:
+ case 0xA016:
+ case 0xA019:
+ case 0xA01F:
+ case 0xA020:
+ case 0xA022:
+ case 0xA026:
+ case 0xA029:
+ case 0xA02F:
+ /* Device is definitely MSP432P411x, check hardware revision */
+ if (hardware_rev >= 0x41 && hardware_rev <= 0x49) {
+ /* Current and future revisions of the MSP432P411x device */
+ device_type = MSP432P411X;
+ } else {
+ /* Unknown or unanticipated hardware revision */
+ device_type = MSP432P411X_GUESS;
+ }
+ break;
+ case 0xFFFF:
+ /* Device is very early silicon that has been deprecated */
+ device_type = MSP432P401X_DEPR;
+ break;
+ default:
+ if (device_id < 0xA010) {
+ /* Wild guess that this is an MSP432P401x */
+ device_type = MSP432P401X_GUESS;
+ } else {
+ /* Reasonable guess that this is a new variant */
+ device_type = MSP432P411X_GUESS;
+ }
+ break;
+ }
+ }
+
+ return device_type;
+}
+
+static const char *msp432_return_text(uint32_t return_code)
+{
+ switch (return_code) {
+ case FLASH_BUSY:
+ return "FLASH_BUSY";
+ case FLASH_SUCCESS:
+ return "FLASH_SUCCESS";
+ case FLASH_ERROR:
+ return "FLASH_ERROR";
+ case FLASH_TIMEOUT_ERROR:
+ return "FLASH_TIMEOUT_ERROR";
+ case FLASH_VERIFY_ERROR:
+ return "FLASH_VERIFY_WRONG";
+ case FLASH_WRONG_COMMAND:
+ return "FLASH_WRONG_COMMAND";
+ case FLASH_POWER_ERROR:
+ return "FLASH_POWER_ERROR";
+ default:
+ return "UNDEFINED_RETURN_CODE";
+ }
+}
+
+static void msp432_init_params(struct msp432_algo_params *algo_params)
+{
+ buf_set_u32(algo_params->flash_command, 0, 32, FLASH_NO_COMMAND);
+ buf_set_u32(algo_params->return_code, 0, 32, 0);
+ buf_set_u32(algo_params->_reserved0, 0, 32, 0);
+ buf_set_u32(algo_params->address, 0, 32, 0);
+ buf_set_u32(algo_params->length, 0, 32, 0);
+ buf_set_u32(algo_params->buffer1_status, 0, 32, BUFFER_INACTIVE);
+ buf_set_u32(algo_params->buffer2_status, 0, 32, BUFFER_INACTIVE);
+ buf_set_u32(algo_params->erase_param, 0, 32, FLASH_ERASE_MAIN);
+ buf_set_u32(algo_params->unlock_bsl, 0, 32, FLASH_LOCK_BSL);
+}
+
+static int msp432_exec_cmd(struct target *target, struct msp432_algo_params
+ *algo_params, uint32_t command)
+{
+ int retval;
+
+ /* Make sure the given params do not include the command */
+ buf_set_u32(algo_params->flash_command, 0, 32, FLASH_NO_COMMAND);
+ buf_set_u32(algo_params->return_code, 0, 32, 0);
+ buf_set_u32(algo_params->buffer1_status, 0, 32, BUFFER_INACTIVE);
+ buf_set_u32(algo_params->buffer2_status, 0, 32, BUFFER_INACTIVE);
+
+ /* Write out parameters to target memory */
+ retval = target_write_buffer(target, ALGO_PARAMS_BASE_ADDR,
+ sizeof(struct msp432_algo_params), (uint8_t *)algo_params);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Write out command to target memory */
+ retval = target_write_buffer(target, ALGO_FLASH_COMMAND_ADDR,
+ sizeof(command), (uint8_t *)&command);
+
+ return retval;
+}
+
+static int msp432_wait_return_code(struct target *target)
+{
+ uint32_t return_code = 0;
+ long long start_ms;
+ long long elapsed_ms;
+
+ int retval = ERROR_OK;
+
+ start_ms = timeval_ms();
+ while ((0 == return_code) || (FLASH_BUSY == return_code)) {
+ retval = target_read_buffer(target, ALGO_RETURN_CODE_ADDR,
+ sizeof(return_code), (uint8_t *)&return_code);
+ if (ERROR_OK != retval)
+ return retval;
+
+ elapsed_ms = timeval_ms() - start_ms;
+ if (elapsed_ms > 500)
+ keep_alive();
+ if (elapsed_ms > FLASH_TIMEOUT)
+ break;
+ };
+
+ if (FLASH_SUCCESS != return_code) {
+ LOG_ERROR("msp432: Flash operation failed: %s",
+ msp432_return_text(return_code));
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static int msp432_wait_inactive(struct target *target, uint32_t buffer)
+{
+ uint32_t status_code = BUFFER_ACTIVE;
+ uint32_t status_addr;
+ long long start_ms;
+ long long elapsed_ms;
+
+ int retval;
+
+ switch (buffer) {
+ case 1: /* Buffer 1 */
+ status_addr = ALGO_BUFFER1_STATUS_ADDR;
+ break;
+ case 2: /* Buffer 2 */
+ status_addr = ALGO_BUFFER2_STATUS_ADDR;
+ break;
+ default:
+ return ERROR_FAIL;
+ }
+
+ start_ms = timeval_ms();
+ while (BUFFER_INACTIVE != status_code) {
+ retval = target_read_buffer(target, status_addr, sizeof(status_code),
+ (uint8_t *)&status_code);
+ if (ERROR_OK != retval)
+ return retval;
+
+ elapsed_ms = timeval_ms() - start_ms;
+ if (elapsed_ms > 500)
+ keep_alive();
+ if (elapsed_ms > FLASH_TIMEOUT)
+ break;
+ };
+
+ if (BUFFER_INACTIVE != status_code) {
+ LOG_ERROR(
+ "msp432: Flash operation failed: buffer not written to flash");
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static int msp432_init(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct msp432_bank *msp432_bank = bank->driver_priv;
+ struct msp432_algo_params algo_params;
+ struct reg_param reg_params[1];
+
+ const uint8_t *loader_code;
+ uint32_t loader_size;
+ uint32_t algo_entry_addr;
+ int retval;
+
+ /* Make sure we've probed the flash to get the device and size */
+ retval = msp432_auto_probe(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Choose appropriate flash helper algorithm */
+ switch (msp432_bank->device_type) {
+ case MSP432P401X:
+ case MSP432P401X_DEPR:
+ case MSP432P401X_GUESS:
+ default:
+ loader_code = msp432p401x_algo;
+ loader_size = sizeof(msp432p401x_algo);
+ algo_entry_addr = P4_ALGO_ENTRY_ADDR;
+ break;
+ case MSP432P411X:
+ case MSP432P411X_GUESS:
+ loader_code = msp432p411x_algo;
+ loader_size = sizeof(msp432p411x_algo);
+ algo_entry_addr = P4_ALGO_ENTRY_ADDR;
+ break;
+ case MSP432E401Y:
+ case MSP432E411Y:
+ case MSP432E4X_GUESS:
+ loader_code = msp432e4x_algo;
+ loader_size = sizeof(msp432e4x_algo);
+ algo_entry_addr = E4_ALGO_ENTRY_ADDR;
+ break;
+ }
+
+ /* Issue warnings if this is a device we may not be able to flash */
+ if (MSP432P401X_GUESS == msp432_bank->device_type ||
+ MSP432P411X_GUESS == msp432_bank->device_type) {
+ /* Explicit device type check failed. Report this. */
+ LOG_WARNING(
+ "msp432: Unrecognized MSP432P4 Device ID and Hardware "
+ "Rev (%04X, %02X)", msp432_bank->device_id,
+ msp432_bank->hardware_rev);
+ } else if (MSP432P401X_DEPR == msp432_bank->device_type) {
+ LOG_WARNING(
+ "msp432: MSP432P401x pre-production device (deprecated "
+ "silicon)\n" SUPPORT_MESSAGE);
+ } else if (MSP432E4X_GUESS == msp432_bank->device_type) {
+ /* Explicit device type check failed. Report this. */
+ LOG_WARNING(
+ "msp432: Unrecognized MSP432E4 DID0 and DID1 values "
+ "(%08X, %08X)", msp432_bank->device_id,
+ msp432_bank->hardware_rev);
+ }
+
+ /* Check for working area to use for flash helper algorithm */
+ if (NULL != msp432_bank->working_area)
+ target_free_working_area(target, msp432_bank->working_area);
+ retval = target_alloc_working_area(target, ALGO_WORKING_SIZE,
+ &msp432_bank->working_area);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Confirm the defined working address is the area we need to use */
+ if (ALGO_BASE_ADDR != msp432_bank->working_area->address)
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+
+ /* Write flash helper algorithm into target memory */
+ retval = target_write_buffer(target, ALGO_BASE_ADDR, loader_size,
+ loader_code);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Initialize the ARMv7 specific info to run the algorithm */
+ msp432_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+ msp432_bank->armv7m_info.core_mode = ARM_MODE_THREAD;
+
+ /* Initialize algorithm parameters to default values */
+ msp432_init_params(&algo_params);
+
+ /* Write out parameters to target memory */
+ retval = target_write_buffer(target, ALGO_PARAMS_BASE_ADDR,
+ sizeof(algo_params), (uint8_t *)&algo_params);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Initialize stack pointer for flash helper algorithm */
+ init_reg_param(&reg_params[0], "sp", 32, PARAM_OUT);
+ buf_set_u32(reg_params[0].value, 0, 32, ALGO_STACK_POINTER_ADDR);
+
+ /* Begin executing the flash helper algorithm */
+ retval = target_start_algorithm(target, 0, 0, 1, reg_params,
+ algo_entry_addr, 0, &msp432_bank->armv7m_info);
+ destroy_reg_param(&reg_params[0]);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("msp432: Failed to start flash helper algorithm");
+ return retval;
+ }
+
+ /*
+ * At this point, the algorithm is running on the target and
+ * ready to receive commands and data to flash the target
+ */
+
+ /* Issue the init command to the flash helper algorithm */
+ retval = msp432_exec_cmd(target, &algo_params, FLASH_INIT);
+ if (ERROR_OK != retval)
+ return retval;
+
+ retval = msp432_wait_return_code(target);
+
+ return retval;
+}
+
+static int msp432_quit(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct msp432_bank *msp432_bank = bank->driver_priv;
+ struct msp432_algo_params algo_params;
+
+ int retval;
+
+ /* Initialize algorithm parameters to default values */
+ msp432_init_params(&algo_params);
+
+ /* Issue the exit command to the flash helper algorithm */
+ retval = msp432_exec_cmd(target, &algo_params, FLASH_EXIT);
+ if (ERROR_OK != retval)
+ return retval;
+
+ (void)msp432_wait_return_code(target);
+
+ /* Regardless of the return code, attempt to halt the target */
+ (void)target_halt(target);
+
+ /* Now confirm target halted and clean up from flash helper algorithm */
+ retval = target_wait_algorithm(target, 0, NULL, 0, NULL, 0, FLASH_TIMEOUT,
+ &msp432_bank->armv7m_info);
+
+ target_free_working_area(target, msp432_bank->working_area);
+ msp432_bank->working_area = NULL;
+
+ return retval;
+}
+
+static int msp432_mass_erase(struct flash_bank *bank, bool all)
+{
+ struct target *target = bank->target;
+ struct msp432_bank *msp432_bank = bank->driver_priv;
+ struct msp432_algo_params algo_params;
+
+ int retval;
+
+ if (TARGET_HALTED != target->state) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ retval = msp432_init(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Initialize algorithm parameters to default values */
+ msp432_init_params(&algo_params);
+ if (all) {
+ buf_set_u32(algo_params.erase_param, 0, 32,
+ FLASH_ERASE_MAIN | FLASH_ERASE_INFO);
+ if (msp432_bank->unlock_bsl)
+ buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL);
+ }
+
+ /* Issue the mass erase command to the flash helper algorithm */
+ retval = msp432_exec_cmd(target, &algo_params, FLASH_MASS_ERASE);
+ if (ERROR_OK != retval) {
+ (void)msp432_quit(bank);
+ return retval;
+ }
+
+ retval = msp432_wait_return_code(target);
+ if (ERROR_OK != retval) {
+ (void)msp432_quit(bank);
+ return retval;
+ }
+
+ retval = msp432_quit(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ return retval;
+}
+
+COMMAND_HANDLER(msp432_mass_erase_command)
+{
+ struct flash_bank *bank;
+ struct msp432_bank *msp432_bank;
+ bool all;
+ int retval;
+
+ if (0 == CMD_ARGC) {
+ all = false;
+ } else if (1 == CMD_ARGC) {
+ /* Check argument for how much to erase */
+ if (0 == strcmp(CMD_ARGV[0], "main"))
+ all = false;
+ else if (0 == strcmp(CMD_ARGV[0], "all"))
+ all = true;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ } else {
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ retval = get_flash_bank_by_num(0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ msp432_bank = bank->driver_priv;
+
+ if (MSP432E4 == msp432_bank->family_type) {
+ /* MSP432E4 does not have main vs info regions, ignore "all" */
+ all = false;
+ }
+
+ retval = msp432_mass_erase(bank, all);
+ if (ERROR_OK != retval)
+ return retval;
+
+ if (MSP432E4 == msp432_bank->family_type) {
+ /* MSP432E4 does not have main vs info regions */
+ LOG_INFO("msp432: Mass erase of flash is complete");
+ } else {
+ LOG_INFO("msp432: Mass erase of %s is complete",
+ all ? "main + info flash" : "main flash");
+ }
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(msp432_bsl_command)
+{
+ struct flash_bank *bank;
+ struct msp432_bank *msp432_bank;
+ int retval;
+
+ if (1 < CMD_ARGC)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ retval = get_flash_bank_by_num(0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ msp432_bank = bank->driver_priv;
+
+ if (MSP432E4 == msp432_bank->family_type) {
+ LOG_WARNING("msp432: MSP432E4 does not have a BSL region");
+ return ERROR_OK;
+ }
+
+ if (1 == CMD_ARGC) {
+ if (0 == strcmp(CMD_ARGV[0], "lock"))
+ msp432_bank->unlock_bsl = false;
+ else if (0 == strcmp(CMD_ARGV[0], "unlock"))
+ msp432_bank->unlock_bsl = true;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ LOG_INFO("msp432: BSL flash region is currently %slocked",
+ msp432_bank->unlock_bsl ? "un" : "");
+
+ return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(msp432_flash_bank_command)
+{
+ struct msp432_bank *msp432_bank;
+
+ if (CMD_ARGC < 6)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ msp432_bank = malloc(sizeof(struct msp432_bank));
+ if (NULL == msp432_bank)
+ return ERROR_FAIL;
+
+ /* Initialize private flash information */
+ msp432_bank->device_id = 0;
+ msp432_bank->hardware_rev = 0;
+ msp432_bank->family_type = MSP432_NO_FAMILY;
+ msp432_bank->device_type = MSP432_NO_TYPE;
+ msp432_bank->sector_length = 0x1000;
+ msp432_bank->probed[0] = false;
+ msp432_bank->probed[1] = false;
+ msp432_bank->unlock_bsl = false;
+ msp432_bank->working_area = NULL;
+
+ /* Finish initialization of bank 0 (main flash) */
+ bank->driver_priv = msp432_bank;
+ bank->next = NULL;
+
+ return ERROR_OK;
+}
+
+static int msp432_erase(struct flash_bank *bank, int first, int last)
+{
+ struct target *target = bank->target;
+ struct msp432_bank *msp432_bank = bank->driver_priv;
+ struct msp432_algo_params algo_params;
+
+ int retval;
+
+ if (TARGET_HALTED != target->state) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* Do a mass erase if user requested all sectors of main flash */
+ if ((0 == bank->bank_number) && (first == 0) &&
+ (last == (bank->num_sectors - 1))) {
+ /* Request mass erase of main flash */
+ return msp432_mass_erase(bank, false);
+ }
+
+ retval = msp432_init(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Initialize algorithm parameters to default values */
+ msp432_init_params(&algo_params);
+
+ /* Adjust params if this is the info bank */
+ if (1 == bank->bank_number) {
+ buf_set_u32(algo_params.erase_param, 0, 32, FLASH_ERASE_INFO);
+ /* And flag if BSL is unlocked */
+ if (msp432_bank->unlock_bsl)
+ buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL);
+ }
+
+ /* Erase requested sectors one by one */
+ for (int i = first; i <= last; i++) {
+
+ /* Skip TVL (read-only) sector of the info bank */
+ if (1 == bank->bank_number && 1 == i)
+ continue;
+
+ /* Skip BSL sectors of info bank if locked */
+ if (1 == bank->bank_number && (2 == i || 3 == i) &&
+ !msp432_bank->unlock_bsl)
+ continue;
+
+ /* Convert sector number to starting address of sector */
+ buf_set_u32(algo_params.address, 0, 32, bank->base +
+ (i * msp432_bank->sector_length));
+
+ /* Issue the sector erase command to the flash helper algorithm */
+ retval = msp432_exec_cmd(target, &algo_params, FLASH_SECTOR_ERASE);
+ if (ERROR_OK != retval) {
+ (void)msp432_quit(bank);
+ return retval;
+ }
+
+ retval = msp432_wait_return_code(target);
+ if (ERROR_OK != retval) {
+ (void)msp432_quit(bank);
+ return retval;
+ }
+ }
+
+ retval = msp432_quit(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ return retval;
+}
+
+static int msp432_protect(struct flash_bank *bank, int set, int first,
+ int last)
+{
+ return ERROR_OK;
+}
+
+static int msp432_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct target *target = bank->target;
+ struct msp432_bank *msp432_bank = bank->driver_priv;
+ struct msp432_algo_params algo_params;
+ uint32_t size;
+ uint32_t data_ready = BUFFER_DATA_READY;
+ long long start_ms;
+ long long elapsed_ms;
+
+ int retval;
+
+ if (TARGET_HALTED != target->state) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /*
+ * Block attempts to write to read-only sectors of flash
+ * The TVL region in sector 1 of the info flash is always read-only
+ * The BSL region in sectors 2 and 3 of the info flash may be unlocked
+ * The helper algorithm will hang on attempts to write to TVL
+ */
+ if (1 == bank->bank_number) {
+ /* Set read-only start to TVL sector */
+ uint32_t start = 0x1000;
+ /* Set read-only end after BSL region if locked */
+ uint32_t end = (msp432_bank->unlock_bsl) ? 0x2000 : 0x4000;
+ /* Check if request includes anything in read-only sectors */
+ if ((offset + count - 1) < start || offset >= end) {
+ /* The request includes no bytes in read-only sectors */
+ /* Fall out and process the request normally */
+ } else {
+ /* Send a request for anything before read-only sectors */
+ if (offset < start) {
+ uint32_t start_count = MIN(start - offset, count);
+ retval = msp432_write(bank, buffer, offset, start_count);
+ if (ERROR_OK != retval)
+ return retval;
+ }
+ /* Send a request for anything after read-only sectors */
+ if ((offset + count - 1) >= end) {
+ uint32_t skip = end - offset;
+ count -= skip;
+ offset += skip;
+ buffer += skip;
+ return msp432_write(bank, buffer, offset, count);
+ } else {
+ /* Request is entirely in read-only sectors */
+ return ERROR_OK;
+ }
+ }
+ }
+
+ retval = msp432_init(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Initialize algorithm parameters to default values */
+ msp432_init_params(&algo_params);
+
+ /* Set up parameters for requested flash write operation */
+ buf_set_u32(algo_params.address, 0, 32, bank->base + offset);
+ buf_set_u32(algo_params.length, 0, 32, count);
+
+ /* Check if this is the info bank */
+ if (1 == bank->bank_number) {
+ /* And flag if BSL is unlocked */
+ if (msp432_bank->unlock_bsl)
+ buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL);
+ }
+
+ /* Set up flash helper algorithm to continuous flash mode */
+ retval = msp432_exec_cmd(target, &algo_params, FLASH_CONTINUOUS);
+ if (ERROR_OK != retval) {
+ (void)msp432_quit(bank);
+ return retval;
+ }
+
+ /* Write requested data, one buffer at a time */
+ start_ms = timeval_ms();
+ while (count > 0) {
+
+ if (count > ALGO_BUFFER_SIZE)
+ size = ALGO_BUFFER_SIZE;
+ else
+ size = count;
+
+ /* Put next block of data to flash into buffer */
+ retval = target_write_buffer(target, ALGO_BUFFER1_ADDR, size, buffer);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("Unable to write data to target memory");
+ (void)msp432_quit(bank);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ /* Signal the flash helper algorithm that data is ready to flash */
+ retval = target_write_buffer(target, ALGO_BUFFER1_STATUS_ADDR,
+ sizeof(data_ready), (uint8_t *)&data_ready);
+ if (ERROR_OK != retval) {
+ (void)msp432_quit(bank);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ retval = msp432_wait_inactive(target, 1);
+ if (ERROR_OK != retval) {
+ (void)msp432_quit(bank);
+ return retval;
+ }
+
+ count -= size;
+ buffer += size;
+
+ elapsed_ms = timeval_ms() - start_ms;
+ if (elapsed_ms > 500)
+ keep_alive();
+ }
+
+ /* Confirm that the flash helper algorithm is finished */
+ retval = msp432_wait_return_code(target);
+ if (ERROR_OK != retval) {
+ (void)msp432_quit(bank);
+ return retval;
+ }
+
+ retval = msp432_quit(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ return retval;
+}
+
+static int msp432_probe(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct msp432_bank *msp432_bank = bank->driver_priv;
+
+ char *name;
+
+ uint32_t device_id;
+ uint32_t hardware_rev;
+
+ uint32_t base;
+ uint32_t sector_length;
+ uint32_t size;
+ int num_sectors;
+ int bank_id;
+
+ int retval;
+
+ bank_id = bank->bank_number;
+
+ /* Read the flash size register to determine this is a P4 or not */
+ /* MSP432P4s will return the size of flash. MSP432E4s will return zero */
+ retval = target_read_u32(target, P4_FLASH_MAIN_SIZE_REG, &size);
+ if (ERROR_OK != retval)
+ return retval;
+
+ if (0 == size) {
+ /* This is likely an MSP432E4 */
+ msp432_bank->family_type = MSP432E4;
+
+ retval = target_read_u32(target, E4_DID0_REG, &device_id);
+ if (ERROR_OK != retval)
+ return retval;
+
+ msp432_bank->device_id = device_id;
+
+ retval = target_read_u32(target, E4_DID1_REG, &hardware_rev);
+ if (ERROR_OK != retval)
+ return retval;
+
+ msp432_bank->hardware_rev = hardware_rev;
+ } else {
+ /* This is likely an MSP432P4 */
+ msp432_bank->family_type = MSP432P4;
+
+ retval = target_read_u32(target, P4_DEVICE_ID_REG, &device_id);
+ if (ERROR_OK != retval)
+ return retval;
+
+ msp432_bank->device_id = device_id & 0xFFFF;
+
+ retval = target_read_u32(target, P4_HARDWARE_REV_REG, &hardware_rev);
+ if (ERROR_OK != retval)
+ return retval;
+
+ msp432_bank->hardware_rev = hardware_rev & 0xFF;
+ }
+
+ msp432_bank->device_type = msp432_device_type(msp432_bank->family_type,
+ msp432_bank->device_id, msp432_bank->hardware_rev);
+
+ /* If not already allocated, create the info bank for MSP432P4 */
+ /* We could not determine it was needed until device was probed */
+ if (MSP432P4 == msp432_bank->family_type) {
+ /* If we've been given bank 1, then this was already done */
+ if (0 == bank_id) {
+ /* And only allocate it if it doesn't exist yet */
+ if (NULL == bank->next) {
+ struct flash_bank *info_bank;
+ info_bank = malloc(sizeof(struct flash_bank));
+ if (NULL == info_bank)
+ return ERROR_FAIL;
+
+ name = malloc(strlen(bank->name)+1);
+ if (NULL == name) {
+ free(info_bank);
+ return ERROR_FAIL;
+ }
+ strcpy(name, bank->name);
+
+ /* Initialize bank 1 (info region) */
+ info_bank->name = name;
+ info_bank->target = bank->target;
+ info_bank->driver = bank->driver;
+ info_bank->driver_priv = bank->driver_priv;
+ info_bank->bank_number = 1;
+ info_bank->base = 0x00200000;
+ info_bank->size = 0;
+ info_bank->chip_width = 0;
+ info_bank->bus_width = 0;
+ info_bank->erased_value = 0xff;
+ info_bank->default_padded_value = 0xff;
+ info_bank->write_start_alignment = 0;
+ info_bank->write_end_alignment = 0;
+ info_bank->minimal_write_gap = FLASH_WRITE_GAP_SECTOR;
+ info_bank->num_sectors = 0;
+ info_bank->sectors = NULL;
+ info_bank->num_prot_blocks = 0;
+ info_bank->prot_blocks = NULL;
+ info_bank->next = NULL;
+
+ /* Enable the new bank */
+ bank->next = info_bank;
+ }
+ }
+ }
+
+ if (MSP432P4 == msp432_bank->family_type) {
+ /* Set up MSP432P4 specific flash parameters */
+ if (0 == bank_id) {
+ retval = target_read_u32(target, P4_FLASH_MAIN_SIZE_REG, &size);
+ if (ERROR_OK != retval)
+ return retval;
+
+ base = P4_FLASH_MAIN_BASE;
+ sector_length = P4_SECTOR_LENGTH;
+ num_sectors = size / sector_length;
+ } else if (1 == bank_id) {
+ if (msp432_bank->device_type == MSP432P411X ||
+ msp432_bank->device_type == MSP432P411X_GUESS) {
+ /* MSP432P411x has an info size register, use that for size */
+ retval = target_read_u32(target, P4_FLASH_INFO_SIZE_REG, &size);
+ if (ERROR_OK != retval)
+ return retval;
+ } else {
+ /* All other MSP432P401x devices have fixed info region size */
+ size = 0x4000; /* 16 KB info region */
+ }
+ base = P4_FLASH_INFO_BASE;
+ sector_length = P4_SECTOR_LENGTH;
+ num_sectors = size / sector_length;
+ } else {
+ /* Invalid bank number somehow */
+ return ERROR_FAIL;
+ }
+ } else {
+ /* Set up MSP432E4 specific flash parameters */
+ base = E4_FLASH_BASE;
+ size = E4_FLASH_SIZE;
+ sector_length = E4_SECTOR_LENGTH;
+ num_sectors = size / sector_length;
+ }
+
+ if (NULL != bank->sectors) {
+ free(bank->sectors);
+ bank->sectors = NULL;
+ }
+
+ bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
+ if (NULL == bank->sectors)
+ return ERROR_FAIL;
+
+ bank->base = base;
+ bank->size = size;
+ bank->write_start_alignment = 0;
+ bank->write_end_alignment = 0;
+ bank->num_sectors = num_sectors;
+ msp432_bank->sector_length = sector_length;
+
+ for (int i = 0; i < num_sectors; i++) {
+ bank->sectors[i].offset = i * sector_length;
+ bank->sectors[i].size = sector_length;
+ bank->sectors[i].is_erased = -1;
+ bank->sectors[i].is_protected = 0;
+ }
+
+ /* We've successfully determined the stats on this flash bank */
+ msp432_bank->probed[bank_id] = true;
+
+ /* If we fall through to here, then all went well */
+
+ return ERROR_OK;
+}
+
+static int msp432_auto_probe(struct flash_bank *bank)
+{
+ struct msp432_bank *msp432_bank = bank->driver_priv;
+
+ int retval = ERROR_OK;
+
+ if (bank->bank_number < 0 || bank->bank_number > 1) {
+ /* Invalid bank number somehow */
+ return ERROR_FAIL;
+ }
+
+ if (!msp432_bank->probed[bank->bank_number])
+ retval = msp432_probe(bank);
+
+ return retval;
+}
+
+static int msp432_protect_check(struct flash_bank *bank)
+{
+ return ERROR_OK;
+}
+
+static int msp432_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+ struct msp432_bank *msp432_bank = bank->driver_priv;
+ int printed = 0;
+
+ switch (msp432_bank->device_type) {
+ case MSP432P401X_DEPR:
+ if (0xFFFF == msp432_bank->device_id) {
+ /* Very early pre-production silicon currently deprecated */
+ printed = snprintf(buf, buf_size,
+ "MSP432P401x pre-production device (deprecated silicon)\n"
+ SUPPORT_MESSAGE);
+ } else {
+ /* Revision A or B silicon, also deprecated */
+ printed = snprintf(buf, buf_size,
+ "MSP432P401x Device Rev %c (deprecated silicon)\n"
+ SUPPORT_MESSAGE, (char)msp432_bank->hardware_rev);
+ }
+ break;
+ case MSP432P401X:
+ printed = snprintf(buf, buf_size,
+ "MSP432P401x Device Rev %c\n",
+ (char)msp432_bank->hardware_rev);
+ break;
+ case MSP432P411X:
+ printed = snprintf(buf, buf_size,
+ "MSP432P411x Device Rev %c\n",
+ (char)msp432_bank->hardware_rev);
+ break;
+ case MSP432E401Y:
+ printed = snprintf(buf, buf_size, "MSP432E401Y Device\n");
+ break;
+ case MSP432E411Y:
+ printed = snprintf(buf, buf_size, "MSP432E411Y Device\n");
+ break;
+ case MSP432E4X_GUESS:
+ printed = snprintf(buf, buf_size,
+ "Unrecognized MSP432E4 DID0 and DID1 IDs (%08X, %08X)",
+ msp432_bank->device_id, msp432_bank->hardware_rev);
+ break;
+ case MSP432P401X_GUESS:
+ case MSP432P411X_GUESS:
+ default:
+ printed = snprintf(buf, buf_size,
+ "Unrecognized MSP432P4 Device ID and Hardware Rev (%04X, %02X)",
+ msp432_bank->device_id, msp432_bank->hardware_rev);
+ break;
+ }
+
+ buf_size -= printed;
+
+ if (0 > buf_size)
+ return ERROR_BUF_TOO_SMALL;
+
+ return ERROR_OK;
+}
+
+static void msp432_flash_free_driver_priv(struct flash_bank *bank)
+{
+ /* A single private struct is shared between main and info banks */
+ /* Only free it on the call for main bank (#0) */
+ if ((0 == bank->bank_number) && (NULL != bank->driver_priv))
+ free(bank->driver_priv);
+ /* Forget about the private struct on both main and info banks */
+ bank->driver_priv = NULL;
+}
+
+static const struct command_registration msp432_exec_command_handlers[] = {
+ {
+ .name = "mass_erase",
+ .handler = msp432_mass_erase_command,
+ .mode = COMMAND_EXEC,
+ .help = "Erase entire flash memory on device.",
+ .usage = "['main' | 'all']",
+ },
+ {
+ .name = "bsl",
+ .handler = msp432_bsl_command,
+ .mode = COMMAND_EXEC,
+ .help = "Allow BSL to be erased or written by flash commands.",
+ .usage = "['unlock' | 'lock']",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration msp432_command_handlers[] = {
+ {
+ .name = "msp432",
+ .mode = COMMAND_EXEC,
+ .help = "MSP432 flash command group",
+ .usage = "",
+ .chain = msp432_exec_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver msp432_flash = {
+ .name = "msp432",
+ .commands = msp432_command_handlers,
+ .flash_bank_command = msp432_flash_bank_command,
+ .erase = msp432_erase,
+ .protect = msp432_protect,
+ .write = msp432_write,
+ .read = default_flash_read,
+ .probe = msp432_probe,
+ .auto_probe = msp432_auto_probe,
+ .erase_check = default_flash_blank_check,
+ .protect_check = msp432_protect_check,
+ .info = msp432_info,
+ .free_driver_priv = msp432_flash_free_driver_priv,
+};
diff --git a/src/flash/nor/msp432.h b/src/flash/nor/msp432.h
new file mode 100644
index 0000000..ffefa8f
--- /dev/null
+++ b/src/flash/nor/msp432.h
@@ -0,0 +1,127 @@
+/***************************************************************************
+ * Copyright (C) 2018 by Texas Instruments, Inc. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef OPENOCD_FLASH_NOR_MSP432_H
+#define OPENOCD_FLASH_NOR_MSP432_H
+
+/* MSP432 family types */
+#define MSP432_NO_FAMILY 0 /* Family type not determined yet */
+#define MSP432E4 1 /* MSP432E4 family of devices */
+#define MSP432P4 2 /* MSP432P4 family of devices */
+
+/* MSP432 device types */
+#define MSP432_NO_TYPE 0 /* Device type not determined yet */
+#define MSP432P401X_DEPR 1 /* Early MSP432P401x offerings, now deprecated */
+#define MSP432P401X 2 /* MSP432P401x device, revision C or higher */
+#define MSP432P411X 3 /* MSP432P411x device, revision A or higher */
+#define MSP432P401X_GUESS 4 /* Assuming it's an MSP432P401x device */
+#define MSP432P411X_GUESS 5 /* Assuming it's an MSP432P411x device */
+#define MSP432E401Y 6 /* MSP432E401Y device */
+#define MSP432E411Y 7 /* MSP432E401Y device */
+#define MSP432E4X_GUESS 8 /* Assuming it's an MSP432E4x device */
+
+/* MSP432P4 flash parameters */
+#define P4_FLASH_MAIN_BASE 0x00000000
+#define P4_FLASH_INFO_BASE 0x00200000
+#define P4_SECTOR_LENGTH 0x1000
+#define P4_ALGO_ENTRY_ADDR 0x01000110
+
+/* MSP432E4 flash paramters */
+#define E4_FLASH_BASE 0x00000000
+#define E4_FLASH_SIZE 0x100000
+#define E4_SECTOR_LENGTH 0x4000
+#define E4_ALGO_ENTRY_ADDR 0x20000110
+
+/* Flash helper algorithm key addresses */
+#define ALGO_BASE_ADDR 0x20000000
+#define ALGO_BUFFER1_ADDR 0x20002000
+#define ALGO_BUFFER2_ADDR 0x20003000
+#define ALGO_PARAMS_BASE_ADDR 0x20000150
+#define ALGO_FLASH_COMMAND_ADDR 0x20000150
+#define ALGO_RETURN_CODE_ADDR 0x20000154
+#define ALGO_FLASH_DEST_ADDR 0x2000015c
+#define ALGO_FLASH_LENGTH_ADDR 0x20000160
+#define ALGO_BUFFER1_STATUS_ADDR 0x20000164
+#define ALGO_BUFFER2_STATUS_ADDR 0x20000168
+#define ALGO_ERASE_PARAM_ADDR 0x2000016c
+#define ALGO_UNLOCK_BSL_ADDR 0x20000170
+#define ALGO_STACK_POINTER_ADDR 0x20002000
+
+/* Flash helper algorithm key sizes */
+#define ALGO_BUFFER_SIZE 0x1000
+#define ALGO_WORKING_SIZE (ALGO_BUFFER2_ADDR + 0x1000 - ALGO_BASE_ADDR)
+
+/* Flash helper algorithm flash commands */
+#define FLASH_NO_COMMAND 0
+#define FLASH_MASS_ERASE 1
+#define FLASH_SECTOR_ERASE 2
+#define FLASH_PROGRAM 4
+#define FLASH_INIT 8
+#define FLASH_EXIT 16
+#define FLASH_CONTINUOUS 32
+
+/* Flash helper algorithm return codes */
+#define FLASH_BUSY 0x00000001
+#define FLASH_SUCCESS 0x00000ACE
+#define FLASH_ERROR 0x0000DEAD
+#define FLASH_TIMEOUT_ERROR 0xDEAD0000
+#define FLASH_VERIFY_ERROR 0xDEADDEAD
+#define FLASH_WRONG_COMMAND 0x00000BAD
+#define FLASH_POWER_ERROR 0x00DEAD00
+
+/* Flash helper algorithm buffer status values */
+#define BUFFER_INACTIVE 0x00
+#define BUFFER_ACTIVE 0x01
+#define BUFFER_DATA_READY 0x10
+
+/* Flash helper algorithm erase parameters */
+#define FLASH_ERASE_MAIN 0x01
+#define FLASH_ERASE_INFO 0x02
+
+/* Flash helper algorithm lock/unlock BSL options */
+#define FLASH_LOCK_BSL 0x00
+#define FLASH_UNLOCK_BSL 0x0b
+
+/* Flash helper algorithm parameter block struct */
+struct msp432_algo_params {
+ uint8_t flash_command[4];
+ uint8_t return_code[4];
+ uint8_t _reserved0[4];
+ uint8_t address[4];
+ uint8_t length[4];
+ uint8_t buffer1_status[4];
+ uint8_t buffer2_status[4];
+ uint8_t erase_param[4];
+ uint8_t unlock_bsl[4];
+};
+
+/* Flash helper algorithm for MSP432P401x targets */
+const uint8_t msp432p401x_algo[] = {
+#include "../../../contrib/loaders/flash/msp432/msp432p401x_algo.inc"
+};
+
+/* Flash helper algorithm for MSP432P411x targets */
+const uint8_t msp432p411x_algo[] = {
+#include "../../../contrib/loaders/flash/msp432/msp432p411x_algo.inc"
+};
+
+/* Flash helper algorithm for MSP432E4x targets */
+const uint8_t msp432e4x_algo[] = {
+#include "../../../contrib/loaders/flash/msp432/msp432e4x_algo.inc"
+};
+
+#endif /* OPENOCD_FLASH_NOR_MSP432_H */
diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c
index 31dd5aa..16459c7 100644
--- a/src/flash/nor/nrf5.c
+++ b/src/flash/nor/nrf5.c
@@ -108,6 +108,7 @@ enum nrf5_nvmc_config_bits {
struct nrf5_info {
uint32_t code_page_size;
+ uint32_t refcount;
struct {
bool probed;
@@ -204,6 +205,7 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = {
/* nRF52832 Devices */
NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512),
+ NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512),
};
static int nrf5_bank_is_probed(struct flash_bank *bank)
@@ -531,7 +533,6 @@ static int nrf5_probe(struct flash_bank *bank)
bank->sectors[0].size = bank->size;
bank->sectors[0].offset = 0;
- /* mark as unknown */
bank->sectors[0].is_erased = 0;
bank->sectors[0].is_protected = 0;
@@ -553,17 +554,6 @@ static int nrf5_auto_probe(struct flash_bank *bank)
return nrf5_probe(bank);
}
-static struct flash_sector *nrf5_find_sector_by_address(struct flash_bank *bank, uint32_t address)
-{
- struct nrf5_info *chip = bank->driver_priv;
-
- for (int i = 0; i < bank->num_sectors; i++)
- if (bank->sectors[i].offset <= address &&
- address < (bank->sectors[i].offset + chip->code_page_size))
- return &bank->sectors[i];
- return NULL;
-}
-
static int nrf5_erase_all(struct nrf5_info *chip)
{
LOG_DEBUG("Erasing all non-volatile memory");
@@ -615,9 +605,6 @@ static int nrf5_erase_page(struct flash_bank *bank,
sector->offset);
}
- if (res == ERROR_OK)
- sector->is_erased = 1;
-
return res;
}
@@ -743,48 +730,22 @@ static int nrf5_write_pages(struct flash_bank *bank, uint32_t start, uint32_t en
{
int res = ERROR_FAIL;
struct nrf5_info *chip = bank->driver_priv;
- struct flash_sector *sector;
- uint32_t offset;
assert(start % chip->code_page_size == 0);
assert(end % chip->code_page_size == 0);
- /* Erase all sectors */
- for (offset = start; offset < end; offset += chip->code_page_size) {
- sector = nrf5_find_sector_by_address(bank, offset);
- if (!sector) {
- LOG_ERROR("Invalid sector @ 0x%08"PRIx32, offset);
- return ERROR_FLASH_SECTOR_INVALID;
- }
-
- if (sector->is_protected) {
- LOG_ERROR("Can't erase protected sector @ 0x%08"PRIx32, offset);
- goto error;
- }
-
- if (sector->is_erased != 1) { /* 1 = erased, 0= not erased, -1 = unknown */
- res = nrf5_erase_page(bank, chip, sector);
- if (res != ERROR_OK) {
- LOG_ERROR("Failed to erase sector @ 0x%08"PRIx32, sector->offset);
- goto error;
- }
- }
- sector->is_erased = 0;
- }
-
res = nrf5_nvmc_write_enable(chip);
if (res != ERROR_OK)
goto error;
res = nrf5_ll_flash_write(chip, start, buffer, (end - start));
if (res != ERROR_OK)
- goto set_read_only;
+ goto error;
return nrf5_nvmc_read_only(chip);
-set_read_only:
- nrf5_nvmc_read_only(chip);
error:
+ nrf5_nvmc_read_only(chip);
LOG_ERROR("Failed to write to nrf5 flash");
return res;
}
@@ -876,11 +837,9 @@ static int nrf5_uicr_flash_write(struct flash_bank *bank,
if (res != ERROR_OK)
return res;
- if (sector->is_erased != 1) {
- res = nrf5_erase_page(bank, chip, sector);
- if (res != ERROR_OK)
- return res;
- }
+ res = nrf5_erase_page(bank, chip, sector);
+ if (res != ERROR_OK)
+ return res;
res = nrf5_nvmc_write_enable(chip);
if (res != ERROR_OK)
@@ -911,6 +870,18 @@ static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer,
return chip->bank[bank->bank_number].write(bank, chip, buffer, offset, count);
}
+static void nrf5_free_driver_priv(struct flash_bank *bank)
+{
+ struct nrf5_info *chip = bank->driver_priv;
+ if (chip == NULL)
+ return;
+
+ chip->refcount--;
+ if (chip->refcount == 0) {
+ free(chip);
+ bank->driver_priv = NULL;
+ }
+}
FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
{
@@ -946,6 +917,7 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
break;
}
+ chip->refcount++;
chip->bank[bank->bank_number].probed = false;
bank->driver_priv = chip;
@@ -992,9 +964,6 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command)
return res;
}
- for (int i = 0; i < bank->num_sectors; i++)
- bank->sectors[i].is_erased = 1;
-
res = nrf5_protect_check(bank);
if (res != ERROR_OK) {
LOG_ERROR("Failed to check chip's write protection");
@@ -1005,8 +974,6 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command)
if (res != ERROR_OK)
return res;
- bank->sectors[0].is_erased = 1;
-
return ERROR_OK;
}
@@ -1175,6 +1142,7 @@ struct flash_driver nrf5_flash = {
.auto_probe = nrf5_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = nrf5_protect_check,
+ .free_driver_priv = nrf5_free_driver_priv,
};
/* We need to retain the flash-driver name as well as the commands
@@ -1192,4 +1160,5 @@ struct flash_driver nrf51_flash = {
.auto_probe = nrf5_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = nrf5_protect_check,
+ .free_driver_priv = nrf5_free_driver_priv,
};
diff --git a/src/flash/nor/psoc5lp.c b/src/flash/nor/psoc5lp.c
index ae8e3d3..b88abbb 100644
--- a/src/flash/nor/psoc5lp.c
+++ b/src/flash/nor/psoc5lp.c
@@ -234,7 +234,8 @@ static void psoc5lp_get_part_number(const struct psoc5lp_device *dev, char *str)
}
/* Package does not matter. */
- strncpy(str + 8, "xx", 2);
+ str[8] = 'x';
+ str[9] = 'x';
/* Temperate range cannot uniquely be identified. */
str[10] = 'x';
@@ -859,6 +860,7 @@ struct flash_driver psoc5lp_nvl_flash = {
.erase = psoc5lp_nvl_erase,
.erase_check = psoc5lp_nvl_erase_check,
.write = psoc5lp_nvl_write,
+ .free_driver_priv = default_flash_free_driver_priv,
};
/*
@@ -1067,6 +1069,7 @@ struct flash_driver psoc5lp_eeprom_flash = {
.erase = psoc5lp_eeprom_erase,
.erase_check = default_flash_blank_check,
.write = psoc5lp_eeprom_write,
+ .free_driver_priv = default_flash_free_driver_priv,
};
/*
@@ -1077,6 +1080,10 @@ struct psoc5lp_flash_bank {
bool probed;
const struct psoc5lp_device *device;
bool ecc_enabled;
+ /* If ecc is disabled, num_sectors counts both std and ecc sectors.
+ * If ecc is enabled, num_sectors indicates just the number of std sectors.
+ * However ecc sector descriptors bank->sector[num_sectors..2*num_sectors-1]
+ * are used for driver private flash operations */
};
static int psoc5lp_erase(struct flash_bank *bank, int first, int last)
@@ -1121,21 +1128,25 @@ static int psoc5lp_erase_check(struct flash_bank *bank)
return ERROR_TARGET_NOT_HALTED;
}
+ int num_sectors = bank->num_sectors;
+ if (psoc_bank->ecc_enabled)
+ num_sectors *= 2; /* count both std and ecc sector always */
+
struct target_memory_check_block *block_array;
- block_array = malloc(bank->num_sectors * sizeof(struct target_memory_check_block));
+ block_array = malloc(num_sectors * sizeof(struct target_memory_check_block));
if (block_array == NULL)
return ERROR_FAIL;
- for (i = 0; i < bank->num_sectors; i++) {
+ for (i = 0; i < num_sectors; i++) {
block_array[i].address = bank->base + bank->sectors[i].offset;
block_array[i].size = bank->sectors[i].size;
block_array[i].result = UINT32_MAX; /* erase state unknown */
}
bool fast_check = true;
- for (i = 0; i < bank->num_sectors; ) {
+ for (i = 0; i < num_sectors; ) {
retval = armv7m_blank_check_memory(target,
- block_array + i, bank->num_sectors - i,
+ block_array + i, num_sectors - i,
bank->erased_value);
if (retval < 1) {
/* Run slow fallback if the first run gives no result
@@ -1148,15 +1159,15 @@ static int psoc5lp_erase_check(struct flash_bank *bank)
}
if (fast_check) {
- if (!psoc_bank->ecc_enabled) {
- int half_sectors = bank->num_sectors / 2;
- for (i = 0; i < half_sectors / 2; i++)
+ if (psoc_bank->ecc_enabled) {
+ for (i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased =
(block_array[i].result != 1)
- ? block_array[i + half_sectors].result
- : block_array[i].result;
+ ? block_array[i].result
+ : block_array[i + bank->num_sectors].result;
+ /* if std sector is erased, use status of ecc sector */
} else {
- for (i = 0; i < bank->num_sectors; i++)
+ for (i = 0; i < num_sectors; i++)
bank->sectors[i].is_erased = block_array[i].result;
}
retval = ERROR_OK;
@@ -1571,4 +1582,5 @@ struct flash_driver psoc5lp_flash = {
.erase = psoc5lp_erase,
.erase_check = psoc5lp_erase_check,
.write = psoc5lp_write,
+ .free_driver_priv = default_flash_free_driver_priv,
};
diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c
index 015988a..faada9a 100644
--- a/src/flash/nor/stm32f1x.c
+++ b/src/flash/nor/stm32f1x.c
@@ -585,8 +585,10 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
retval = target_write_buffer(target, write_algorithm->address,
sizeof(stm32x_flash_write_code), stm32x_flash_write_code);
- if (retval != ERROR_OK)
+ if (retval != ERROR_OK) {
+ target_free_working_area(target, write_algorithm);
return retval;
+ }
/* memory buffer */
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c
index 8013e58..413d04d 100644
--- a/src/flash/nor/stm32f2x.c
+++ b/src/flash/nor/stm32f2x.c
@@ -252,6 +252,8 @@ static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout)
/* Clear but report errors */
if (status & FLASH_ERROR) {
+ if (retval == ERROR_OK)
+ retval = ERROR_FAIL;
/* If this operation fails, we ignore it and report the original
* retval
*/
@@ -597,8 +599,10 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
retval = target_write_buffer(target, write_algorithm->address,
sizeof(stm32x_flash_write_code),
stm32x_flash_write_code);
- if (retval != ERROR_OK)
+ if (retval != ERROR_OK) {
+ target_free_working_area(target, write_algorithm);
return retval;
+ }
/* memory buffer */
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c
index 009eb9b..fcfcf91 100644
--- a/src/flash/nor/stm32h7x.c
+++ b/src/flash/nor/stm32h7x.c
@@ -64,7 +64,7 @@
#define FLASH_WRPERR (1 << 17) /* Write protection error */
#define FLASH_PGSERR (1 << 18) /* Programming sequence error */
#define FLASH_STRBERR (1 << 19) /* Strobe error */
-#define FLASH_INCERR (1 << 21) /* Increment error */
+#define FLASH_INCERR (1 << 21) /* Inconsistency error */
#define FLASH_OPERR (1 << 22) /* Operation error */
#define FLASH_RDPERR (1 << 23) /* Read Protection error */
#define FLASH_RDSERR (1 << 24) /* Secure Protection error */
@@ -220,6 +220,8 @@ static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout)
/* Clear error + EOP flags but report errors */
if (status & FLASH_ERROR) {
+ if (retval == ERROR_OK)
+ retval = ERROR_FAIL;
/* If this operation fails, we ignore it and report the original retval */
target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CCR), status);
}
@@ -495,7 +497,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last)
retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
if (retval != ERROR_OK) {
- LOG_ERROR("erase time-out error sector %d", i);
+ LOG_ERROR("erase time-out or operation error sector %d", i);
return retval;
}
bank->sectors[i].is_erased = 1;
@@ -581,8 +583,10 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
retval = target_write_buffer(target, write_algorithm->address,
sizeof(stm32x_flash_write_code),
stm32x_flash_write_code);
- if (retval != ERROR_OK)
+ if (retval != ERROR_OK) {
+ target_free_working_area(target, write_algorithm);
return retval;
+ }
/* memory buffer */
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c
index e47313c..4fb7e03 100644
--- a/src/flash/nor/stm32l4x.c
+++ b/src/flash/nor/stm32l4x.c
@@ -187,6 +187,8 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout)
/* Clear but report errors */
if (status & FLASH_ERROR) {
+ if (retval == ERROR_OK)
+ retval = ERROR_FAIL;
/* If this operation fails, we ignore it and report the original
* retval
*/
@@ -474,8 +476,10 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
retval = target_write_buffer(target, write_algorithm->address,
sizeof(stm32l4_flash_write_code),
stm32l4_flash_write_code);
- if (retval != ERROR_OK)
+ if (retval != ERROR_OK) {
+ target_free_working_area(target, write_algorithm);
return retval;
+ }
/* memory buffer */
while (target_alloc_working_area_try(target, buffer_size, &source) !=
diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c
index c68d7c2..3251df3 100644
--- a/src/flash/nor/stm32lx.c
+++ b/src/flash/nor/stm32lx.c
@@ -146,7 +146,7 @@ static const struct stm32lx_rev stm32_425_revs[] = {
{ 0x1000, "A" }, { 0x2000, "B" }, { 0x2008, "Y" },
};
static const struct stm32lx_rev stm32_427_revs[] = {
- { 0x1000, "A" }, { 0x1018, "Y" }, { 0x1038, "X" },
+ { 0x1000, "A" }, { 0x1018, "Y" }, { 0x1038, "X" }, { 0x10f8, "V" },
};
static const struct stm32lx_rev stm32_429_revs[] = {
{ 0x1000, "A" }, { 0x1018, "Z" },
diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c
index 34681db..95ca819 100644
--- a/src/flash/nor/tcl.c
+++ b/src/flash/nor/tcl.c
@@ -288,24 +288,6 @@ COMMAND_HANDLER(handle_flash_erase_address_command)
return retval;
}
-static int flash_check_sector_parameters(struct command_context *cmd_ctx,
- uint32_t first, uint32_t last, uint32_t num_sectors)
-{
- if (!(first <= last)) {
- command_print(cmd_ctx, "ERROR: "
- "first sector must be <= last sector");
- return ERROR_FAIL;
- }
-
- if (!(last <= (num_sectors - 1))) {
- command_print(cmd_ctx, "ERROR: last sector must be <= %" PRIu32,
- num_sectors - 1);
- return ERROR_FAIL;
- }
-
- return ERROR_OK;
-}
-
COMMAND_HANDLER(handle_flash_erase_command)
{
if (CMD_ARGC != 3)
@@ -327,9 +309,18 @@ COMMAND_HANDLER(handle_flash_erase_command)
else
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last);
- retval = flash_check_sector_parameters(CMD_CTX, first, last, p->num_sectors);
- if (retval != ERROR_OK)
- return retval;
+ if (!(first <= last)) {
+ command_print(CMD_CTX, "ERROR: "
+ "first sector must be <= last");
+ return ERROR_FAIL;
+ }
+
+ if (!(last <= (uint32_t)(p->num_sectors - 1))) {
+ command_print(CMD_CTX, "ERROR: "
+ "last sector must be <= %" PRIu32,
+ p->num_sectors - 1);
+ return ERROR_FAIL;
+ }
struct duration bench;
duration_start(&bench);
@@ -375,15 +366,28 @@ COMMAND_HANDLER(handle_flash_protect_command)
bool set;
COMMAND_PARSE_ON_OFF(CMD_ARGV[3], set);
- retval = flash_check_sector_parameters(CMD_CTX, first, last, num_blocks);
- if (retval != ERROR_OK)
- return retval;
+ if (!(first <= last)) {
+ command_print(CMD_CTX, "ERROR: "
+ "first %s must be <= last",
+ (p->num_prot_blocks) ? "block" : "sector");
+ return ERROR_FAIL;
+ }
+
+ if (!(last <= (uint32_t)(num_blocks - 1))) {
+ command_print(CMD_CTX, "ERROR: "
+ "last %s must be <= %" PRIu32,
+ (p->num_prot_blocks) ? "block" : "sector",
+ num_blocks - 1);
+ return ERROR_FAIL;
+ }
retval = flash_driver_protect(p, set, first, last);
if (retval == ERROR_OK) {
- command_print(CMD_CTX, "%s protection for sectors %" PRIu32
+ command_print(CMD_CTX, "%s protection for %s %" PRIu32
" through %" PRIu32 " on flash bank %d",
- (set) ? "set" : "cleared", first, last, p->bank_number);
+ (set) ? "set" : "cleared",
+ (p->num_prot_blocks) ? "blocks" : "sectors",
+ first, last, p->bank_number);
}
return retval;
@@ -502,7 +506,7 @@ COMMAND_HANDLER(handle_flash_fill_command)
if (count == 0)
return ERROR_OK;
- if (address + count >= bank->base + bank->size) {
+ if (address + count * wordsize > bank->base + bank->size) {
LOG_ERROR("Cannot cross flash bank borders");
return ERROR_FAIL;
}
diff --git a/src/flash/nor/tms470.c b/src/flash/nor/tms470.c
index 102bf1b..2435e79 100644
--- a/src/flash/nor/tms470.c
+++ b/src/flash/nor/tms470.c
@@ -151,6 +151,7 @@ static int tms470_read_part_info(struct flash_bank *bank)
if (bank->sectors) {
free(bank->sectors);
bank->sectors = NULL;
+ bank->num_sectors = 0;
}
/*
@@ -754,9 +755,6 @@ static int tms470_erase_sector(struct flash_bank *bank, int sector)
target_write_u32(target, 0xFFFFFFDC, glbctrl);
LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl);
- if (result == ERROR_OK)
- bank->sectors[sector].is_erased = 1;
-
return result;
}
@@ -1044,27 +1042,17 @@ static int tms470_erase_check(struct flash_bank *bank)
* an attempt to reduce the JTAG overhead.
*/
for (sector = 0; sector < bank->num_sectors; sector++) {
- if (bank->sectors[sector].is_erased != 1) {
- uint32_t i, addr = bank->base + bank->sectors[sector].offset;
-
- LOG_INFO("checking flash bank %d sector %d", tms470_info->ordinal, sector);
-
- target_read_buffer(target, addr, bank->sectors[sector].size, buffer);
-
- bank->sectors[sector].is_erased = 1;
- for (i = 0; i < bank->sectors[sector].size; i++) {
- if (buffer[i] != 0xff) {
- LOG_WARNING("tms470 bank %d, sector %d, not erased.",
- tms470_info->ordinal,
- sector);
- LOG_WARNING(
- "at location 0x%08" PRIx32 ": flash data is 0x%02x.",
- addr + i,
- buffer[i]);
-
- bank->sectors[sector].is_erased = 0;
- break;
- }
+ uint32_t i, addr = bank->base + bank->sectors[sector].offset;
+
+ LOG_INFO("checking flash bank %d sector %d", tms470_info->ordinal, sector);
+
+ target_read_buffer(target, addr, bank->sectors[sector].size, buffer);
+
+ bank->sectors[sector].is_erased = 1;
+ for (i = 0; i < bank->sectors[sector].size; i++) {
+ if (buffer[i] != 0xff) {
+ bank->sectors[sector].is_erased = 0;
+ break;
}
}
if (bank->sectors[sector].is_erased != 1) {
diff --git a/src/jtag/aice/aice_usb.c b/src/jtag/aice/aice_usb.c
index 50468f3..d77b26b 100644
--- a/src/jtag/aice/aice_usb.c
+++ b/src/jtag/aice/aice_usb.c
@@ -2289,37 +2289,39 @@ get_delay:
static int aice_usb_set_clock(int set_clock)
{
- if (aice_write_ctrl(AICE_WRITE_CTRL_TCK_CONTROL,
- AICE_TCK_CONTROL_TCK_SCAN) != ERROR_OK)
- return ERROR_FAIL;
+ if (set_clock & AICE_TCK_CONTROL_TCK_SCAN) {
+ if (aice_write_ctrl(AICE_WRITE_CTRL_TCK_CONTROL,
+ AICE_TCK_CONTROL_TCK_SCAN) != ERROR_OK)
+ return ERROR_FAIL;
- /* Read out TCK_SCAN clock value */
- uint32_t scan_clock;
- if (aice_read_ctrl(AICE_READ_CTRL_GET_ICE_STATE, &scan_clock) != ERROR_OK)
- return ERROR_FAIL;
+ /* Read out TCK_SCAN clock value */
+ uint32_t scan_clock;
+ if (aice_read_ctrl(AICE_READ_CTRL_GET_ICE_STATE, &scan_clock) != ERROR_OK)
+ return ERROR_FAIL;
- scan_clock &= 0x0F;
+ scan_clock &= 0x0F;
- uint32_t scan_base_freq;
- if (scan_clock & 0x8)
- scan_base_freq = 48000; /* 48 MHz */
- else
- scan_base_freq = 30000; /* 30 MHz */
+ uint32_t scan_base_freq;
+ if (scan_clock & 0x8)
+ scan_base_freq = 48000; /* 48 MHz */
+ else
+ scan_base_freq = 30000; /* 30 MHz */
- uint32_t set_base_freq;
- if (set_clock & 0x8)
- set_base_freq = 48000;
- else
- set_base_freq = 30000;
+ uint32_t set_base_freq;
+ if (set_clock & 0x8)
+ set_base_freq = 48000;
+ else
+ set_base_freq = 30000;
- uint32_t set_freq;
- uint32_t scan_freq;
- set_freq = set_base_freq >> (set_clock & 0x7);
- scan_freq = scan_base_freq >> (scan_clock & 0x7);
+ uint32_t set_freq;
+ uint32_t scan_freq;
+ set_freq = set_base_freq >> (set_clock & 0x7);
+ scan_freq = scan_base_freq >> (scan_clock & 0x7);
- if (scan_freq < set_freq) {
- LOG_ERROR("User specifies higher jtag clock than TCK_SCAN clock");
- return ERROR_FAIL;
+ if (scan_freq < set_freq) {
+ LOG_ERROR("User specifies higher jtag clock than TCK_SCAN clock");
+ return ERROR_FAIL;
+ }
}
if (aice_write_ctrl(AICE_WRITE_CTRL_TCK_CONTROL, set_clock) != ERROR_OK)
diff --git a/src/jtag/aice/aice_usb.h b/src/jtag/aice/aice_usb.h
index 2911ae5..15cc1f6 100644
--- a/src/jtag/aice/aice_usb.h
+++ b/src/jtag/aice/aice_usb.h
@@ -71,6 +71,7 @@
/* Constants for AICE command WRITE_CTRL:TCK_CONTROL */
#define AICE_TCK_CONTROL_TCK3048 0x08
+#define AICE_TCK_CONTROL_TCK_SCAN 0x10
/* Constants for AICE command WRITE_CTRL:JTAG_PIN_CONTROL */
#define AICE_JTAG_PIN_CONTROL_SRST 0x01
diff --git a/src/jtag/core.c b/src/jtag/core.c
index 5d9b810..f90ae99 100644
--- a/src/jtag/core.c
+++ b/src/jtag/core.c
@@ -1843,7 +1843,7 @@ void adapter_deassert_reset(void)
LOG_ERROR("transport is not selected");
}
-int adapter_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
+int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq)
{
if (jtag->config_trace)
diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c
index b8181d6..4ee4836 100644
--- a/src/jtag/drivers/cmsis_dap_usb.c
+++ b/src/jtag/drivers/cmsis_dap_usb.c
@@ -729,6 +729,20 @@ static void cmsis_dap_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_del
cmsis_dap_swd_queue_cmd(cmd, value, 0);
}
+static int cmsis_dap_get_serial_info(void)
+{
+ uint8_t *data;
+
+ int retval = cmsis_dap_cmd_DAP_Info(INFO_ID_SERNUM, &data);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (data[0]) /* strlen */
+ LOG_INFO("CMSIS-DAP: Serial# = %s", &data[1]);
+
+ return ERROR_OK;
+}
+
static int cmsis_dap_get_version_info(void)
{
uint8_t *data;
@@ -802,8 +816,7 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq)
/* When we are reconnecting, DAP_Connect needs to be rerun, at
* least on Keil ULINK-ME */
- retval = cmsis_dap_cmd_DAP_Connect(seq == LINE_RESET || seq == JTAG_TO_SWD ?
- CONNECT_SWD : CONNECT_JTAG);
+ retval = cmsis_dap_cmd_DAP_Connect(CONNECT_SWD);
if (retval != ERROR_OK)
return retval;
}
@@ -842,17 +855,6 @@ static int cmsis_dap_swd_open(void)
{
int retval;
- if (cmsis_dap_handle == NULL) {
- /* SWD init */
- retval = cmsis_dap_usb_open();
- if (retval != ERROR_OK)
- return retval;
-
- retval = cmsis_dap_get_caps_info();
- if (retval != ERROR_OK)
- return retval;
- }
-
if (!(cmsis_dap_handle->caps & INFO_CAPS_SWD)) {
LOG_ERROR("CMSIS-DAP: SWD not supported");
return ERROR_JTAG_DEVICE_ERROR;
@@ -873,6 +875,22 @@ static int cmsis_dap_init(void)
int retval;
uint8_t *data;
+ retval = cmsis_dap_usb_open();
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = cmsis_dap_get_caps_info();
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = cmsis_dap_get_version_info();
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = cmsis_dap_get_serial_info();
+ if (retval != ERROR_OK)
+ return retval;
+
if (swd_mode) {
retval = cmsis_dap_swd_open();
if (retval != ERROR_OK)
@@ -880,16 +898,6 @@ static int cmsis_dap_init(void)
}
if (cmsis_dap_handle == NULL) {
-
- /* JTAG init */
- retval = cmsis_dap_usb_open();
- if (retval != ERROR_OK)
- return retval;
-
- retval = cmsis_dap_get_caps_info();
- if (retval != ERROR_OK)
- return retval;
-
/* Connect in JTAG mode */
if (!(cmsis_dap_handle->caps & INFO_CAPS_JTAG)) {
LOG_ERROR("CMSIS-DAP: JTAG not supported");
@@ -903,10 +911,6 @@ static int cmsis_dap_init(void)
LOG_INFO("CMSIS-DAP: Interface Initialised (JTAG)");
}
- retval = cmsis_dap_get_version_info();
- if (retval != ERROR_OK)
- return retval;
-
/* INFO_ID_PKT_SZ - short */
retval = cmsis_dap_cmd_DAP_Info(INFO_ID_PKT_SZ, &data);
if (retval != ERROR_OK)
@@ -1458,6 +1462,12 @@ static void cmsis_dap_execute_stableclocks(struct jtag_command *cmd)
cmsis_dap_stableclocks(cmd->cmd.runtest->num_cycles);
}
+static void cmsis_dap_execute_tms(struct jtag_command *cmd)
+{
+ DEBUG_JTAG_IO("TMS: %d bits", cmd->cmd.tms->num_bits);
+ cmsis_dap_cmd_DAP_SWJ_Sequence(cmd->cmd.tms->num_bits, cmd->cmd.tms->bits);
+}
+
/* TODO: Is there need to call cmsis_dap_flush() for the JTAG_PATHMOVE,
* JTAG_RUNTEST, JTAG_STABLECLOCKS? */
static void cmsis_dap_execute_command(struct jtag_command *cmd)
@@ -1488,6 +1498,8 @@ static void cmsis_dap_execute_command(struct jtag_command *cmd)
cmsis_dap_execute_stableclocks(cmd);
break;
case JTAG_TMS:
+ cmsis_dap_execute_tms(cmd);
+ break;
default:
LOG_ERROR("BUG: unknown JTAG command type 0x%X encountered", cmd->type);
exit(-1);
@@ -1650,6 +1662,7 @@ static const char * const cmsis_dap_transport[] = { "swd", "jtag", NULL };
struct jtag_interface cmsis_dap_interface = {
.name = "cmsis-dap",
+ .supported = DEBUG_CAP_TMS_SEQ,
.commands = cmsis_dap_command_handlers,
.swd = &cmsis_dap_swd_driver,
.transports = cmsis_dap_transport,
diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c
index 132ef06..e74965e 100644
--- a/src/jtag/drivers/jlink.c
+++ b/src/jtag/drivers/jlink.c
@@ -1263,7 +1263,7 @@ static bool check_trace_freq(struct jaylink_swo_speed speed,
return false;
}
-static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
+static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq)
{
int ret;
@@ -1275,7 +1275,7 @@ static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
return ERROR_FAIL;
}
- if (pin_protocol != ASYNC_UART) {
+ if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) {
LOG_ERROR("Selected pin protocol is not supported.");
return ERROR_FAIL;
}
diff --git a/src/jtag/drivers/jtag_vpi.c b/src/jtag/drivers/jtag_vpi.c
index a1787d4..1a42b3a 100644
--- a/src/jtag/drivers/jtag_vpi.c
+++ b/src/jtag/drivers/jtag_vpi.c
@@ -204,23 +204,20 @@ static int jtag_vpi_queue_tdi_xfer(uint8_t *bits, int nb_bits, int tap_shift)
static int jtag_vpi_queue_tdi(uint8_t *bits, int nb_bits, int tap_shift)
{
int nb_xfer = DIV_ROUND_UP(nb_bits, XFERT_MAX_SIZE * 8);
- uint8_t *xmit_buffer = bits;
- int xmit_nb_bits = nb_bits;
- int i = 0;
int retval;
while (nb_xfer) {
-
if (nb_xfer == 1) {
- retval = jtag_vpi_queue_tdi_xfer(&xmit_buffer[i], xmit_nb_bits, tap_shift);
+ retval = jtag_vpi_queue_tdi_xfer(bits, nb_bits, tap_shift);
if (retval != ERROR_OK)
return retval;
} else {
- retval = jtag_vpi_queue_tdi_xfer(&xmit_buffer[i], XFERT_MAX_SIZE * 8, NO_TAP_SHIFT);
+ retval = jtag_vpi_queue_tdi_xfer(bits, XFERT_MAX_SIZE * 8, NO_TAP_SHIFT);
if (retval != ERROR_OK)
return retval;
- xmit_nb_bits -= XFERT_MAX_SIZE * 8;
- i += XFERT_MAX_SIZE;
+ nb_bits -= XFERT_MAX_SIZE * 8;
+ if (bits)
+ bits += XFERT_MAX_SIZE;
}
nb_xfer--;
diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c
index 99f96b9..d9ca53e 100644
--- a/src/jtag/drivers/stlink_usb.c
+++ b/src/jtag/drivers/stlink_usb.c
@@ -2194,12 +2194,13 @@ error_open:
return ERROR_FAIL;
}
-int stlink_config_trace(void *handle, bool enabled, enum tpio_pin_protocol pin_protocol,
+int stlink_config_trace(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq)
{
struct stlink_usb_handle_s *h = handle;
- if (enabled && (h->jtag_api < 2 || pin_protocol != ASYNC_UART)) {
+ if (enabled && (h->jtag_api < 2 ||
+ pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART)) {
LOG_ERROR("The attached ST-LINK version doesn't support this trace mode");
return ERROR_FAIL;
}
diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c b/src/jtag/drivers/usb_blaster/usb_blaster.c
index df9f2a1..8ccf871 100644
--- a/src/jtag/drivers/usb_blaster/usb_blaster.c
+++ b/src/jtag/drivers/usb_blaster/usb_blaster.c
@@ -445,6 +445,7 @@ static void ublast_queue_bytes(uint8_t *bytes, int nb_bytes)
* ublast_tms_seq - write a TMS sequence transition to JTAG
* @bits: TMS bits to be written (bit0, bit1 .. bitN)
* @nb_bits: number of TMS bits (between 1 and 8)
+ * @skip: number of TMS bits to skip at the beginning of the series
*
* Write a serie of TMS transitions, where each transition consists in :
* - writing out TCK=0, TMS=<new_state>, TDI=<???>
@@ -452,12 +453,12 @@ static void ublast_queue_bytes(uint8_t *bytes, int nb_bytes)
* The function ensures that at the end of the sequence, the clock (TCK) is put
* low.
*/
-static void ublast_tms_seq(const uint8_t *bits, int nb_bits)
+static void ublast_tms_seq(const uint8_t *bits, int nb_bits, int skip)
{
int i;
DEBUG_JTAG_IO("(bits=%02x..., nb_bits=%d)", bits[0], nb_bits);
- for (i = 0; i < nb_bits; i++)
+ for (i = skip; i < nb_bits; i++)
ublast_clock_tms((bits[i / 8] >> (i % 8)) & 0x01);
ublast_idle_clock();
}
@@ -469,7 +470,7 @@ static void ublast_tms_seq(const uint8_t *bits, int nb_bits)
static void ublast_tms(struct tms_command *cmd)
{
DEBUG_JTAG_IO("(num_bits=%d)", cmd->num_bits);
- ublast_tms_seq(cmd->bits, cmd->num_bits);
+ ublast_tms_seq(cmd->bits, cmd->num_bits, 0);
}
/**
@@ -501,11 +502,12 @@ static void ublast_path_move(struct pathmove_command *cmd)
/**
* ublast_state_move - move JTAG state to the target state
* @state: the target state
+ * @skip: number of bits to skip at the beginning of the path
*
* Input the correct TMS sequence to the JTAG TAP so that we end up in the
* target state. This assumes the current state (tap_get_state()) is correct.
*/
-static void ublast_state_move(tap_state_t state)
+static void ublast_state_move(tap_state_t state, int skip)
{
uint8_t tms_scan;
int tms_len;
@@ -516,7 +518,7 @@ static void ublast_state_move(tap_state_t state)
return;
tms_scan = tap_get_tms_path(tap_get_state(), state);
tms_len = tap_get_tms_path_len(tap_get_state(), state);
- ublast_tms_seq(&tms_scan, tms_len);
+ ublast_tms_seq(&tms_scan, tms_len, skip);
tap_set_state(state);
}
@@ -688,9 +690,9 @@ static void ublast_runtest(int cycles, tap_state_t state)
{
DEBUG_JTAG_IO("%s(cycles=%i, end_state=%d)", __func__, cycles, state);
- ublast_state_move(TAP_IDLE);
+ ublast_state_move(TAP_IDLE, 0);
ublast_queue_tdi(NULL, cycles, SCAN_OUT);
- ublast_state_move(state);
+ ublast_state_move(state, 0);
}
static void ublast_stableclocks(int cycles)
@@ -720,9 +722,9 @@ static int ublast_scan(struct scan_command *cmd)
scan_bits = jtag_build_buffer(cmd, &buf);
if (cmd->ir_scan)
- ublast_state_move(TAP_IRSHIFT);
+ ublast_state_move(TAP_IRSHIFT, 0);
else
- ublast_state_move(TAP_DRSHIFT);
+ ublast_state_move(TAP_DRSHIFT, 0);
log_buf = hexdump(buf, DIV_ROUND_UP(scan_bits, 8));
DEBUG_JTAG_IO("%s(scan=%s, type=%s, bits=%d, buf=[%s], end_state=%d)", __func__,
@@ -733,20 +735,15 @@ static int ublast_scan(struct scan_command *cmd)
ublast_queue_tdi(buf, scan_bits, type);
- /*
- * As our JTAG is in an unstable state (IREXIT1 or DREXIT1), move it
- * forward to a stable IRPAUSE or DRPAUSE.
- */
- ublast_clock_tms(0);
- if (cmd->ir_scan)
- tap_set_state(TAP_IRPAUSE);
- else
- tap_set_state(TAP_DRPAUSE);
-
ret = jtag_read_buffer(buf, cmd);
if (buf)
free(buf);
- ublast_state_move(cmd->end_state);
+ /*
+ * ublast_queue_tdi sends the last bit with TMS=1. We are therefore
+ * already in Exit1-DR/IR and have to skip the first step on our way
+ * to end_state.
+ */
+ ublast_state_move(cmd->end_state, 1);
return ret;
}
@@ -776,7 +773,7 @@ static void ublast_initial_wipeout(void)
/*
* Put JTAG in RESET state (five 1 on TMS)
*/
- ublast_tms_seq(&tms_reset, 5);
+ ublast_tms_seq(&tms_reset, 5, 0);
tap_set_state(TAP_RESET);
}
@@ -805,7 +802,7 @@ static int ublast_execute_queue(void)
ublast_stableclocks(cmd->cmd.stableclocks->num_cycles);
break;
case JTAG_TLR_RESET:
- ublast_state_move(cmd->cmd.statemove->end_state);
+ ublast_state_move(cmd->cmd.statemove->end_state, 0);
break;
case JTAG_PATHMOVE:
ublast_path_move(cmd->cmd.pathmove);
diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c
index cb9ef39..2abed21 100644
--- a/src/jtag/hla/hla_interface.c
+++ b/src/jtag/hla/hla_interface.c
@@ -191,7 +191,7 @@ int hl_interface_override_target(const char **targetname)
return ERROR_FAIL;
}
-int hl_interface_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
+int hl_interface_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq)
{
if (hl_if.layout->api->config_trace)
diff --git a/src/jtag/hla/hla_layout.h b/src/jtag/hla/hla_layout.h
index 40c1321..9f41b59 100644
--- a/src/jtag/hla/hla_layout.h
+++ b/src/jtag/hla/hla_layout.h
@@ -91,7 +91,7 @@ struct hl_layout_api_s {
* its maximum supported rate there
* @returns ERROR_OK on success, an error code on failure.
*/
- int (*config_trace)(void *handle, bool enabled, enum tpio_pin_protocol pin_protocol,
+ int (*config_trace)(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq);
/**
* Poll for new trace data
diff --git a/src/jtag/interface.h b/src/jtag/interface.h
index cdfc676..e6fa0ca 100644
--- a/src/jtag/interface.h
+++ b/src/jtag/interface.h
@@ -309,7 +309,7 @@ struct jtag_interface {
* its maximum supported rate there
* @returns ERROR_OK on success, an error code on failure.
*/
- int (*config_trace)(bool enabled, enum tpio_pin_protocol pin_protocol,
+ int (*config_trace)(bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq);
/**
@@ -328,7 +328,7 @@ extern const char * const jtag_only[];
void adapter_assert_reset(void);
void adapter_deassert_reset(void);
-int adapter_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
+int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq);
int adapter_poll_trace(uint8_t *buf, size_t *size);
diff --git a/src/jtag/zy1000/zy1000.c b/src/jtag/zy1000/zy1000.c
index 67d9907..4e53dd1 100644
--- a/src/jtag/zy1000/zy1000.c
+++ b/src/jtag/zy1000/zy1000.c
@@ -265,8 +265,8 @@ COMMAND_HANDLER(handle_power_command)
bool enable;
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable);
setPower(enable);
- /* fall through */
}
+ /* fall through */
case 0:
LOG_INFO("Target power %s", savePower ? "on" : "off");
break;
diff --git a/src/rtos/Makefile.am b/src/rtos/Makefile.am
index 22f7da5..6f14b42 100644
--- a/src/rtos/Makefile.am
+++ b/src/rtos/Makefile.am
@@ -16,6 +16,7 @@ noinst_LTLIBRARIES += %D%/librtos.la
%D%/mqx.c \
%D%/riscv_debug.c \
%D%/uCOS-III.c \
+ %D%/nuttx.c \
%D%/rtos.h \
%D%/rtos_standard_stackings.h \
%D%/rtos_ecos_stackings.h \
@@ -24,6 +25,7 @@ noinst_LTLIBRARIES += %D%/librtos.la
%D%/rtos_embkernel_stackings.h \
%D%/rtos_mqx_stackings.h \
%D%/rtos_ucos_iii_stackings.h \
+ %D%/nuttx_header.h \
%D%/riscv_debug.h
%C%_librtos_la_CFLAGS = $(AM_CFLAGS)
diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c
new file mode 100644
index 0000000..284b968
--- /dev/null
+++ b/src/rtos/nuttx.c
@@ -0,0 +1,405 @@
+/***************************************************************************
+ * Copyright 2016,2017 Sony Video & Sound Products Inc. *
+ * Masatoshi Tateishi - Masatoshi.Tateishi@jp.sony.com *
+ * Masayuki Ishikawa - Masayuki.Ishikawa@jp.sony.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <jtag/jtag.h>
+#include "target/target.h"
+#include "target/target_type.h"
+#include "target/armv7m.h"
+#include "target/cortex_m.h"
+#include "rtos.h"
+#include "helper/log.h"
+#include "helper/types.h"
+#include "server/gdb_server.h"
+
+#include "nuttx_header.h"
+
+
+int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
+
+#ifdef CONFIG_DISABLE_SIGNALS
+#define SIG_QUEUE_NUM 0
+#else
+#define SIG_QUEUE_NUM 1
+#endif /* CONFIG_DISABLE_SIGNALS */
+
+#ifdef CONFIG_DISABLE_MQUEUE
+#define M_QUEUE_NUM 0
+#else
+#define M_QUEUE_NUM 2
+#endif /* CONFIG_DISABLE_MQUEUE */
+
+#ifdef CONFIG_PAGING
+#define PAGING_QUEUE_NUM 1
+#else
+#define PAGING_QUEUE_NUM 0
+#endif /* CONFIG_PAGING */
+
+
+#define TASK_QUEUE_NUM (6 + SIG_QUEUE_NUM + M_QUEUE_NUM + PAGING_QUEUE_NUM)
+
+
+/* see nuttx/sched/os_start.c */
+static char *nuttx_symbol_list[] = {
+ "g_readytorun", /* 0: must be top of this array */
+ "g_tasklisttable",
+ NULL
+};
+
+/* see nuttx/include/nuttx/sched.h */
+struct tcb {
+ uint32_t flink;
+ uint32_t blink;
+ uint8_t dat[512];
+};
+
+struct {
+ uint32_t addr;
+ uint32_t prio;
+} g_tasklist[TASK_QUEUE_NUM];
+
+static char *task_state_str[] = {
+ "INVALID",
+ "PENDING",
+ "READYTORUN",
+ "RUNNING",
+ "INACTIVE",
+ "WAIT_SEM",
+#ifndef CONFIG_DISABLE_SIGNALS
+ "WAIT_SIG",
+#endif /* CONFIG_DISABLE_SIGNALS */
+#ifndef CONFIG_DISABLE_MQUEUE
+ "WAIT_MQNOTEMPTY",
+ "WAIT_MQNOTFULL",
+#endif /* CONFIG_DISABLE_MQUEUE */
+#ifdef CONFIG_PAGING
+ "WAIT_PAGEFILL",
+#endif /* CONFIG_PAGING */
+};
+
+/* see arch/arm/include/armv7-m/irq_cmnvector.h */
+static const struct stack_register_offset nuttx_stack_offsets_cortex_m[] = {
+ { 0x28, 32 }, /* r0 */
+ { 0x2c, 32 }, /* r1 */
+ { 0x30, 32 }, /* r2 */
+ { 0x34, 32 }, /* r3 */
+ { 0x08, 32 }, /* r4 */
+ { 0x0c, 32 }, /* r5 */
+ { 0x10, 32 }, /* r6 */
+ { 0x14, 32 }, /* r7 */
+ { 0x18, 32 }, /* r8 */
+ { 0x1c, 32 }, /* r9 */
+ { 0x20, 32 }, /* r10 */
+ { 0x24, 32 }, /* r11 */
+ { 0x38, 32 }, /* r12 */
+ { 0, 32 }, /* sp */
+ { 0x3c, 32 }, /* lr */
+ { 0x40, 32 }, /* pc */
+ { 0x44, 32 }, /* xPSR */
+};
+
+
+static const struct rtos_register_stacking nuttx_stacking_cortex_m = {
+ 0x48, /* stack_registers_size */
+ -1, /* stack_growth_direction */
+ 17, /* num_output_registers */
+ 0, /* stack_alignment */
+ nuttx_stack_offsets_cortex_m /* register_offsets */
+};
+
+static const struct stack_register_offset nuttx_stack_offsets_cortex_m_fpu[] = {
+ { 0x6c, 32 }, /* r0 */
+ { 0x70, 32 }, /* r1 */
+ { 0x74, 32 }, /* r2 */
+ { 0x78, 32 }, /* r3 */
+ { 0x08, 32 }, /* r4 */
+ { 0x0c, 32 }, /* r5 */
+ { 0x10, 32 }, /* r6 */
+ { 0x14, 32 }, /* r7 */
+ { 0x18, 32 }, /* r8 */
+ { 0x1c, 32 }, /* r9 */
+ { 0x20, 32 }, /* r10 */
+ { 0x24, 32 }, /* r11 */
+ { 0x7c, 32 }, /* r12 */
+ { 0, 32 }, /* sp */
+ { 0x80, 32 }, /* lr */
+ { 0x84, 32 }, /* pc */
+ { 0x88, 32 }, /* xPSR */
+};
+
+static const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu = {
+ 0x8c, /* stack_registers_size */
+ -1, /* stack_growth_direction */
+ 17, /* num_output_registers */
+ 0, /* stack_alignment */
+ nuttx_stack_offsets_cortex_m_fpu /* register_offsets */
+};
+
+static int pid_offset = PID;
+static int state_offset = STATE;
+static int name_offset = NAME;
+static int xcpreg_offset = XCPREG;
+static int name_size = NAME_SIZE;
+
+static int rcmd_offset(const char *cmd, const char *name)
+{
+ if (strncmp(cmd, name, strlen(name)))
+ return -1;
+
+ if (strlen(cmd) <= strlen(name) + 1)
+ return -1;
+
+ return atoi(cmd + strlen(name));
+}
+
+static int nuttx_thread_packet(struct connection *connection,
+ char const *packet, int packet_size)
+{
+ char cmd[GDB_BUFFER_SIZE / 2] = "";
+
+ if (!strncmp(packet, "qRcmd", 5)) {
+ size_t len = unhexify((uint8_t *)cmd, packet + 6, sizeof(cmd));
+ int offset;
+
+ if (len <= 0)
+ goto pass;
+
+ offset = rcmd_offset(cmd, "nuttx.pid_offset");
+
+ if (offset >= 0) {
+ LOG_INFO("pid_offset: %d", offset);
+ pid_offset = offset;
+ goto retok;
+ }
+
+ offset = rcmd_offset(cmd, "nuttx.state_offset");
+
+ if (offset >= 0) {
+ LOG_INFO("state_offset: %d", offset);
+ state_offset = offset;
+ goto retok;
+ }
+
+ offset = rcmd_offset(cmd, "nuttx.name_offset");
+
+ if (offset >= 0) {
+ LOG_INFO("name_offset: %d", offset);
+ name_offset = offset;
+ goto retok;
+ }
+
+ offset = rcmd_offset(cmd, "nuttx.xcpreg_offset");
+
+ if (offset >= 0) {
+ LOG_INFO("xcpreg_offset: %d", offset);
+ xcpreg_offset = offset;
+ goto retok;
+ }
+
+ offset = rcmd_offset(cmd, "nuttx.name_size");
+
+ if (offset >= 0) {
+ LOG_INFO("name_size: %d", offset);
+ name_size = offset;
+ goto retok;
+ }
+ }
+pass:
+ return rtos_thread_packet(connection, packet, packet_size);
+retok:
+ gdb_put_packet(connection, "OK", 2);
+ return ERROR_OK;
+}
+
+
+static bool nuttx_detect_rtos(struct target *target)
+{
+ if ((target->rtos->symbols != NULL) &&
+ (target->rtos->symbols[0].address != 0) &&
+ (target->rtos->symbols[1].address != 0)) {
+ return true;
+ }
+ return false;
+}
+
+static int nuttx_create(struct target *target)
+{
+
+ target->rtos->gdb_thread_packet = nuttx_thread_packet;
+ LOG_INFO("target type name = %s", target->type->name);
+ return 0;
+}
+
+static int nuttx_update_threads(struct rtos *rtos)
+{
+ uint32_t thread_count;
+ struct tcb tcb;
+ int ret;
+ uint32_t head;
+ uint32_t tcb_addr;
+ uint32_t i;
+ uint8_t state;
+
+ if (rtos->symbols == NULL) {
+ LOG_ERROR("No symbols for NuttX");
+ return -3;
+ }
+
+ /* free previous thread details */
+ rtos_free_threadlist(rtos);
+
+ ret = target_read_buffer(rtos->target, rtos->symbols[1].address,
+ sizeof(g_tasklist), (uint8_t *)&g_tasklist);
+ if (ret) {
+ LOG_ERROR("target_read_buffer : ret = %d\n", ret);
+ return ERROR_FAIL;
+ }
+
+ thread_count = 0;
+
+ for (i = 0; i < TASK_QUEUE_NUM; i++) {
+
+ if (g_tasklist[i].addr == 0)
+ continue;
+
+ ret = target_read_u32(rtos->target, g_tasklist[i].addr,
+ &head);
+
+ if (ret) {
+ LOG_ERROR("target_read_u32 : ret = %d\n", ret);
+ return ERROR_FAIL;
+ }
+
+ /* readytorun head is current thread */
+ if (g_tasklist[i].addr == rtos->symbols[0].address)
+ rtos->current_thread = head;
+
+
+ tcb_addr = head;
+ while (tcb_addr) {
+ struct thread_detail *thread;
+ ret = target_read_buffer(rtos->target, tcb_addr,
+ sizeof(tcb), (uint8_t *)&tcb);
+ if (ret) {
+ LOG_ERROR("target_read_buffer : ret = %d\n",
+ ret);
+ return ERROR_FAIL;
+ }
+ thread_count++;
+
+ rtos->thread_details = realloc(rtos->thread_details,
+ sizeof(struct thread_detail) * thread_count);
+ thread = &rtos->thread_details[thread_count - 1];
+ thread->threadid = tcb_addr;
+ thread->exists = true;
+
+ state = tcb.dat[state_offset - 8];
+ thread->extra_info_str = NULL;
+ if (state < sizeof(task_state_str)/sizeof(char *)) {
+ thread->extra_info_str = malloc(256);
+ snprintf(thread->extra_info_str, 256, "pid:%d, %s",
+ tcb.dat[pid_offset - 8] |
+ tcb.dat[pid_offset - 8 + 1] << 8,
+ task_state_str[state]);
+ }
+
+ if (name_offset) {
+ thread->thread_name_str = malloc(name_size + 1);
+ snprintf(thread->thread_name_str, name_size,
+ "%s", (char *)&tcb.dat[name_offset - 8]);
+ } else {
+ thread->thread_name_str = malloc(sizeof("None"));
+ strcpy(thread->thread_name_str, "None");
+ }
+
+ tcb_addr = tcb.flink;
+ }
+ }
+ rtos->thread_count = thread_count;
+
+ return 0;
+}
+
+
+/*
+ * thread_id = tcb address;
+ */
+static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
+ char **hex_reg_list) {
+ int retval;
+
+ *hex_reg_list = NULL;
+
+ /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4F */
+ bool cm4_fpu_enabled = false;
+ struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
+ if (is_armv7m(armv7m_target)) {
+ if (armv7m_target->fp_feature == FPv4_SP) {
+ /* Found ARM v7m target which includes a FPU */
+ uint32_t cpacr;
+
+ retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Could not read CPACR register to check FPU state");
+ return -1;
+ }
+
+ /* Check if CP10 and CP11 are set to full access. */
+ if (cpacr & 0x00F00000) {
+ /* Found target with enabled FPU */
+ cm4_fpu_enabled = 1;
+ }
+ }
+ }
+
+ const struct rtos_register_stacking *stacking;
+ if (cm4_fpu_enabled)
+ stacking = &nuttx_stacking_cortex_m_fpu;
+ else
+ stacking = &nuttx_stacking_cortex_m;
+
+ return rtos_generic_stack_read(rtos->target, stacking,
+ (uint32_t)thread_id + xcpreg_offset, hex_reg_list);
+}
+
+static int nuttx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+{
+ unsigned int i;
+
+ *symbol_list = (symbol_table_elem_t *) calloc(1,
+ sizeof(symbol_table_elem_t) * ARRAY_SIZE(nuttx_symbol_list));
+
+ for (i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++)
+ (*symbol_list)[i].symbol_name = nuttx_symbol_list[i];
+
+ return 0;
+}
+
+struct rtos_type nuttx_rtos = {
+ .name = "nuttx",
+ .detect_rtos = nuttx_detect_rtos,
+ .create = nuttx_create,
+ .update_threads = nuttx_update_threads,
+ .get_thread_reg_list = nuttx_get_thread_reg_list,
+ .get_symbol_list_to_lookup = nuttx_get_symbol_list_to_lookup,
+};
+
diff --git a/src/rtos/nuttx_header.h b/src/rtos/nuttx_header.h
new file mode 100644
index 0000000..00b0484
--- /dev/null
+++ b/src/rtos/nuttx_header.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+ * Copyright 2016,2017 Sony Video & Sound Products Inc. *
+ * Masatoshi Tateishi - Masatoshi.Tateishi@jp.sony.com *
+ * Masayuki Ishikawa - Masayuki.Ishikawa@jp.sony.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef OPENOCD_RTOS_NUTTX_HEADER_H
+#define OPENOCD_RTOS_NUTTX_HEADER_H
+
+/* gdb script to update the header file
+ according to kernel version and build option
+ before executing function awareness
+ kernel symbol must be loaded : symbol nuttx
+
+define awareness
+ set logging off
+ set logging file nuttx_header.h
+ set logging on
+
+ printf "#define PID %p\n",&((struct tcb_s *)(0))->pid
+ printf "#define XCPREG %p\n",&((struct tcb_s *)(0))->xcp.regs
+ printf "#define STATE %p\n",&((struct tcb_s *)(0))->task_state
+ printf "#define NAME %p\n",&((struct tcb_s *)(0))->name
+ printf "#define NAME_SIZE %d\n",sizeof(((struct tcb_s *)(0))->name)
+ end
+
+
+ OR ~/.gdbinit
+
+
+define hookpost-file
+
+ if &g_readytorun != 0
+ eval "monitor nuttx.pid_offset %d", &((struct tcb_s *)(0))->pid
+ eval "monitor nuttx.xcpreg_offset %d", &((struct tcb_s *)(0))->xcp.regs
+ eval "monitor nuttx.state_offset %d", &((struct tcb_s *)(0))->task_state
+ eval "monitor nuttx.name_offset %d", &((struct tcb_s *)(0))->name
+ eval "monitor nuttx.name_size %d", sizeof(((struct tcb_s *)(0))->name)
+ end
+
+end
+
+*/
+
+/* default offset */
+#define PID 0xc
+#define XCPREG 0x70
+#define STATE 0x19
+#define NAME 0xb8
+#define NAME_SIZE 32
+
+/* defconfig of nuttx */
+/* #define CONFIG_DISABLE_SIGNALS */
+#define CONFIG_DISABLE_MQUEUE
+/* #define CONFIG_PAGING */
+
+
+#endif /* OPENOCD_RTOS_NUTTX_HEADER_H */
diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c
index 4f23040..bd9da0d 100644
--- a/src/rtos/rtos.c
+++ b/src/rtos/rtos.c
@@ -35,6 +35,7 @@ extern struct rtos_type ChibiOS_rtos;
extern struct rtos_type embKernel_rtos;
extern struct rtos_type mqx_rtos;
extern struct rtos_type uCOS_III_rtos;
+extern struct rtos_type nuttx_rtos;
extern struct rtos_type riscv_rtos;
static struct rtos_type *rtos_types[] = {
@@ -46,6 +47,7 @@ static struct rtos_type *rtos_types[] = {
&embKernel_rtos,
&mqx_rtos,
&uCOS_III_rtos,
+ &nuttx_rtos,
&riscv_rtos,
NULL
};
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index b62899d..eb4eea9 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -936,6 +936,7 @@ static int gdb_new_connection(struct connection *connection)
target = get_target_from_connection(connection);
connection->priv = gdb_connection;
+ connection->cmd_ctx->current_target = target;
/* initialize gdb connection information */
gdb_connection->buf_p = gdb_connection->buffer;
@@ -1359,7 +1360,8 @@ static int gdb_set_register_packet(struct connection *connection,
int chars = (DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2);
if ((unsigned int)chars != strlen(separator + 1)) {
- LOG_ERROR("gdb sent a packet with wrong register size");
+ LOG_ERROR("gdb sent %zu bits for a %d-bit register (%s)",
+ strlen(separator + 1) * 4, chars * 4, reg_list[reg_num]->name);
free(bin_buf);
return ERROR_SERVER_REMOTE_CLOSED;
}
@@ -3020,9 +3022,12 @@ static int gdb_v_packet(struct connection *connection,
static int gdb_detach(struct connection *connection)
{
- target_call_event_callbacks(get_target_from_connection(connection),
- TARGET_EVENT_GDB_DETACH);
-
+ /*
+ * Only reply "OK" to GDB
+ * it will close the connection and this will trigger a call to
+ * gdb_connection_closed() that will in turn trigger the event
+ * TARGET_EVENT_GDB_DETACH
+ */
return gdb_put_packet(connection, "OK", 2);
}
diff --git a/src/server/server.c b/src/server/server.c
index 4e80656..f8273d4 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -46,9 +46,13 @@
static struct service *services;
-/* shutdown_openocd == 1: exit the main event loop, and quit the
- * debugger; 2: quit with non-zero return code */
-static int shutdown_openocd;
+enum shutdown_reason {
+ CONTINUE_MAIN_LOOP, /* stay in main event loop */
+ SHUTDOWN_REQUESTED, /* set by shutdown command; exit the event loop and quit the debugger */
+ SHUTDOWN_WITH_ERROR_CODE, /* set by shutdown command; quit with non-zero return code */
+ SHUTDOWN_WITH_SIGNAL_CODE /* set by sig_handler; exec shutdown then exit with signal as return code */
+};
+static enum shutdown_reason shutdown_openocd = CONTINUE_MAIN_LOOP;
/* store received signal to exit application by killing ourselves */
static int last_signal;
@@ -360,6 +364,35 @@ static void remove_connections(struct service *service)
}
}
+int remove_service(const char *name, const char *port)
+{
+ struct service *tmp;
+ struct service *prev;
+
+ prev = services;
+
+ for (tmp = services; tmp; prev = tmp, tmp = tmp->next) {
+ if (!strcmp(tmp->name, name) && !strcmp(tmp->port, port)) {
+ remove_connections(tmp);
+
+ if (tmp == services)
+ services = tmp->next;
+ else
+ prev->next = tmp->next;
+
+ if (tmp->type != CONNECTION_STDINOUT)
+ close_socket(tmp->fd);
+
+ free(tmp->priv);
+ free_service(tmp);
+
+ return ERROR_OK;
+ }
+ }
+
+ return ERROR_OK;
+}
+
static int remove_services(void)
{
struct service *c = services;
@@ -413,7 +446,7 @@ int server_loop(struct command_context *command_context)
LOG_ERROR("couldn't set SIGPIPE to SIG_IGN");
#endif
- while (!shutdown_openocd) {
+ while (shutdown_openocd == CONTINUE_MAIN_LOOP) {
/* monitor sockets for activity */
fd_max = 0;
FD_ZERO(&read_fds);
@@ -505,7 +538,7 @@ int server_loop(struct command_context *command_context)
for (service = services; service; service = service->next) {
/* handle new connections on listeners */
if ((service->fd != -1)
- && (FD_ISSET(service->fd, &read_fds))) {
+ && (FD_ISSET(service->fd, &read_fds))) {
if (service->max_connections != 0)
add_connection(service, command_context);
else {
@@ -537,7 +570,7 @@ int server_loop(struct command_context *command_context)
service->type == CONNECTION_STDINOUT) {
/* if connection uses a pipe then
* shutdown openocd on error */
- shutdown_openocd = 1;
+ shutdown_openocd = SHUTDOWN_REQUESTED;
}
remove_connection(service, c);
LOG_INFO("dropped '%s' connection",
@@ -555,29 +588,48 @@ int server_loop(struct command_context *command_context)
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
- shutdown_openocd = 1;
+ shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE;
}
#endif
}
- return shutdown_openocd != 2 ? ERROR_OK : ERROR_FAIL;
+ /* when quit for signal or CTRL-C, run (eventually user implemented) "shutdown" */
+ if (shutdown_openocd == SHUTDOWN_WITH_SIGNAL_CODE)
+ command_run_line(command_context, "shutdown");
+
+ return shutdown_openocd == SHUTDOWN_WITH_ERROR_CODE ? ERROR_FAIL : ERROR_OK;
}
+void sig_handler(int sig)
+{
+ /* store only first signal that hits us */
+ if (shutdown_openocd == CONTINUE_MAIN_LOOP) {
+ shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE;
+ last_signal = sig;
+ LOG_DEBUG("Terminating on Signal %d", sig);
+ } else
+ LOG_DEBUG("Ignored extra Signal %d", sig);
+}
+
+
#ifdef _WIN32
BOOL WINAPI ControlHandler(DWORD dwCtrlType)
{
- shutdown_openocd = 1;
+ shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE;
return TRUE;
}
-#endif
-
-void sig_handler(int sig)
+#else
+static void sigkey_handler(int sig)
{
- /* store only first signal that hits us */
- if (!last_signal)
- last_signal = sig;
- shutdown_openocd = 1;
+ /* ignore keystroke generated signals if not in foreground process group */
+
+ if (tcgetpgrp(STDIN_FILENO) > 0)
+ sig_handler(sig);
+ else
+ LOG_DEBUG("Ignored Signal %d", sig);
}
+#endif
+
int server_preinit(void)
{
@@ -600,8 +652,13 @@ int server_preinit(void)
SetConsoleCtrlHandler(ControlHandler, TRUE);
signal(SIGBREAK, sig_handler);
-#endif
signal(SIGINT, sig_handler);
+#else
+ signal(SIGHUP, sig_handler);
+ signal(SIGPIPE, sig_handler);
+ signal(SIGQUIT, sigkey_handler);
+ signal(SIGINT, sigkey_handler);
+#endif
signal(SIGTERM, sig_handler);
signal(SIGABRT, sig_handler);
@@ -682,11 +739,11 @@ COMMAND_HANDLER(handle_shutdown_command)
{
LOG_USER("shutdown command invoked");
- shutdown_openocd = 1;
+ shutdown_openocd = SHUTDOWN_REQUESTED;
if (CMD_ARGC == 1) {
if (!strcmp(CMD_ARGV[0], "error")) {
- shutdown_openocd = 2;
+ shutdown_openocd = SHUTDOWN_WITH_ERROR_CODE;
return ERROR_FAIL;
}
}
@@ -743,7 +800,7 @@ static const struct command_registration server_command_handlers[] = {
.mode = COMMAND_ANY,
.usage = "[name]",
.help = "Specify address by name on which to listen for "
- "incoming TCP/IP connections",
+ "incoming TCP/IP connections",
},
COMMAND_REGISTRATION_DONE
};
diff --git a/src/server/server.h b/src/server/server.h
index d4eae94..96e0b48 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -78,6 +78,7 @@ int add_service(char *name, const char *port,
int max_connections, new_connection_handler_t new_connection_handler,
input_handler_t in_handler, connection_closed_handler_t close_handler,
void *priv);
+int remove_service(const char *name, const char *port);
int server_preinit(void);
int server_init(struct command_context *cmd_ctx);
diff --git a/src/target/aarch64.c b/src/target/aarch64.c
index df1e49c..454de9e 100644
--- a/src/target/aarch64.c
+++ b/src/target/aarch64.c
@@ -28,6 +28,7 @@
#include "target_type.h"
#include "armv8_opcodes.h"
#include "armv8_cache.h"
+#include "arm_semihosting.h"
#include <helper/time_support.h>
enum restart_mode {
@@ -522,6 +523,9 @@ static int aarch64_poll(struct target *target)
if (target->smp)
update_halt_gdb(target, debug_reason);
+ if (arm_semihosting(target, &retval) != 0)
+ return retval;
+
switch (prev_target_state) {
case TARGET_RUNNING:
case TARGET_UNKNOWN:
@@ -543,6 +547,9 @@ static int aarch64_poll(struct target *target)
static int aarch64_halt(struct target *target)
{
+ struct armv8_common *armv8 = target_to_armv8(target);
+ armv8->last_run_control_op = ARMV8_RUNCONTROL_HALT;
+
if (target->smp)
return aarch64_halt_smp(target, false);
@@ -831,6 +838,9 @@ static int aarch64_resume(struct target *target, int current,
int retval = 0;
uint64_t addr = address;
+ struct armv8_common *armv8 = target_to_armv8(target);
+ armv8->last_run_control_op = ARMV8_RUNCONTROL_RESUME;
+
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
@@ -1069,6 +1079,8 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres
int retval;
uint32_t edecr;
+ armv8->last_run_control_op = ARMV8_RUNCONTROL_STEP;
+
if (target->state != TARGET_HALTED) {
LOG_WARNING("target not halted");
return ERROR_TARGET_NOT_HALTED;
@@ -1682,17 +1694,19 @@ static int aarch64_deassert_reset(struct target *target)
if (retval != ERROR_OK)
return retval;
+ retval = aarch64_init_debug_access(target);
+ if (retval != ERROR_OK)
+ return retval;
+
if (target->reset_halt) {
if (target->state != TARGET_HALTED) {
LOG_WARNING("%s: ran after reset and before halt ...",
target_name(target));
retval = target_halt(target);
- if (retval != ERROR_OK)
- return retval;
}
}
- return aarch64_init_debug_access(target);
+ return retval;
}
static int aarch64_write_cpu_memory_slow(struct target *target,
@@ -2351,6 +2365,7 @@ static int aarch64_init_target(struct command_context *cmd_ctx,
struct target *target)
{
/* examine_first() does a bunch of this */
+ arm_semihosting_init(target);
return ERROR_OK;
}
diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c
index 0de272d..b520223 100644
--- a/src/target/adi_v5_swd.c
+++ b/src/target/adi_v5_swd.c
@@ -276,6 +276,16 @@ static int swd_run(struct adiv5_dap *dap)
return swd_run_inner(dap);
}
+/** Put the SWJ-DP back to JTAG mode */
+static void swd_quit(struct adiv5_dap *dap)
+{
+ const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
+
+ swd->switch_seq(SWD_TO_JTAG);
+ /* flush the queue before exit */
+ swd->run();
+}
+
const struct dap_ops swd_dap_ops = {
.connect = swd_connect,
.queue_dp_read = swd_queue_dp_read,
@@ -284,6 +294,7 @@ const struct dap_ops swd_dap_ops = {
.queue_ap_write = swd_queue_ap_write,
.queue_ap_abort = swd_queue_ap_abort,
.run = swd_run,
+ .quit = swd_quit,
};
/*
diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c
index d0a58bd..302ea78 100644
--- a/src/target/arm_adi_v5.c
+++ b/src/target/arm_adi_v5.c
@@ -102,8 +102,10 @@ static int mem_ap_setup_csw(struct adiv5_ap *ap, uint32_t csw)
if (csw != ap->csw_value) {
/* LOG_DEBUG("DAP: Set CSW %x",csw); */
int retval = dap_queue_ap_write(ap, MEM_AP_REG_CSW, csw);
- if (retval != ERROR_OK)
+ if (retval != ERROR_OK) {
+ ap->csw_value = 0;
return retval;
+ }
ap->csw_value = csw;
}
return ERROR_OK;
@@ -114,8 +116,10 @@ static int mem_ap_setup_tar(struct adiv5_ap *ap, uint32_t tar)
if (!ap->tar_valid || tar != ap->tar_value) {
/* LOG_DEBUG("DAP: Set TAR %x",tar); */
int retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR, tar);
- if (retval != ERROR_OK)
+ if (retval != ERROR_OK) {
+ ap->tar_valid = false;
return retval;
+ }
ap->tar_value = tar;
ap->tar_valid = true;
}
@@ -1612,13 +1616,12 @@ COMMAND_HANDLER(dap_memaccess_command)
COMMAND_HANDLER(dap_apsel_command)
{
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
- uint32_t apsel, apid;
- int retval;
+ uint32_t apsel;
switch (CMD_ARGC) {
case 0:
- apsel = dap->apsel;
- break;
+ command_print(CMD_CTX, "%" PRIi32, dap->apsel);
+ return ERROR_OK;
case 1:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
/* AP address is in bits 31:24 of DP_SELECT */
@@ -1630,18 +1633,7 @@ COMMAND_HANDLER(dap_apsel_command)
}
dap->apsel = apsel;
-
- retval = dap_queue_ap_read(dap_ap(dap, apsel), AP_REG_IDR, &apid);
- if (retval != ERROR_OK)
- return retval;
- retval = dap_run(dap);
- if (retval != ERROR_OK)
- return retval;
-
- command_print(CMD_CTX, "ap %" PRIi32 " selected, identification register 0x%8.8" PRIx32,
- apsel, apid);
-
- return retval;
+ return ERROR_OK;
}
COMMAND_HANDLER(dap_apcsw_command)
@@ -1722,6 +1714,7 @@ COMMAND_HANDLER(dap_apreg_command)
{
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
uint32_t apsel, reg, value;
+ struct adiv5_ap *ap;
int retval;
if (CMD_ARGC < 2 || CMD_ARGC > 3)
@@ -1731,6 +1724,7 @@ COMMAND_HANDLER(dap_apreg_command)
/* AP address is in bits 31:24 of DP_SELECT */
if (apsel >= 256)
return ERROR_COMMAND_SYNTAX_ERROR;
+ ap = dap_ap(dap, apsel);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg);
if (reg >= 256 || (reg & 3))
@@ -1738,9 +1732,21 @@ COMMAND_HANDLER(dap_apreg_command)
if (CMD_ARGC == 3) {
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value);
- retval = dap_queue_ap_write(dap_ap(dap, apsel), reg, value);
+ switch (reg) {
+ case MEM_AP_REG_CSW:
+ ap->csw_default = 0; /* invalid, force write */
+ retval = mem_ap_setup_csw(ap, value);
+ break;
+ case MEM_AP_REG_TAR:
+ ap->tar_valid = false; /* invalid, force write */
+ retval = mem_ap_setup_tar(ap, value);
+ break;
+ default:
+ retval = dap_queue_ap_write(ap, reg, value);
+ break;
+ }
} else {
- retval = dap_queue_ap_read(dap_ap(dap, apsel), reg, &value);
+ retval = dap_queue_ap_read(ap, reg, &value);
}
if (retval == ERROR_OK)
retval = dap_run(dap);
@@ -1754,6 +1760,37 @@ COMMAND_HANDLER(dap_apreg_command)
return retval;
}
+COMMAND_HANDLER(dap_dpreg_command)
+{
+ struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
+ uint32_t reg, value;
+ int retval;
+
+ if (CMD_ARGC < 1 || CMD_ARGC > 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], reg);
+ if (reg >= 256 || (reg & 3))
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (CMD_ARGC == 2) {
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
+ retval = dap_queue_dp_write(dap, reg, value);
+ } else {
+ retval = dap_queue_dp_read(dap, reg, &value);
+ }
+ if (retval == ERROR_OK)
+ retval = dap_run(dap);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (CMD_ARGC == 1)
+ command_print(CMD_CTX, "0x%08" PRIx32, value);
+
+ return retval;
+}
+
COMMAND_HANDLER(dap_ti_be_32_quirks_command)
{
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
@@ -1789,7 +1826,7 @@ const struct command_registration dap_instance_commands[] = {
{
.name = "apsel",
.handler = dap_apsel_command,
- .mode = COMMAND_EXEC,
+ .mode = COMMAND_ANY,
.help = "Set the currently selected AP (default 0) "
"and display the result",
.usage = "[ap_num]",
@@ -1797,7 +1834,7 @@ const struct command_registration dap_instance_commands[] = {
{
.name = "apcsw",
.handler = dap_apcsw_command,
- .mode = COMMAND_EXEC,
+ .mode = COMMAND_ANY,
.help = "Set CSW default bits",
.usage = "[value [mask]]",
},
@@ -1819,6 +1856,14 @@ const struct command_registration dap_instance_commands[] = {
.usage = "ap_num reg [value]",
},
{
+ .name = "dpreg",
+ .handler = dap_dpreg_command,
+ .mode = COMMAND_EXEC,
+ .help = "read/write a register from DP "
+ "(reg is byte address (bank << 4 | reg) of a word register, like 0 4 8...)",
+ .usage = "reg [value]",
+ },
+ {
.name = "baseaddr",
.handler = dap_baseaddr_command,
.mode = COMMAND_EXEC,
diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h
index 22c3166..883ac8b 100644
--- a/src/target/arm_adi_v5.h
+++ b/src/target/arm_adi_v5.h
@@ -286,6 +286,9 @@ struct dap_ops {
/** Executes all queued DAP operations but doesn't check
* sticky error conditions */
int (*sync)(struct adiv5_dap *dap);
+
+ /** Optional; called at OpenOCD exit */
+ void (*quit)(struct adiv5_dap *dap);
};
/*
diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c
index 8c08180..3be4d71 100644
--- a/src/target/arm_dap.c
+++ b/src/target/arm_dap.c
@@ -132,8 +132,13 @@ static int dap_init_all(void)
int dap_cleanup_all(void)
{
struct arm_dap_object *obj, *tmp;
+ struct adiv5_dap *dap;
list_for_each_entry_safe(obj, tmp, &all_dap, lh) {
+ dap = &obj->dap;
+ if (dap->ops && dap->ops->quit)
+ dap->ops->quit(dap);
+
free(obj->name);
free(obj);
}
diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c
index 17948d6..8eb8194 100644
--- a/src/target/arm_disassembler.c
+++ b/src/target/arm_disassembler.c
@@ -118,15 +118,78 @@ static int evaluate_pld(uint32_t opcode,
uint32_t address, struct arm_instruction *instruction)
{
/* PLD */
- if ((opcode & 0x0d70f000) == 0x0550f000) {
+ if ((opcode & 0x0d30f000) == 0x0510f000) {
+ uint8_t Rn;
+ uint8_t U;
+ unsigned offset;
+
instruction->type = ARM_PLD;
+ Rn = (opcode & 0xf0000) >> 16;
+ U = (opcode & 0x00800000) >> 23;
+ if (Rn == 0xf) {
+ /* literal */
+ offset = opcode & 0x0fff;
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD %s%d",
+ address, opcode, U ? "" : "-", offset);
+ } else {
+ uint8_t I, R;
- snprintf(instruction->text,
- 128,
- "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD ...TODO...",
- address,
- opcode);
+ I = (opcode & 0x02000000) >> 25;
+ R = (opcode & 0x00400000) >> 22;
+
+ if (I) {
+ /* register PLD{W} [<Rn>,+/-<Rm>{, <shift>}] */
+ offset = (opcode & 0x0F80) >> 7;
+ uint8_t Rm;
+ Rm = opcode & 0xf;
+
+ if (offset == 0) {
+ /* No shift */
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d]",
+ address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm);
+
+ } else {
+ uint8_t shift;
+ shift = (opcode & 0x60) >> 5;
+ if (shift == 0x0) {
+ /* LSL */
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, LSL #0x%x)",
+ address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset);
+ } else if (shift == 0x1) {
+ /* LSR */
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, LSR #0x%x)",
+ address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset);
+ } else if (shift == 0x2) {
+ /* ASR */
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, ASR #0x%x)",
+ address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset);
+ } else if (shift == 0x3) {
+ /* ROR */
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, ROR #0x%x)",
+ address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset);
+ }
+ }
+ } else {
+ /* immediate PLD{W} [<Rn>, #+/-<imm12>] */
+ offset = opcode & 0x0fff;
+ if (offset == 0) {
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d]",
+ address, opcode, R ? "" : "W", Rn);
+ } else {
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, #%s%d]",
+ address, opcode, R ? "" : "W", Rn, U ? "" : "-", offset);
+ }
+ }
+ }
return ERROR_OK;
}
/* DSB */
diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c
index 57f3139..9117a74 100644
--- a/src/target/arm_semihosting.c
+++ b/src/target/arm_semihosting.c
@@ -46,6 +46,7 @@
#include "arm7_9_common.h"
#include "armv7m.h"
#include "armv7a.h"
+#include "armv8.h"
#include "cortex_m.h"
#include "register.h"
#include "arm_opcodes.h"
@@ -55,10 +56,35 @@
#include <helper/log.h>
#include <sys/stat.h>
+static int arm_semihosting_resume(struct target *target, int *retval)
+{
+ if (is_armv8(target_to_armv8(target))) {
+ struct armv8_common *armv8 = target_to_armv8(target);
+ if (armv8->last_run_control_op == ARMV8_RUNCONTROL_RESUME) {
+ *retval = target_resume(target, 1, 0, 0, 0);
+ if (*retval != ERROR_OK) {
+ LOG_ERROR("Failed to resume target");
+ return 0;
+ }
+ } else if (armv8->last_run_control_op == ARMV8_RUNCONTROL_STEP)
+ target->debug_reason = DBG_REASON_SINGLESTEP;
+ } else {
+ *retval = target_resume(target, 1, 0, 0, 0);
+ if (*retval != ERROR_OK) {
+ LOG_ERROR("Failed to resume target");
+ return 0;
+ }
+ }
+ return 1;
+}
+
static int post_result(struct target *target)
{
struct arm *arm = target_to_arm(target);
+ if (!target->semihosting)
+ return ERROR_FAIL;
+
/* REVISIT this looks wrong ... ARM11 and Cortex-A8
* should work this way at least sometimes.
*/
@@ -88,6 +114,16 @@ static int post_result(struct target *target)
if (spsr & 0x20)
arm->core_state = ARM_STATE_THUMB;
+ } else if (is_armv8(target_to_armv8(target))) {
+ if (arm->core_state == ARM_STATE_AARCH64) {
+ /* return value in R0 */
+ buf_set_u64(arm->core_cache->reg_list[0].value, 0, 64, target->semihosting->result);
+ arm->core_cache->reg_list[0].dirty = 1;
+
+ uint64_t pc = buf_get_u64(arm->core_cache->reg_list[32].value, 0, 64);
+ buf_set_u64(arm->pc->value, 0, 64, pc + 4);
+ arm->pc->dirty = 1;
+ }
} else {
/* resume execution, this will be pc+2 to skip over the
* bkpt instruction */
@@ -235,6 +271,24 @@ int arm_semihosting(struct target *target, int *retval)
/* bkpt 0xAB */
if (insn != 0xBEAB)
return 0;
+ } else if (is_armv8(target_to_armv8(target))) {
+ if (target->debug_reason != DBG_REASON_BREAKPOINT)
+ return 0;
+
+ if (arm->core_state == ARM_STATE_AARCH64) {
+ uint32_t insn = 0;
+ r = arm->pc;
+ uint64_t pc64 = buf_get_u64(r->value, 0, 64);
+ *retval = target_read_u32(target, pc64, &insn);
+
+ if (*retval != ERROR_OK)
+ return 1;
+
+ /* bkpt 0xAB */
+ if (insn != 0xD45E0000)
+ return 0;
+ } else
+ return 1;
} else {
LOG_ERROR("Unsupported semi-hosting Target");
return 0;
@@ -244,13 +298,18 @@ int arm_semihosting(struct target *target, int *retval)
* operation to complete.
*/
if (!semihosting->hit_fileio) {
- /* TODO: update for 64-bits */
- uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32);
- uint32_t r1 = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32);
-
- semihosting->op = r0;
- semihosting->param = r1;
- semihosting->word_size_bytes = 4;
+ if (is_armv8(target_to_armv8(target)) &&
+ arm->core_state == ARM_STATE_AARCH64) {
+ /* Read op and param from register x0 and x1 respectively. */
+ semihosting->op = buf_get_u64(arm->core_cache->reg_list[0].value, 0, 64);
+ semihosting->param = buf_get_u64(arm->core_cache->reg_list[1].value, 0, 64);
+ semihosting->word_size_bytes = 8;
+ } else {
+ /* Read op and param from register r0 and r1 respectively. */
+ semihosting->op = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32);
+ semihosting->param = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32);
+ semihosting->word_size_bytes = 4;
+ }
/* Check for ARM operation numbers. */
if (0 <= semihosting->op && semihosting->op <= 0x31) {
@@ -265,19 +324,11 @@ int arm_semihosting(struct target *target, int *retval)
}
}
- /* Post result to target if we are not waiting on a fileio
+ /* Resume if target it is resumable and we are not waiting on a fileio
* operation to complete:
*/
- if (semihosting->is_resumable && !semihosting->hit_fileio) {
- /* Resume right after the BRK instruction. */
- *retval = target_resume(target, 1, 0, 0, 0);
- if (*retval != ERROR_OK) {
- LOG_ERROR("Failed to resume target");
- return 0;
- }
-
- return 1;
- }
+ if (semihosting->is_resumable && !semihosting->hit_fileio)
+ return arm_semihosting_resume(target, retval);
return 0;
}
diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c
index 5ee8ead..96a63e4 100644
--- a/src/target/armv4_5.c
+++ b/src/target/armv4_5.c
@@ -752,7 +752,7 @@ int arm_arch_state(struct target *target)
}
/* avoid filling log waiting for fileio reply */
- if (target->semihosting->hit_fileio)
+ if (target->semihosting && target->semihosting->hit_fileio)
return ERROR_OK;
LOG_USER("target halted in %s state due to %s, current mode: %s\n"
@@ -762,8 +762,8 @@ int arm_arch_state(struct target *target)
arm_mode_name(arm->core_mode),
buf_get_u32(arm->cpsr->value, 0, 32),
buf_get_u32(arm->pc->value, 0, 32),
- target->semihosting->is_active ? ", semihosting" : "",
- target->semihosting->is_fileio ? " fileio" : "");
+ (target->semihosting && target->semihosting->is_active) ? ", semihosting" : "",
+ (target->semihosting && target->semihosting->is_fileio) ? " fileio" : "");
return ERROR_OK;
}
diff --git a/src/target/armv7a.c b/src/target/armv7a.c
index fab7363..eecfa70 100644
--- a/src/target/armv7a.c
+++ b/src/target/armv7a.c
@@ -124,7 +124,7 @@ done:
return retval;
}
-static int armv7a_read_ttbcr(struct target *target)
+int armv7a_read_ttbcr(struct target *target)
{
struct armv7a_common *armv7a = target_to_armv7a(target);
struct arm_dpm *dpm = armv7a->arm.dpm;
@@ -554,9 +554,6 @@ int armv7a_identify_cache(struct target *target)
struct armv7a_cache_common *cache =
&(armv7a->armv7a_mmu.armv7a_cache);
- if (!armv7a->is_armv7r)
- armv7a_read_ttbcr(target);
-
retval = dpm->prepare(dpm);
if (retval != ERROR_OK)
goto done;
@@ -729,8 +726,6 @@ int armv7a_arch_state(struct target *target)
arm_arch_state(target);
- armv7a_read_ttbcr(target);
-
if (armv7a->is_armv7r) {
LOG_USER("D-Cache: %s, I-Cache: %s",
state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled],
diff --git a/src/target/armv7a.h b/src/target/armv7a.h
index 33f6f5d..57779c6 100644
--- a/src/target/armv7a.h
+++ b/src/target/armv7a.h
@@ -194,6 +194,7 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val);
int armv7a_handle_cache_info_command(struct command_context *cmd_ctx,
struct armv7a_cache_common *armv7a_cache);
+int armv7a_read_ttbcr(struct target *target);
extern const struct command_registration armv7a_command_handlers[];
diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c
index 3e5f8d6..7435aab 100644
--- a/src/target/armv7a_cache.c
+++ b/src/target/armv7a_cache.c
@@ -70,6 +70,7 @@ static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cach
LOG_DEBUG("cl %" PRId32, cl);
do {
+ keep_alive();
c_way = size->way;
do {
uint32_t value = (c_index << size->index_shift)
@@ -89,6 +90,7 @@ static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cach
} while (c_index >= 0);
done:
+ keep_alive();
return retval;
}
@@ -164,7 +166,7 @@ int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
uint32_t linelen = armv7a_cache->dminline;
uint32_t va_line, va_end;
- int retval;
+ int retval, i = 0;
retval = armv7a_l1_d_cache_sanity_check(target);
if (retval != ERROR_OK)
@@ -198,6 +200,8 @@ int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
}
while (va_line < va_end) {
+ if ((i++ & 0x3f) == 0)
+ keep_alive();
/* DCIMVAC - Invalidate data cache line by VA to PoC. */
retval = dpm->instr_write_data_r0(dpm,
ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line);
@@ -206,11 +210,13 @@ int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
va_line += linelen;
}
+ keep_alive();
dpm->finish(dpm);
return retval;
done:
LOG_ERROR("d-cache invalidate failed");
+ keep_alive();
dpm->finish(dpm);
return retval;
@@ -224,7 +230,7 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
uint32_t linelen = armv7a_cache->dminline;
uint32_t va_line, va_end;
- int retval;
+ int retval, i = 0;
retval = armv7a_l1_d_cache_sanity_check(target);
if (retval != ERROR_OK)
@@ -238,6 +244,8 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
va_end = virt + size;
while (va_line < va_end) {
+ if ((i++ & 0x3f) == 0)
+ keep_alive();
/* DCCMVAC - Data Cache Clean by MVA to PoC */
retval = dpm->instr_write_data_r0(dpm,
ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line);
@@ -246,11 +254,13 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
va_line += linelen;
}
+ keep_alive();
dpm->finish(dpm);
return retval;
done:
LOG_ERROR("d-cache invalidate failed");
+ keep_alive();
dpm->finish(dpm);
return retval;
@@ -264,7 +274,7 @@ int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
uint32_t linelen = armv7a_cache->dminline;
uint32_t va_line, va_end;
- int retval;
+ int retval, i = 0;
retval = armv7a_l1_d_cache_sanity_check(target);
if (retval != ERROR_OK)
@@ -278,6 +288,8 @@ int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
va_end = virt + size;
while (va_line < va_end) {
+ if ((i++ & 0x3f) == 0)
+ keep_alive();
/* DCCIMVAC */
retval = dpm->instr_write_data_r0(dpm,
ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
@@ -286,11 +298,13 @@ int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
va_line += linelen;
}
+ keep_alive();
dpm->finish(dpm);
return retval;
done:
LOG_ERROR("d-cache invalidate failed");
+ keep_alive();
dpm->finish(dpm);
return retval;
@@ -342,7 +356,7 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
&armv7a->armv7a_mmu.armv7a_cache;
uint32_t linelen = armv7a_cache->iminline;
uint32_t va_line, va_end;
- int retval;
+ int retval, i = 0;
retval = armv7a_l1_i_cache_sanity_check(target);
if (retval != ERROR_OK)
@@ -356,6 +370,8 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
va_end = virt + size;
while (va_line < va_end) {
+ if ((i++ & 0x3f) == 0)
+ keep_alive();
/* ICIMVAU - Invalidate instruction cache by VA to PoU. */
retval = dpm->instr_write_data_r0(dpm,
ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line);
@@ -368,10 +384,13 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
goto done;
va_line += linelen;
}
+ keep_alive();
+ dpm->finish(dpm);
return retval;
done:
LOG_ERROR("i-cache invalidate failed");
+ keep_alive();
dpm->finish(dpm);
return retval;
diff --git a/src/target/armv7m.c b/src/target/armv7m.c
index 1b4e5b1..7d3bd73 100644
--- a/src/target/armv7m.c
+++ b/src/target/armv7m.c
@@ -541,7 +541,7 @@ int armv7m_arch_state(struct target *target)
uint32_t ctrl, sp;
/* avoid filling log waiting for fileio reply */
- if (target->semihosting->hit_fileio)
+ if (target->semihosting && target->semihosting->hit_fileio)
return ERROR_OK;
ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
@@ -556,8 +556,8 @@ int armv7m_arch_state(struct target *target)
buf_get_u32(arm->pc->value, 0, 32),
(ctrl & 0x02) ? 'p' : 'm',
sp,
- target->semihosting->is_active ? ", semihosting" : "",
- target->semihosting->is_fileio ? " fileio" : "");
+ (target->semihosting && target->semihosting->is_active) ? ", semihosting" : "",
+ (target->semihosting && target->semihosting->is_fileio) ? " fileio" : "");
return ERROR_OK;
}
diff --git a/src/target/armv7m_trace.c b/src/target/armv7m_trace.c
index c1e4f5b..62f0f8e 100644
--- a/src/target/armv7m_trace.c
+++ b/src/target/armv7m_trace.c
@@ -62,7 +62,7 @@ int armv7m_trace_tpiu_config(struct target *target)
target_unregister_timer_callback(armv7m_poll_trace, target);
- retval = adapter_config_trace(trace_config->config_type == INTERNAL,
+ retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL,
trace_config->pin_protocol,
trace_config->port_size,
&trace_config->trace_freq);
@@ -83,7 +83,7 @@ int armv7m_trace_tpiu_config(struct target *target)
trace_config->trace_freq, trace_config->traceclkin_freq,
trace_freq);
trace_config->trace_freq = trace_freq;
- retval = adapter_config_trace(trace_config->config_type == INTERNAL,
+ retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL,
trace_config->pin_protocol,
trace_config->port_size,
&trace_config->trace_freq);
@@ -115,7 +115,7 @@ int armv7m_trace_tpiu_config(struct target *target)
if (retval != ERROR_OK)
return retval;
- if (trace_config->config_type == INTERNAL)
+ if (trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL)
target_register_timer_callback(armv7m_poll_trace, 1, 1, target);
target_call_event_callbacks(target, TARGET_EVENT_TRACE_CONFIG);
@@ -173,7 +173,7 @@ COMMAND_HANDLER(handle_tpiu_config_command)
if (CMD_ARGC == cmd_idx + 1) {
close_trace_file(armv7m);
- armv7m->trace_config.config_type = DISABLED;
+ armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_DISABLED;
if (CMD_CTX->mode == COMMAND_EXEC)
return armv7m_trace_tpiu_config(target);
else
@@ -183,13 +183,13 @@ COMMAND_HANDLER(handle_tpiu_config_command)
!strcmp(CMD_ARGV[cmd_idx], "internal")) {
close_trace_file(armv7m);
- armv7m->trace_config.config_type = EXTERNAL;
+ armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_EXTERNAL;
if (!strcmp(CMD_ARGV[cmd_idx], "internal")) {
cmd_idx++;
if (CMD_ARGC == cmd_idx)
return ERROR_COMMAND_SYNTAX_ERROR;
- armv7m->trace_config.config_type = INTERNAL;
+ armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_INTERNAL;
if (strcmp(CMD_ARGV[cmd_idx], "-") != 0) {
armv7m->trace_config.trace_file = fopen(CMD_ARGV[cmd_idx], "ab");
@@ -204,7 +204,7 @@ COMMAND_HANDLER(handle_tpiu_config_command)
return ERROR_COMMAND_SYNTAX_ERROR;
if (!strcmp(CMD_ARGV[cmd_idx], "sync")) {
- armv7m->trace_config.pin_protocol = SYNC;
+ armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_SYNC;
cmd_idx++;
if (CMD_ARGC == cmd_idx)
@@ -213,9 +213,9 @@ COMMAND_HANDLER(handle_tpiu_config_command)
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[cmd_idx], armv7m->trace_config.port_size);
} else {
if (!strcmp(CMD_ARGV[cmd_idx], "manchester"))
- armv7m->trace_config.pin_protocol = ASYNC_MANCHESTER;
+ armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER;
else if (!strcmp(CMD_ARGV[cmd_idx], "uart"))
- armv7m->trace_config.pin_protocol = ASYNC_UART;
+ armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_UART;
else
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -237,7 +237,7 @@ COMMAND_HANDLER(handle_tpiu_config_command)
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.trace_freq);
cmd_idx++;
} else {
- if (armv7m->trace_config.config_type != INTERNAL) {
+ if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_INTERNAL) {
LOG_ERROR("Trace port frequency can't be omitted in external capture mode");
return ERROR_COMMAND_SYNTAX_ERROR;
}
diff --git a/src/target/armv7m_trace.h b/src/target/armv7m_trace.h
index 4f99394..c63f36d 100644
--- a/src/target/armv7m_trace.h
+++ b/src/target/armv7m_trace.h
@@ -27,15 +27,15 @@
*/
enum trace_config_type {
- DISABLED, /**< tracing is disabled */
- EXTERNAL, /**< trace output is captured externally */
- INTERNAL /**< trace output is handled by OpenOCD adapter driver */
+ TRACE_CONFIG_TYPE_DISABLED, /**< tracing is disabled */
+ TRACE_CONFIG_TYPE_EXTERNAL, /**< trace output is captured externally */
+ TRACE_CONFIG_TYPE_INTERNAL /**< trace output is handled by OpenOCD adapter driver */
};
-enum tpio_pin_protocol {
- SYNC, /**< synchronous trace output */
- ASYNC_MANCHESTER, /**< asynchronous output with Manchester coding */
- ASYNC_UART /**< asynchronous output with NRZ coding */
+enum tpiu_pin_protocol {
+ TPIU_PIN_PROTOCOL_SYNC, /**< synchronous trace output */
+ TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER, /**< asynchronous output with Manchester coding */
+ TPIU_PIN_PROTOCOL_ASYNC_UART /**< asynchronous output with NRZ coding */
};
enum itm_ts_prescaler {
@@ -50,7 +50,7 @@ struct armv7m_trace_config {
enum trace_config_type config_type;
/** Currently active trace output mode */
- enum tpio_pin_protocol pin_protocol;
+ enum tpiu_pin_protocol pin_protocol;
/** TPIU formatter enable/disable (in async mode) */
bool formatter;
/** Synchronous output port width */
diff --git a/src/target/armv8.c b/src/target/armv8.c
index 20f2b67..dfa2c67 100644
--- a/src/target/armv8.c
+++ b/src/target/armv8.c
@@ -1017,11 +1017,24 @@ int armv8_handle_cache_info_command(struct command_context *cmd_ctx,
return ERROR_OK;
}
+static int armv8_setup_semihosting(struct target *target, int enable)
+{
+ struct arm *arm = target_to_arm(target);
+
+ if (arm->core_state != ARM_STATE_AARCH64) {
+ LOG_ERROR("semihosting only supported in AArch64 state\n");
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
int armv8_init_arch_info(struct target *target, struct armv8_common *armv8)
{
struct arm *arm = &armv8->arm;
arm->arch_info = armv8;
target->arch_info = &armv8->arm;
+ arm->setup_semihosting = armv8_setup_semihosting;
/* target is useful in all function arm v4 5 compatible */
armv8->arm.target = target;
armv8->arm.common_magic = ARM_COMMON_MAGIC;
@@ -1050,7 +1063,7 @@ int armv8_aarch64_state(struct target *target)
armv8_mode_name(arm->core_mode),
buf_get_u32(arm->cpsr->value, 0, 32),
buf_get_u64(arm->pc->value, 0, 64),
- target->semihosting->is_active ? ", semihosting" : "");
+ (target->semihosting && target->semihosting->is_active) ? ", semihosting" : "");
return ERROR_OK;
}
diff --git a/src/target/armv8.h b/src/target/armv8.h
index b346462..dfd54ed 100644
--- a/src/target/armv8.h
+++ b/src/target/armv8.h
@@ -113,6 +113,12 @@ enum {
ARMV8_LAST_REG,
};
+enum run_control_op {
+ ARMV8_RUNCONTROL_UNKNOWN = 0,
+ ARMV8_RUNCONTROL_RESUME = 1,
+ ARMV8_RUNCONTROL_HALT = 2,
+ ARMV8_RUNCONTROL_STEP = 3,
+};
#define ARMV8_COMMON_MAGIC 0x0A450AAA
@@ -210,6 +216,9 @@ struct armv8_common {
struct arm_cti *cti;
+ /* last run-control command issued to this target (resume, halt, step) */
+ enum run_control_op last_run_control_op;
+
/* Direct processor core register read and writes */
int (*read_reg_u64)(struct armv8_common *armv8, int num, uint64_t *value);
int (*write_reg_u64)(struct armv8_common *armv8, int num, uint64_t value);
@@ -232,6 +241,11 @@ target_to_armv8(struct target *target)
return container_of(target->arch_info, struct armv8_common, arm);
}
+static inline bool is_armv8(struct armv8_common *armv8)
+{
+ return armv8->common_magic == ARMV8_COMMON_MAGIC;
+}
+
/* register offsets from armv8.debug_base */
#define CPUV8_DBG_MAINID0 0xD00
#define CPUV8_DBG_CPUFEATURE0 0xD20
diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c
index 8985051..4aae5e4 100644
--- a/src/target/cortex_a.c
+++ b/src/target/cortex_a.c
@@ -1297,6 +1297,9 @@ static int cortex_a_post_debug_entry(struct target *target)
LOG_DEBUG("cp15_control_reg: %8.8" PRIx32, cortex_a->cp15_control_reg);
cortex_a->cp15_control_reg_curr = cortex_a->cp15_control_reg;
+ if (!armv7a->is_armv7r)
+ armv7a_read_ttbcr(target);
+
if (armv7a->armv7a_mmu.armv7a_cache.info == -1)
armv7a_identify_cache(target);
@@ -3226,6 +3229,20 @@ static int cortex_a_virt2phys(struct target *target,
struct armv7a_common *armv7a = target_to_armv7a(target);
struct adiv5_dap *swjdp = armv7a->arm.dap;
uint8_t apsel = swjdp->apsel;
+ int mmu_enabled = 0;
+
+ /*
+ * If the MMU was not enabled at debug entry, there is no
+ * way of knowing if there was ever a valid configuration
+ * for it and thus it's not safe to enable it. In this case,
+ * just return the virtual address as physical.
+ */
+ cortex_a_mmu(target, &mmu_enabled);
+ if (!mmu_enabled) {
+ *phys = virt;
+ return ERROR_OK;
+ }
+
if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap->ap_num)) {
uint32_t ret;
retval = armv7a_mmu_translate_va(target,
@@ -3421,7 +3438,7 @@ static const struct command_registration cortex_a_exec_command_handlers[] = {
{
.name = "dacrfixup",
.handler = handle_cortex_a_dacrfixup_command,
- .mode = COMMAND_EXEC,
+ .mode = COMMAND_ANY,
.help = "set domain access control (DACR) to all-manager "
"on memory access",
.usage = "['on'|'off']",
diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c
index b6043fc..ca3dbec 100644
--- a/src/target/cortex_m.c
+++ b/src/target/cortex_m.c
@@ -165,7 +165,7 @@ static int cortex_m_single_step_core(struct target *target)
struct armv7m_common *armv7m = &cortex_m->armv7m;
int retval;
- /* Mask interrupts before clearing halt, if done already. This avoids
+ /* Mask interrupts before clearing halt, if not done already. This avoids
* Erratum 377497 (fixed in r1p0) where setting MASKINTS while clearing
* HALT can put the core into an unknown state.
*/
@@ -237,8 +237,11 @@ static int cortex_m_endreset_event(struct target *target)
return retval;
}
- /* clear any interrupt masking */
- cortex_m_write_debug_halt_mask(target, 0, C_MASKINTS);
+ /* Restore proper interrupt masking setting. */
+ if (cortex_m->isrmasking_mode == CORTEX_M_ISRMASK_ON)
+ cortex_m_write_debug_halt_mask(target, C_MASKINTS, 0);
+ else
+ cortex_m_write_debug_halt_mask(target, 0, C_MASKINTS);
/* Enable features controlled by ITM and DWT blocks, and catch only
* the vectors we were told to pay attention to.
@@ -1137,6 +1140,10 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint
breakpoint->set = fp_num + 1;
fpcr_value = breakpoint->address | 1;
if (cortex_m->fp_rev == 0) {
+ if (breakpoint->address > 0x1FFFFFFF) {
+ LOG_ERROR("Cortex-M Flash Patch Breakpoint rev.1 cannot handle HW breakpoint above address 0x1FFFFFFE");
+ return ERROR_FAIL;
+ }
uint32_t hilo;
hilo = (breakpoint->address & 0x2) ? FPCR_REPLACE_BKPT_HIGH : FPCR_REPLACE_BKPT_LOW;
fpcr_value = (fpcr_value & 0x1FFFFFFC) | hilo | 1;
@@ -2076,7 +2083,7 @@ int cortex_m_examine(struct target *target)
if (retval != ERROR_OK)
return retval;
- if (armv7m->trace_config.config_type != DISABLED) {
+ if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_DISABLED) {
armv7m_trace_tpiu_config(target);
armv7m_trace_itm_config(target);
}
@@ -2270,20 +2277,6 @@ static int cortex_m_verify_pointer(struct command_context *cmd_ctx,
* cortexm3_target structure, which is only used with CM3 targets.
*/
-static const struct {
- char name[10];
- unsigned mask;
-} vec_ids[] = {
- { "hard_err", VC_HARDERR, },
- { "int_err", VC_INTERR, },
- { "bus_err", VC_BUSERR, },
- { "state_err", VC_STATERR, },
- { "chk_err", VC_CHKERR, },
- { "nocp_err", VC_NOCPERR, },
- { "mm_err", VC_MMERR, },
- { "reset", VC_CORERESET, },
-};
-
COMMAND_HANDLER(handle_cortex_m_vector_catch_command)
{
struct target *target = get_current_target(CMD_CTX);
@@ -2292,6 +2285,20 @@ COMMAND_HANDLER(handle_cortex_m_vector_catch_command)
uint32_t demcr = 0;
int retval;
+ static const struct {
+ char name[10];
+ unsigned mask;
+ } vec_ids[] = {
+ { "hard_err", VC_HARDERR, },
+ { "int_err", VC_INTERR, },
+ { "bus_err", VC_BUSERR, },
+ { "state_err", VC_STATERR, },
+ { "chk_err", VC_CHKERR, },
+ { "nocp_err", VC_NOCPERR, },
+ { "mm_err", VC_MMERR, },
+ { "reset", VC_CORERESET, },
+ };
+
retval = cortex_m_verify_pointer(CMD_CTX, cortex_m);
if (retval != ERROR_OK)
return retval;
diff --git a/src/target/image.c b/src/target/image.c
index 9f56bea..0d98c57 100644
--- a/src/target/image.c
+++ b/src/target/image.c
@@ -1048,8 +1048,7 @@ int image_calculate_checksum(uint8_t *buffer, uint32_t nbytes, uint32_t *checksu
static bool first_init;
if (!first_init) {
/* Initialize the CRC table and the decoding table. */
- int i, j;
- unsigned int c;
+ unsigned int i, j, c;
for (i = 0; i < 256; i++) {
/* as per gdb */
for (c = i << 24, j = 8; j > 0; --j)
diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c
index 78718ca..20c707b 100644
--- a/src/target/mips_m4k.c
+++ b/src/target/mips_m4k.c
@@ -344,6 +344,8 @@ static int mips_m4k_assert_reset(struct target *target)
jtag_add_reset(1, 1);
else if (!srst_asserted)
jtag_add_reset(0, 1);
+ } else if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) {
+ target_handle_event(target, TARGET_EVENT_RESET_ASSERT);
} else {
if (mips_m4k->is_pic32mx) {
LOG_DEBUG("Using MTAP reset to reset processor...");
diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c
index 142b27f..db9aad3 100644
--- a/src/target/riscv/riscv-011.c
+++ b/src/target/riscv/riscv-011.c
@@ -240,6 +240,7 @@ static unsigned int slot_offset(const struct target *target, slot_t slot)
case SLOT1: return 5;
case SLOT_LAST: return info->dramsize-1;
}
+ break;
case 64:
switch (slot) {
case SLOT0: return 4;
@@ -1775,6 +1776,8 @@ static riscv_error_t handle_halt_routine(struct target *target)
break;
default:
assert(0);
+ LOG_ERROR("Got invalid register result %d", result);
+ goto error;
}
if (riscv_xlen(target) == 32) {
reg_cache_set(target, reg, data & 0xffffffff);
diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c
index beeb474..5920789 100644
--- a/src/target/semihosting_common.c
+++ b/src/target/semihosting_common.c
@@ -225,6 +225,10 @@ int semihosting_common(struct target *target)
else {
int fd = semihosting_get_field(target, 0, fields);
if (semihosting->is_fileio) {
+ if (fd == 0 || fd == 1 || fd == 2) {
+ semihosting->result = 0;
+ break;
+ }
semihosting->hit_fileio = true;
fileio_info->identifier = "close";
fileio_info->param_1 = fd;
@@ -445,8 +449,8 @@ int semihosting_common(struct target *target)
* - –1 if an error occurs.
*/
if (semihosting->is_fileio) {
- LOG_ERROR("SYS_FLEN not supported by semihosting fileio");
- return ERROR_FAIL;
+ semihosting->result = -1;
+ semihosting->sys_errno = EINVAL;
}
retval = semihosting_read_fields(target, 1, fields);
if (retval != ERROR_OK)
@@ -690,9 +694,19 @@ int semihosting_common(struct target *target)
/* TODO: implement the :semihosting-features special file.
* */
if (semihosting->is_fileio) {
- if (strcmp((char *)fn, ":tt") == 0)
- semihosting->result = 0;
- else {
+ if (strcmp((char *)fn, ":semihosting-features") == 0) {
+ semihosting->result = -1;
+ semihosting->sys_errno = EINVAL;
+ } else if (strcmp((char *)fn, ":tt") == 0) {
+ if (mode == 0)
+ semihosting->result = 0;
+ else if (mode == 4)
+ semihosting->result = 1;
+ else if (mode == 8)
+ semihosting->result = 2;
+ else
+ semihosting->result = -1;
+ } else {
semihosting->hit_fileio = true;
fileio_info->identifier = "open";
fileio_info->param_1 = addr;
@@ -1397,8 +1411,9 @@ static int semihosting_read_fields(struct target *target, size_t number,
uint8_t *fields)
{
struct semihosting *semihosting = target->semihosting;
- return target_read_memory(target, semihosting->param,
- semihosting->word_size_bytes, number, fields);
+ /* Use 4-byte multiples to trigger fast memory access. */
+ return target_read_memory(target, semihosting->param, 4,
+ number * (semihosting->word_size_bytes / 4), fields);
}
/**
@@ -1408,8 +1423,9 @@ static int semihosting_write_fields(struct target *target, size_t number,
uint8_t *fields)
{
struct semihosting *semihosting = target->semihosting;
- return target_write_memory(target, semihosting->param,
- semihosting->word_size_bytes, number, fields);
+ /* Use 4-byte multiples to trigger fast memory access. */
+ return target_write_memory(target, semihosting->param, 4,
+ number * (semihosting->word_size_bytes / 4), fields);
}
/**
diff --git a/src/target/target.c b/src/target/target.c
index dc2cedd..8240e65 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -4146,8 +4146,9 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
* argv[3] = memory address
* argv[4] = count of times to read
*/
+
if (argc < 4 || argc > 5) {
- Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems [phys]");
+ Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]");
return JIM_ERR;
}
varname = Jim_GetString(argv[0], &len);
@@ -6430,7 +6431,7 @@ static const struct command_registration target_exec_command_handlers[] = {
.handler = handle_bp_command,
.mode = COMMAND_EXEC,
.help = "list or set hardware or software breakpoint",
- .usage = "<address> [<asid>]<length> ['hw'|'hw_ctx']",
+ .usage = "<address> [<asid>] <length> ['hw'|'hw_ctx']",
},
{
.name = "rbp",