diff options
Diffstat (limited to 'src')
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(®_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(®_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", |