diff options
Diffstat (limited to 'src')
227 files changed, 17964 insertions, 4490 deletions
diff --git a/src/flash/nand/core.c b/src/flash/nand/core.c index b9ac793..baef5d5 100644 --- a/src/flash/nand/core.c +++ b/src/flash/nand/core.c @@ -263,6 +263,7 @@ int nand_read_status(struct nand_device *nand, uint8_t *status) return ERROR_NAND_DEVICE_NOT_PROBED; /* Send read status command */ + /* FIXME: errors returned from nand->controller are mostly ignored! */ nand->controller->command(nand, NAND_CMD_STATUS); alive_sleep(1); @@ -301,7 +302,8 @@ static int nand_poll_ready(struct nand_device *nand, int timeout) int nand_probe(struct nand_device *nand) { uint8_t manufacturer_id, device_id; - uint8_t id_buff[6]; + uint8_t id_buff[6] = { 0 }; /* zero buff to silence false warning + * from clang static analyzer */ int retval; int i; @@ -392,19 +394,34 @@ int nand_probe(struct nand_device *nand) if (nand->device->page_size == 0 || nand->device->erase_size == 0) { if (nand->bus_width == 8) { - nand->controller->read_data(nand, id_buff + 3); - nand->controller->read_data(nand, id_buff + 4); - nand->controller->read_data(nand, id_buff + 5); + retval = nand->controller->read_data(nand, id_buff + 3); + if (retval != ERROR_OK) + return retval; + + retval = nand->controller->read_data(nand, id_buff + 4); + if (retval != ERROR_OK) + return retval; + + retval = nand->controller->read_data(nand, id_buff + 5); + if (retval != ERROR_OK) + return retval; + } else { uint16_t data_buf; - nand->controller->read_data(nand, &data_buf); + retval = nand->controller->read_data(nand, &data_buf); + if (retval != ERROR_OK) + return retval; id_buff[3] = data_buf; - nand->controller->read_data(nand, &data_buf); + retval = nand->controller->read_data(nand, &data_buf); + if (retval != ERROR_OK) + return retval; id_buff[4] = data_buf; - nand->controller->read_data(nand, &data_buf); + retval = nand->controller->read_data(nand, &data_buf); + if (retval != ERROR_OK) + return retval; id_buff[5] = data_buf >> 8; } } diff --git a/src/flash/nand/davinci.c b/src/flash/nand/davinci.c index 17e6f68..167b401 100644 --- a/src/flash/nand/davinci.c +++ b/src/flash/nand/davinci.c @@ -730,7 +730,7 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command) goto fail; } - info = calloc(1, sizeof *info); + info = calloc(1, sizeof(*info)); if (info == NULL) goto fail; diff --git a/src/flash/nand/mx3.c b/src/flash/nand/mx3.c index 5fdc923..da141b7 100644 --- a/src/flash/nand/mx3.c +++ b/src/flash/nand/mx3.c @@ -685,7 +685,6 @@ static int do_data_output(struct nand_device *nand) case 2 << 2: LOG_DEBUG("main area readed with more than 1 (incorrectable) error"); return ERROR_NAND_OPERATION_FAILED; - break; } switch (ecc_status & 0x0003) { case 1: @@ -694,7 +693,6 @@ static int do_data_output(struct nand_device *nand) case 2: LOG_DEBUG("main area readed with more than 1 (incorrectable) error"); return ERROR_NAND_OPERATION_FAILED; - break; } } break; diff --git a/src/flash/nand/mxc.c b/src/flash/nand/mxc.c index b541157..ee093c0 100644 --- a/src/flash/nand/mxc.c +++ b/src/flash/nand/mxc.c @@ -874,7 +874,6 @@ int ecc_status_v1(struct nand_device *nand) case 2 << 2: LOG_INFO("main area read with more than 1 (incorrectable) error"); return ERROR_NAND_OPERATION_FAILED; - break; } switch (ecc_status & 0x0003) { case 1: @@ -883,7 +882,6 @@ int ecc_status_v1(struct nand_device *nand) case 2: LOG_INFO("main area read with more than 1 (incorrectable) error"); return ERROR_NAND_OPERATION_FAILED; - break; } return ERROR_OK; } diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 34f91ce..b95b003 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -51,6 +51,8 @@ NOR_DRIVERS = \ %D%/psoc4.c \ %D%/psoc5lp.c \ %D%/psoc6.c \ + %D%/renesas_rpchf.c \ + %D%/sh_qspi.c \ %D%/sim3x.c \ %D%/spi.c \ %D%/stmsmi.c \ @@ -74,6 +76,7 @@ NOR_DRIVERS = \ NORHEADERS = \ %D%/core.h \ %D%/cc3220sf.h \ + %D%/bluenrg-x.h \ %D%/cc26xx.h \ %D%/cfi.h \ %D%/driver.h \ @@ -81,4 +84,5 @@ NORHEADERS = \ %D%/non_cfi.h \ %D%/ocl.h \ %D%/spi.h \ + %D%/stm32l4x.h \ %D%/msp432.h diff --git a/src/flash/nor/aducm360.c b/src/flash/nor/aducm360.c index f468c89..7c5596d 100644 --- a/src/flash/nor/aducm360.c +++ b/src/flash/nor/aducm360.c @@ -434,10 +434,8 @@ static int aducm360_write_block(struct flash_bank *bank, switch (choice) { case 0: return aducm360_write_block_sync(bank, buffer, offset, count); - break; case 1: return aducm360_write_block_async(bank, buffer, offset, count); - break; default: LOG_ERROR("aducm360_write_block was cancelled (no writing method was chosen)!"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; diff --git a/src/flash/nor/ambiqmicro.c b/src/flash/nor/ambiqmicro.c index b1e3e72..b41b15c 100644 --- a/src/flash/nor/ambiqmicro.c +++ b/src/flash/nor/ambiqmicro.c @@ -253,8 +253,7 @@ static int ambiqmicro_read_part_info(struct flash_bank *bank) } - if (ambiqmicro_info->target_class < - (sizeof(ambiqmicroParts)/sizeof(ambiqmicroParts[0]))) + if (ambiqmicro_info->target_class < ARRAY_SIZE(ambiqmicroParts)) ambiqmicro_info->target_name = ambiqmicroParts[ambiqmicro_info->target_class].partname; else diff --git a/src/flash/nor/at91sam3.c b/src/flash/nor/at91sam3.c index 2457c15..c9ffa65 100644 --- a/src/flash/nor/at91sam3.c +++ b/src/flash/nor/at91sam3.c @@ -3068,7 +3068,6 @@ FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command) ((unsigned int)(FLASH_BANK1_BASE_256K_AX)), ((unsigned int)(FLASH_BANK1_BASE_512K_AX))); return ERROR_FAIL; - break; /* at91sam3s and at91sam3n series only has bank 0*/ /* at91sam3u and at91sam3ax series has the same address for bank 0*/ @@ -3621,10 +3620,8 @@ COMMAND_HANDLER(sam3_handle_gpnvm_command) switch (CMD_ARGC) { default: return ERROR_COMMAND_SYNTAX_ERROR; - break; case 0: goto showall; - break; case 1: who = -1; break; @@ -3653,7 +3650,8 @@ showall: } if ((who >= 0) && (((unsigned)(who)) < pChip->details.n_gpnvms)) { r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), who, &v); - command_print(CMD, "sam3-gpnvm%u: %u", who, v); + if (r == ERROR_OK) + command_print(CMD, "sam3-gpnvm%u: %u", who, v); return r; } else { command_print(CMD, "sam3-gpnvm invalid GPNVM: %u", who); @@ -3707,7 +3705,6 @@ COMMAND_HANDLER(sam3_handle_slowclk_command) /* error */ command_print(CMD, "Too many parameters"); return ERROR_COMMAND_SYNTAX_ERROR; - break; } command_print(CMD, "Slowclk freq: %d.%03dkhz", (int)(pChip->cfg.slow_freq / 1000), @@ -3729,7 +3726,7 @@ static const struct command_registration at91sam3_exec_command_handlers[] = { .name = "info", .handler = sam3_handle_info_command, .mode = COMMAND_EXEC, - .help = "Print information about the current at91sam3 chip" + .help = "Print information about the current at91sam3 chip " "and its flash configuration.", .usage = "", }, diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c index 621754c..5b56c42 100644 --- a/src/flash/nor/at91sam4.c +++ b/src/flash/nor/at91sam4.c @@ -2482,7 +2482,6 @@ FLASH_BANK_COMMAND_HANDLER(sam4_flash_bank_command) ((unsigned int)(bank->base)), ((unsigned int)(FLASH_BANK_BASE_S))); return ERROR_FAIL; - break; /* at91sam4s series only has bank 0*/ /* at91sam4sd series has the same address for bank 0 (FLASH_BANK0_BASE_SD)*/ @@ -3101,10 +3100,8 @@ COMMAND_HANDLER(sam4_handle_gpnvm_command) switch (CMD_ARGC) { default: return ERROR_COMMAND_SYNTAX_ERROR; - break; case 0: goto showall; - break; case 1: who = -1; break; @@ -3188,7 +3185,6 @@ COMMAND_HANDLER(sam4_handle_slowclk_command) /* error */ command_print(CMD, "Too many parameters"); return ERROR_COMMAND_SYNTAX_ERROR; - break; } command_print(CMD, "Slowclk freq: %d.%03dkhz", (int)(pChip->cfg.slow_freq / 1000), @@ -3210,7 +3206,7 @@ static const struct command_registration at91sam4_exec_command_handlers[] = { .name = "info", .handler = sam4_handle_info_command, .mode = COMMAND_EXEC, - .help = "Print information about the current at91sam4 chip" + .help = "Print information about the current at91sam4 chip " "and its flash configuration.", .usage = "", }, diff --git a/src/flash/nor/at91sam4l.c b/src/flash/nor/at91sam4l.c index d356398..d4bfe53 100644 --- a/src/flash/nor/at91sam4l.c +++ b/src/flash/nor/at91sam4l.c @@ -601,6 +601,7 @@ static int sam4l_write(struct flash_bank *bank, const uint8_t *buffer, /* There's at least one aligned page to write out. */ if (count >= chip->page_size) { + assert(chip->page_size > 0); int np = count / chip->page_size + ((count % chip->page_size) ? 1 : 0); for (int i = 0; i < np; i++) { diff --git a/src/flash/nor/at91sam7.c b/src/flash/nor/at91sam7.c index 232260b..039746c 100644 --- a/src/flash/nor/at91sam7.c +++ b/src/flash/nor/at91sam7.c @@ -711,8 +711,6 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command) uint16_t page_size; uint16_t num_nvmbits; - char *target_name_t; - int bnk, sec; at91sam7_info = malloc(sizeof(struct at91sam7_flash_bank)); @@ -753,9 +751,6 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command) return ERROR_OK; } - target_name_t = calloc(strlen(CMD_ARGV[7]) + 1, sizeof(char)); - strcpy(target_name_t, CMD_ARGV[7]); - /* calculate bank size */ bank_size = num_sectors * pages_per_sector * page_size; @@ -794,7 +789,7 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command) at91sam7_info = t_bank->driver_priv; - at91sam7_info->target_name = target_name_t; + at91sam7_info->target_name = strdup(CMD_ARGV[7]); at91sam7_info->flashmode = 0; at91sam7_info->ext_freq = ext_freq; at91sam7_info->num_nvmbits = num_nvmbits; diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index b6cff9a..6e89099 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -181,6 +181,23 @@ static const struct samd_part samd21_parts[] = { { 0x26, "SAMD21E16B", 64, 8 }, { 0x27, "SAMD21E15B", 32, 4 }, + /* SAMD21 D and L Variants (from Errata) + http://ww1.microchip.com/downloads/en/DeviceDoc/ + SAM-D21-Family-Silicon-Errata-and-DataSheet-Clarification-DS80000760D.pdf */ + { 0x55, "SAMD21E16BU", 64, 8 }, + { 0x56, "SAMD21E15BU", 32, 4 }, + { 0x57, "SAMD21G16L", 64, 8 }, + { 0x3E, "SAMD21E16L", 64, 8 }, + { 0x3F, "SAMD21E15L", 32, 4 }, + { 0x62, "SAMD21E16CU", 64, 8 }, + { 0x63, "SAMD21E15CU", 32, 4 }, + { 0x92, "SAMD21J17D", 128, 16 }, + { 0x93, "SAMD21G17D", 128, 16 }, + { 0x94, "SAMD21E17D", 128, 16 }, + { 0x95, "SAMD21E17DU", 128, 16 }, + { 0x96, "SAMD21G17L", 128, 16 }, + { 0x97, "SAMD21E17L", 128, 16 }, + /* Known SAMDA1 parts. SAMD-A1 series uses the same series identifier like the SAMD21 taken from http://ww1.microchip.com/downloads/en/DeviceDoc/40001895A.pdf (pages 14-17) */ diff --git a/src/flash/nor/atsamv.c b/src/flash/nor/atsamv.c index d6f1a0a..9a53369 100644 --- a/src/flash/nor/atsamv.c +++ b/src/flash/nor/atsamv.c @@ -375,7 +375,6 @@ static int samv_probe(struct flash_bank *bank) default: LOG_ERROR("unrecognized flash size code: %d", nvm_size_code); return ERROR_FAIL; - break; } struct samv_flash_bank *samv_info = bank->driver_priv; @@ -645,7 +644,6 @@ COMMAND_HANDLER(samv_handle_gpnvm_command) switch (CMD_ARGC) { case 0: goto showall; - break; case 1: who = -1; break; @@ -660,7 +658,6 @@ COMMAND_HANDLER(samv_handle_gpnvm_command) break; default: return ERROR_COMMAND_SYNTAX_ERROR; - break; } uint32_t v; diff --git a/src/flash/nor/avrf.c b/src/flash/nor/avrf.c index 178567e..93f6872 100644 --- a/src/flash/nor/avrf.c +++ b/src/flash/nor/avrf.c @@ -58,7 +58,7 @@ struct avrf_type { struct avrf_flash_bank { int ppage_size; - int probed; + bool probed; }; static const struct avrf_type avft_chips_info[] = { @@ -67,6 +67,7 @@ static const struct avrf_type avft_chips_info[] = { */ {"atmega128", 0x9702, 256, 512, 8, 512}, {"atmega128rfa1", 0xa701, 128, 512, 8, 512}, + {"atmega256rfr2", 0xa802, 256, 1024, 8, 1024}, {"at90can128", 0x9781, 256, 512, 8, 512}, {"at90usb128", 0x9782, 256, 512, 8, 512}, {"atmega164p", 0x940a, 128, 128, 4, 128}, @@ -142,16 +143,24 @@ static int avr_jtagprg_chiperase(struct avr_common *avr) } static int avr_jtagprg_writeflashpage(struct avr_common *avr, + const bool ext_addressing, const uint8_t *page_buf, uint32_t buf_size, uint32_t addr, uint32_t page_size) { - uint32_t i, poll_value; + uint32_t poll_value; avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2310, AVR_JTAG_REG_ProgrammingCommand_Len); + /* load extended high byte */ + if (ext_addressing) + avr_jtag_senddat(avr->jtag_info.tap, + NULL, + 0x0b00 | ((addr >> 17) & 0xFF), + AVR_JTAG_REG_ProgrammingCommand_Len); + /* load addr high byte */ avr_jtag_senddat(avr->jtag_info.tap, NULL, @@ -166,7 +175,7 @@ static int avr_jtagprg_writeflashpage(struct avr_common *avr, avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_PAGELOAD); - for (i = 0; i < page_size; i++) { + for (uint32_t i = 0; i < page_size; i++) { if (i < buf_size) avr_jtag_senddat(avr->jtag_info.tap, NULL, page_buf[i], 8); else @@ -204,7 +213,7 @@ FLASH_BANK_COMMAND_HANDLER(avrf_flash_bank_command) avrf_info = malloc(sizeof(struct avrf_flash_bank)); bank->driver_priv = avrf_info; - avrf_info->probed = 0; + avrf_info->probed = false; return ERROR_OK; } @@ -238,6 +247,7 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o struct target *target = bank->target; struct avr_common *avr = target->arch_info; uint32_t cur_size, cur_buffer_size, page_size; + bool ext_addressing; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -258,6 +268,11 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o if (ERROR_OK != avr_jtagprg_enterprogmode(avr)) return ERROR_FAIL; + if (bank->size > 0x20000) + ext_addressing = true; + else + ext_addressing = false; + cur_size = 0; while (count > 0) { if (count > page_size) @@ -265,6 +280,7 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o else cur_buffer_size = count; avr_jtagprg_writeflashpage(avr, + ext_addressing, buffer + cur_size, cur_buffer_size, offset + cur_size, @@ -288,7 +304,6 @@ static int avrf_probe(struct flash_bank *bank) struct avrf_flash_bank *avrf_info = bank->driver_priv; struct avr_common *avr = target->arch_info; const struct avrf_type *avr_info = NULL; - int i; uint32_t device_id; if (bank->target->state != TARGET_HALTED) { @@ -296,7 +311,7 @@ static int avrf_probe(struct flash_bank *bank) return ERROR_TARGET_NOT_HALTED; } - avrf_info->probed = 0; + avrf_info->probed = false; avr_jtag_read_jtagid(avr, &device_id); if (ERROR_OK != mcu_execute_queue()) @@ -308,7 +323,7 @@ static int avrf_probe(struct flash_bank *bank) EXTRACT_MFG(device_id), 0x1F); - for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++) { + for (size_t i = 0; i < ARRAY_SIZE(avft_chips_info); i++) { if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) { avr_info = &avft_chips_info[i]; LOG_INFO("target device is %s", avr_info->name); @@ -328,20 +343,20 @@ static int avrf_probe(struct flash_bank *bank) bank->num_sectors = avr_info->flash_page_num; bank->sectors = malloc(sizeof(struct flash_sector) * avr_info->flash_page_num); - for (i = 0; i < avr_info->flash_page_num; i++) { + for (int i = 0; i < avr_info->flash_page_num; i++) { bank->sectors[i].offset = i * avr_info->flash_page_size; bank->sectors[i].size = avr_info->flash_page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } - avrf_info->probed = 1; + avrf_info->probed = true; return ERROR_OK; } else { /* chip not supported */ LOG_ERROR("0x%" PRIx32 " is not support for avr", EXTRACT_PART(device_id)); - avrf_info->probed = 1; + avrf_info->probed = true; return ERROR_FAIL; } } @@ -359,7 +374,6 @@ static int avrf_info(struct flash_bank *bank, char *buf, int buf_size) struct target *target = bank->target; struct avr_common *avr = target->arch_info; const struct avrf_type *avr_info = NULL; - int i; uint32_t device_id; if (bank->target->state != TARGET_HALTED) { @@ -377,7 +391,7 @@ static int avrf_info(struct flash_bank *bank, char *buf, int buf_size) EXTRACT_MFG(device_id), 0x1F); - for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++) { + for (size_t i = 0; i < ARRAY_SIZE(avft_chips_info); i++) { if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) { avr_info = &avft_chips_info[i]; LOG_INFO("target device is %s", avr_info->name); @@ -418,8 +432,6 @@ static int avrf_mass_erase(struct flash_bank *bank) COMMAND_HANDLER(avrf_handle_mass_erase_command) { - int i; - if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; @@ -430,7 +442,7 @@ COMMAND_HANDLER(avrf_handle_mass_erase_command) if (avrf_mass_erase(bank) == ERROR_OK) { /* set all sectors as erased */ - for (i = 0; i < bank->num_sectors; i++) + for (int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; command_print(CMD, "avr mass erase complete"); diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c index f6a2492..fbce20d 100644 --- a/src/flash/nor/bluenrg-x.c +++ b/src/flash/nor/bluenrg-x.c @@ -24,35 +24,62 @@ #include <target/armv7m.h> #include <target/cortex_m.h> #include "imp.h" +#include "bluenrg-x.h" + +#define BLUENRG2_JTAG_REG (flash_priv_data_2.jtag_idcode_reg) +#define BLUENRGLP_JTAG_REG (flash_priv_data_lp.jtag_idcode_reg) + +#define DIE_ID_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->die_id_reg) +#define JTAG_IDCODE_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->jtag_idcode_reg) +#define FLASH_PAGE_SIZE(bluenrgx_info) (bluenrgx_info->flash_ptr->flash_page_size) + +struct flash_ctrl_priv_data { + uint32_t die_id_reg; + uint32_t jtag_idcode_reg; + uint32_t flash_base; + uint32_t flash_regs_base; + uint32_t flash_page_size; + uint32_t jtag_idcode; + char *part_name; +}; + +const struct flash_ctrl_priv_data flash_priv_data_1 = { + .die_id_reg = 0x4090001C, + .jtag_idcode_reg = 0x40900028, + .flash_base = 0x10040000, + .flash_regs_base = 0x40100000, + .flash_page_size = 2048, + .jtag_idcode = 0x00000000, + .part_name = "BLUENRG-1", +}; -#define FLASH_SIZE_REG (0x40100014) -#define DIE_ID_REG (0x4090001C) -#define JTAG_IDCODE_REG (0x40900028) -#define BLUENRG2_IDCODE (0x0200A041) -#define FLASH_BASE (0x10040000) -#define FLASH_PAGE_SIZE (2048) -#define FLASH_REG_COMMAND (0x40100000) -#define FLASH_REG_IRQRAW (0x40100010) -#define FLASH_REG_ADDRESS (0x40100018) -#define FLASH_REG_DATA (0x40100040) -#define FLASH_CMD_ERASE_PAGE 0x11 -#define FLASH_CMD_MASSERASE 0x22 -#define FLASH_CMD_WRITE 0x33 -#define FLASH_CMD_BURSTWRITE 0xCC -#define FLASH_INT_CMDDONE 0x01 -#define FLASH_WORD_LEN 4 +const struct flash_ctrl_priv_data flash_priv_data_2 = { + .die_id_reg = 0x4090001C, + .jtag_idcode_reg = 0x40900028, + .flash_base = 0x10040000, + .flash_regs_base = 0x40100000, + .flash_page_size = 2048, + .jtag_idcode = 0x0200A041, + .part_name = "BLUENRG-2", +}; + +const struct flash_ctrl_priv_data flash_priv_data_lp = { + .die_id_reg = 0x40000000, + .jtag_idcode_reg = 0x40000004, + .flash_base = 0x10040000, + .flash_regs_base = 0x40001000, + .flash_page_size = 2048, + .jtag_idcode = 0x0201E041, + .part_name = "BLUENRG-LP", +}; struct bluenrgx_flash_bank { - int probed; - uint32_t idcode; + bool probed; uint32_t die_id; + const struct flash_ctrl_priv_data *flash_ptr; }; -static int bluenrgx_protect_check(struct flash_bank *bank) -{ - /* Nothing to do. Protection is only handled in SW. */ - return ERROR_OK; -} +const struct flash_ctrl_priv_data *flash_ctrl[] = {&flash_priv_data_1, &flash_priv_data_2, &flash_priv_data_lp}; /* flash_bank bluenrg-x 0 0 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command) @@ -67,9 +94,12 @@ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command) return ERROR_FAIL; } + bank->write_start_alignment = 16; + bank->write_end_alignment = 16; + bank->driver_priv = bluenrgx_info; - bluenrgx_info->probed = 0; + bluenrgx_info->probed = false; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; @@ -77,6 +107,22 @@ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command) return ERROR_OK; } +static inline uint32_t bluenrgx_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset) +{ + struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; + return bluenrgx_info->flash_ptr->flash_regs_base + reg_offset; +} + +static inline int bluenrgx_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value) +{ + return target_read_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value); +} + +static inline int bluenrgx_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) +{ + return target_write_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value); +} + static int bluenrgx_erase(struct flash_bank *bank, int first, int last) { int retval = ERROR_OK; @@ -87,7 +133,7 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last) uint32_t address, command; /* check preconditions */ - if (bluenrgx_info->probed == 0) + if (!bluenrgx_info->probed) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_HALTED) { @@ -103,24 +149,25 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last) if (mass_erase) { command = FLASH_CMD_MASSERASE; address = bank->base; - if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { + if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } - if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) { + if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS, + (address - bank->base) >> 2) != ERROR_OK) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } - if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) { + if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, command) != ERROR_OK) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } - for (int i = 0; i < 100; i++) { + for (unsigned int i = 0; i < 100; i++) { uint32_t value; - if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) { + if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } @@ -135,26 +182,28 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last) } else { command = FLASH_CMD_ERASE_PAGE; for (int i = first; i <= last; i++) { - address = bank->base+i*FLASH_PAGE_SIZE; + address = bank->base+i*FLASH_PAGE_SIZE(bluenrgx_info); + LOG_DEBUG("address = %08x, index = %d", address, i); - if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { + if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } - if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) { + if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS, + (address - bank->base) >> 2) != ERROR_OK) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } - if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) { + if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, command) != ERROR_OK) { LOG_ERROR("Failed"); return ERROR_FAIL; } - for (int j = 0; j < 100; j++) { + for (unsigned int j = 0; j < 100; j++) { uint32_t value; - if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) { + if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) { LOG_ERROR("Register write failed"); return ERROR_FAIL; } @@ -172,140 +221,10 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last) } -static int bluenrgx_protect(struct flash_bank *bank, int set, int first, int last) -{ - /* Protection is only handled in software: no hardware write protection - available in BlueNRG-x devices */ - int sector; - - for (sector = first; sector <= last; sector++) - bank->sectors[sector].is_protected = set; - return ERROR_OK; -} -static int bluenrgx_write_word(struct target *target, uint32_t address_base, uint8_t *values, uint32_t count) -{ - int retval = ERROR_OK; - - retval = target_write_u32(target, FLASH_REG_IRQRAW, 0x3f); - if (retval != ERROR_OK) { - LOG_ERROR("Register write failed, error code: %d", retval); - return retval; - } - - for (uint32_t i = 0; i < count; i++) { - uint32_t address = address_base + i * FLASH_WORD_LEN; - - retval = target_write_u32(target, FLASH_REG_ADDRESS, address >> 2); - if (retval != ERROR_OK) { - LOG_ERROR("Register write failed, error code: %d", retval); - return retval; - } - - retval = target_write_buffer(target, FLASH_REG_DATA, FLASH_WORD_LEN, values + i * FLASH_WORD_LEN); - if (retval != ERROR_OK) { - LOG_ERROR("Register write failed, error code: %d", retval); - return retval; - } - - retval = target_write_u32(target, FLASH_REG_COMMAND, FLASH_CMD_WRITE); - if (retval != ERROR_OK) { - LOG_ERROR("Register write failed, error code: %d", retval); - return retval; - } - - for (int j = 0; j < 100; j++) { - uint32_t reg_value; - retval = target_read_u32(target, FLASH_REG_IRQRAW, ®_value); - - if (retval != ERROR_OK) { - LOG_ERROR("Register read failed, error code: %d", retval); - return retval; - } - - if (reg_value & FLASH_INT_CMDDONE) - break; - - if (j == 99) { - LOG_ERROR("Write command failed (timeout)"); - return ERROR_FAIL; - } - } - } - return retval; -} - -static int bluenrgx_write_bytes(struct target *target, uint32_t address_base, uint8_t *buffer, uint32_t count) -{ - int retval = ERROR_OK; - uint8_t *new_buffer = NULL; - uint32_t pre_bytes = 0, post_bytes = 0, pre_word, post_word, pre_address, post_address; - - if (count == 0) { - /* Just return if there are no bytes to write */ - return retval; - } - - if (address_base & 3) { - pre_bytes = address_base & 3; - pre_address = address_base - pre_bytes; - } - - if ((count + pre_bytes) & 3) { - post_bytes = ((count + pre_bytes + 3) & ~3) - (count + pre_bytes); - post_address = (address_base + count) & ~3; - } - - if (pre_bytes || post_bytes) { - uint32_t old_count = count; - - count = old_count + pre_bytes + post_bytes; - - new_buffer = malloc(count); - - if (new_buffer == NULL) { - LOG_ERROR("odd number of bytes to write and no memory " - "for padding buffer"); - return ERROR_FAIL; - } - - LOG_INFO("Requested number of bytes to write and/or address not word aligned (%" PRIu32 "), extending to %" - PRIu32 " ", old_count, count); - - if (pre_bytes) { - if (target_read_u32(target, pre_address, &pre_word)) { - LOG_ERROR("Memory read failed"); - free(new_buffer); - return ERROR_FAIL; - } - - } - - if (post_bytes) { - if (target_read_u32(target, post_address, &post_word)) { - LOG_ERROR("Memory read failed"); - free(new_buffer); - return ERROR_FAIL; - } - - } - - memcpy(new_buffer, &pre_word, pre_bytes); - memcpy((new_buffer+((pre_bytes+old_count) & ~3)), &post_word, 4); - memcpy(new_buffer+pre_bytes, buffer, old_count); - buffer = new_buffer; - } - - retval = bluenrgx_write_word(target, address_base - pre_bytes, buffer, count/4); - - if (new_buffer) - free(new_buffer); - - return retval; -} - static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { + struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; struct target *target = bank->target; uint32_t buffer_size = 16384 + 8; struct working_area *write_algorithm; @@ -313,10 +232,9 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[5]; + struct mem_param mem_params[1]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; - uint32_t pre_size = 0, fast_size = 0, post_size = 0; - uint32_t pre_offset = 0, fast_offset = 0, post_offset = 0; /* See contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c for source and * hints how to generate the data! @@ -325,6 +243,10 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, #include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc" }; + /* check preconditions */ + if (!bluenrgx_info->probed) + return ERROR_FLASH_BANK_NOT_PROBED; + if ((offset + count) > bank->size) { LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %d, size=%d", (offset + count), @@ -337,132 +259,105 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, return ERROR_TARGET_NOT_HALTED; } - /* We are good here and we need to compute pre_size, fast_size, post_size */ - pre_size = MIN(count, ((offset+0xF) & ~0xF) - offset); - pre_offset = offset; - fast_size = 16*((count - pre_size) / 16); - fast_offset = offset + pre_size; - post_size = (count-pre_size-fast_size) % 16; - post_offset = fast_offset + fast_size; - - LOG_DEBUG("pre_size = %08x, pre_offset=%08x", pre_size, pre_offset); - LOG_DEBUG("fast_size = %08x, fast_offset=%08x", fast_size, fast_offset); - LOG_DEBUG("post_size = %08x, post_offset=%08x", post_size, post_offset); - - /* Program initial chunk not 16 bytes aligned */ - retval = bluenrgx_write_bytes(target, bank->base+pre_offset, (uint8_t *) buffer, pre_size); - if (retval) { - LOG_ERROR("bluenrgx_write_bytes failed %d", retval); - return ERROR_FAIL; + if (target_alloc_working_area(target, sizeof(bluenrgx_flash_write_code), + &write_algorithm) != ERROR_OK) { + LOG_WARNING("no working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - /* Program chunk 16 bytes aligned in fast mode */ - if (fast_size) { - - if (target_alloc_working_area(target, sizeof(bluenrgx_flash_write_code), - &write_algorithm) != ERROR_OK) { - LOG_WARNING("no working area available, can't do block memory writes"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - retval = target_write_buffer(target, write_algorithm->address, - sizeof(bluenrgx_flash_write_code), - bluenrgx_flash_write_code); - if (retval != ERROR_OK) - return retval; + retval = target_write_buffer(target, write_algorithm->address, + sizeof(bluenrgx_flash_write_code), + bluenrgx_flash_write_code); + if (retval != ERROR_OK) + return retval; - /* memory buffer */ - if (target_alloc_working_area(target, buffer_size, &source)) { - LOG_WARNING("no large enough working area available"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } + /* memory buffer */ + if (target_alloc_working_area(target, buffer_size, &source)) { + LOG_WARNING("no large enough working area available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } - /* Stack pointer area */ - if (target_alloc_working_area(target, 64, - &write_algorithm_sp) != ERROR_OK) { - LOG_DEBUG("no working area for write code stack pointer"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } + /* Stack pointer area */ + if (target_alloc_working_area(target, 128, + &write_algorithm_sp) != ERROR_OK) { + LOG_DEBUG("no working area for write code stack pointer"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } - armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; - armv7m_info.core_mode = ARM_MODE_THREAD; - - init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); - init_reg_param(®_params[1], "r1", 32, PARAM_OUT); - init_reg_param(®_params[2], "r2", 32, PARAM_OUT); - init_reg_param(®_params[3], "r3", 32, PARAM_OUT); - init_reg_param(®_params[4], "sp", 32, PARAM_OUT); - - /* FIFO start address (first two words used for write and read pointers) */ - buf_set_u32(reg_params[0].value, 0, 32, source->address); - /* FIFO end address (first two words used for write and read pointers) */ - buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); - /* Flash memory address */ - buf_set_u32(reg_params[2].value, 0, 32, address+pre_size); - /* Number of bytes */ - buf_set_u32(reg_params[3].value, 0, 32, fast_size); - /* Stack pointer for program working area */ - buf_set_u32(reg_params[4].value, 0, 32, write_algorithm_sp->address); - - LOG_DEBUG("source->address = " TARGET_ADDR_FMT, source->address); - LOG_DEBUG("source->address+ source->size = " TARGET_ADDR_FMT, source->address+source->size); - LOG_DEBUG("write_algorithm_sp->address = " TARGET_ADDR_FMT, write_algorithm_sp->address); - LOG_DEBUG("address = %08x", address+pre_size); - LOG_DEBUG("count = %08x", count); - - retval = target_run_flash_async_algorithm(target, - buffer+pre_size, - fast_size/16, - 16, /* Block size: we write in block of 16 bytes to enjoy burstwrite speed */ - 0, - NULL, - 5, - reg_params, - source->address, - source->size, - write_algorithm->address, - 0, - &armv7m_info); - - if (retval == ERROR_FLASH_OPERATION_FAILED) { - LOG_ERROR("error executing bluenrg-x flash write algorithm"); - - uint32_t error = buf_get_u32(reg_params[0].value, 0, 32); - - if (error != 0) - LOG_ERROR("flash write failed = %08" PRIx32, error); - } + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); + init_reg_param(®_params[4], "sp", 32, PARAM_OUT); + /* Put the parameter at the first available stack location */ + init_mem_param(&mem_params[0], write_algorithm_sp->address + 80, 32, PARAM_OUT); + + /* FIFO start address (first two words used for write and read pointers) */ + buf_set_u32(reg_params[0].value, 0, 32, source->address); + /* FIFO end address (first two words used for write and read pointers) */ + buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); + /* Flash memory address */ + buf_set_u32(reg_params[2].value, 0, 32, address); + /* Number of bytes */ + buf_set_u32(reg_params[3].value, 0, 32, count); + /* Stack pointer for program working area */ + buf_set_u32(reg_params[4].value, 0, 32, write_algorithm_sp->address); + /* Flash register base address */ + buf_set_u32(mem_params[0].value, 0, 32, bluenrgx_info->flash_ptr->flash_regs_base); + + LOG_DEBUG("source->address = " TARGET_ADDR_FMT, source->address); + LOG_DEBUG("source->address+ source->size = " TARGET_ADDR_FMT, source->address+source->size); + LOG_DEBUG("write_algorithm_sp->address = " TARGET_ADDR_FMT, write_algorithm_sp->address); + LOG_DEBUG("address = %08x", address); + LOG_DEBUG("count = %08x", count); + + retval = target_run_flash_async_algorithm(target, + buffer, + count/16, + 16, /* Block size: we write in block of 16 bytes to enjoy burstwrite speed */ + 1, + mem_params, + 5, + reg_params, + source->address, + source->size, + write_algorithm->address, + 0, + &armv7m_info); + + if (retval == ERROR_FLASH_OPERATION_FAILED) { + LOG_ERROR("error executing bluenrg-x flash write algorithm"); + + uint32_t error = buf_get_u32(reg_params[0].value, 0, 32); + + if (error != 0) + LOG_ERROR("flash write failed = %08" PRIx32, error); + } + if (retval == ERROR_OK) { + uint32_t rp; + /* Read back rp and check that is valid */ + retval = target_read_u32(target, source->address+4, &rp); if (retval == ERROR_OK) { - uint32_t rp; - /* Read back rp and check that is valid */ - retval = target_read_u32(target, source->address+4, &rp); - if (retval == ERROR_OK) { - if ((rp < source->address+8) || (rp > (source->address + source->size))) { - LOG_ERROR("flash write failed = %08" PRIx32, rp); - retval = ERROR_FLASH_OPERATION_FAILED; - } + if ((rp < source->address+8) || (rp > (source->address + source->size))) { + LOG_ERROR("flash write failed = %08" PRIx32, rp); + retval = ERROR_FLASH_OPERATION_FAILED; } } - target_free_working_area(target, source); - target_free_working_area(target, write_algorithm); - target_free_working_area(target, write_algorithm_sp); - - destroy_reg_param(®_params[0]); - destroy_reg_param(®_params[1]); - destroy_reg_param(®_params[2]); - destroy_reg_param(®_params[3]); - destroy_reg_param(®_params[4]); - if (retval != ERROR_OK) - return retval; - } + target_free_working_area(target, source); + target_free_working_area(target, write_algorithm); + target_free_working_area(target, write_algorithm_sp); + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + destroy_mem_param(&mem_params[0]); - /* Program chunk at end, not addressable by fast burst write algorithm */ - retval = bluenrgx_write_bytes(target, bank->base+post_offset, (uint8_t *) (buffer+pre_size+fast_size), post_size); - if (retval) { - LOG_ERROR("bluenrgx_write_bytes failed %d", retval); - return ERROR_FAIL; - } return retval; } @@ -470,33 +365,50 @@ static int bluenrgx_probe(struct flash_bank *bank) { struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; uint32_t idcode, size_info, die_id; - int i; - int retval = target_read_u32(bank->target, JTAG_IDCODE_REG, &idcode); + int retval = target_read_u32(bank->target, BLUENRGLP_JTAG_REG, &idcode); + if (retval != ERROR_OK) return retval; - retval = target_read_u32(bank->target, FLASH_SIZE_REG, &size_info); + + if (idcode != flash_priv_data_lp.jtag_idcode) { + retval = target_read_u32(bank->target, BLUENRG2_JTAG_REG, &idcode); + if (retval != ERROR_OK) + return retval; + } + + /* Default device is BlueNRG-1 */ + bluenrgx_info->flash_ptr = &flash_priv_data_1; + bank->base = flash_priv_data_1.flash_base; + + for (size_t i = 0; i < ARRAY_SIZE(flash_ctrl); i++) { + if (idcode == (*flash_ctrl[i]).jtag_idcode) { + bluenrgx_info->flash_ptr = flash_ctrl[i]; + bank->base = (*flash_ctrl[i]).flash_base; + break; + } + } + retval = bluenrgx_read_flash_reg(bank, FLASH_SIZE_REG, &size_info); if (retval != ERROR_OK) return retval; - retval = target_read_u32(bank->target, DIE_ID_REG, &die_id); + retval = target_read_u32(bank->target, DIE_ID_REG(bluenrgx_info), &die_id); if (retval != ERROR_OK) return retval; - bank->size = (size_info + 1) * 4; - bank->base = FLASH_BASE; - bank->num_sectors = bank->size/FLASH_PAGE_SIZE; + bank->size = (size_info + 1) * FLASH_WORD_LEN; + bank->num_sectors = bank->size/FLASH_PAGE_SIZE(bluenrgx_info); bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors); - for (i = 0; i < bank->num_sectors; i++) { - bank->sectors[i].offset = i * FLASH_PAGE_SIZE; - bank->sectors[i].size = FLASH_PAGE_SIZE; + for (int i = 0; i < bank->num_sectors; i++) { + bank->sectors[i].offset = i * FLASH_PAGE_SIZE(bluenrgx_info); + bank->sectors[i].size = FLASH_PAGE_SIZE(bluenrgx_info); bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; } - bluenrgx_info->probed = 1; + bluenrgx_info->probed = true; bluenrgx_info->die_id = die_id; - bluenrgx_info->idcode = idcode; + return ERROR_OK; } @@ -515,7 +427,6 @@ static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size) { struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; int mask_number, cut_number; - char *part_name; if (!bluenrgx_info->probed) { int retval = bluenrgx_probe(bank); @@ -526,16 +437,11 @@ static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size) } } - if (bluenrgx_info->idcode == BLUENRG2_IDCODE) - part_name = "BLUENRG-2"; - else - part_name = "BLUENRG-1"; - mask_number = (bluenrgx_info->die_id >> 4) & 0xF; cut_number = bluenrgx_info->die_id & 0xF; snprintf(buf, buf_size, - "%s - Rev: %d.%d", part_name, mask_number, cut_number); + "%s - Rev: %d.%d", bluenrgx_info->flash_ptr->part_name, mask_number, cut_number); return ERROR_OK; } @@ -543,12 +449,12 @@ const struct flash_driver bluenrgx_flash = { .name = "bluenrg-x", .flash_bank_command = bluenrgx_flash_bank_command, .erase = bluenrgx_erase, - .protect = bluenrgx_protect, + .protect = NULL, .write = bluenrgx_write, .read = default_flash_read, .probe = bluenrgx_probe, .erase_check = default_flash_blank_check, - .protect_check = bluenrgx_protect_check, + .protect_check = NULL, .auto_probe = bluenrgx_auto_probe, .info = bluenrgx_get_info, }; diff --git a/src/jtag/drivers/libusb_common.h b/src/flash/nor/bluenrg-x.h index 599a0a9..3b84b8b 100644 --- a/src/jtag/drivers/libusb_common.h +++ b/src/flash/nor/bluenrg-x.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2011 by Mauro Gamba <maurillo71@gmail.com> * + * Copyright (C) 2019 by STMicroelectronics. * * * * 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 * @@ -15,13 +15,31 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ***************************************************************************/ -#ifndef OPENOCD_JTAG_DRIVERS_LIBUSB_COMMON_H -#define OPENOCD_JTAG_DRIVERS_LIBUSB_COMMON_H +#ifndef OPENOCD_FLASH_NOR_BLUENRGX_H +#define OPENOCD_FLASH_NOR_BLUENRGX_H -#ifdef HAVE_LIBUSB1 -#include "libusb1_common.h" -#else -#include "libusb0_common.h" -#endif +/* Flash Controller registers offsets */ +#define FLASH_REG_COMMAND 0x00 +#define FLASH_REG_CONFIG 0x04 +#define FLASH_REG_IRQSTAT 0x08 +#define FLASH_REG_IRQMASK 0x0C +#define FLASH_REG_IRQRAW 0x10 +#define FLASH_REG_ADDRESS 0x18 +#define FLASH_REG_UNLOCKM 0x1C +#define FLASH_REG_UNLOCKL 0x20 +#define FLASH_REG_DATA0 0x40 +#define FLASH_REG_DATA1 0x44 +#define FLASH_REG_DATA2 0x48 +#define FLASH_REG_DATA3 0x4C +#define FLASH_SIZE_REG 0x14 -#endif /* OPENOCD_JTAG_DRIVERS_LIBUSB_COMMON_H */ +/* Flash Controller commands */ +#define FLASH_CMD_ERASE_PAGE 0x11 +#define FLASH_CMD_MASSERASE 0x22 +#define FLASH_CMD_WRITE 0x33 +#define FLASH_CMD_BURSTWRITE 0xCC +#define FLASH_INT_CMDDONE 0x01 + +#define FLASH_WORD_LEN 4 + +#endif /* OPENOCD_FLASH_NOR_BLUENRGX_H */ diff --git a/src/flash/nor/cc3220sf.c b/src/flash/nor/cc3220sf.c index afdb7f4..c8de7d0 100644 --- a/src/flash/nor/cc3220sf.c +++ b/src/flash/nor/cc3220sf.c @@ -363,6 +363,8 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, LOG_ERROR("cc3220sf: Flash operation failed"); break; } + + keep_alive(); } /* Do one word write for any final bytes less than a full word */ diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c index 04fa83b..50ab207 100644 --- a/src/flash/nor/cfi.c +++ b/src/flash/nor/cfi.c @@ -34,9 +34,6 @@ #include <helper/binarybuffer.h> #include <target/algorithm.h> -#define CFI_MAX_BUS_WIDTH 4 -#define CFI_MAX_CHIP_WIDTH 4 - /* defines internal maximum size for code fragment in cfi_intel_write_block() */ #define CFI_MAX_INTEL_CODESIZE 256 @@ -103,16 +100,15 @@ static const struct cfi_fixup cfi_0001_fixups[] = { static void cfi_fixup(struct flash_bank *bank, const struct cfi_fixup *fixups) { struct cfi_flash_bank *cfi_info = bank->driver_priv; - const struct cfi_fixup *f; - for (f = fixups; f->fixup; f++) { + for (const struct cfi_fixup *f = fixups; f->fixup; f++) { if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi_info->manufacturer)) && ((f->id == CFI_ID_ANY) || (f->id == cfi_info->device_id))) f->fixup(bank, f->param); } } -static inline uint32_t flash_address(struct flash_bank *bank, int sector, uint32_t offset) +uint32_t cfi_flash_address(struct flash_bank *bank, int sector, uint32_t offset) { struct cfi_flash_bank *cfi_info = bank->driver_priv; @@ -131,32 +127,55 @@ static inline uint32_t flash_address(struct flash_bank *bank, int sector, uint32 } } +static int cfi_target_write_memory(struct flash_bank *bank, target_addr_t addr, + uint32_t count, const uint8_t *buffer) +{ + struct cfi_flash_bank *cfi_info = bank->driver_priv; + if (cfi_info->write_mem) { + return cfi_info->write_mem(bank, addr, count, buffer); + } else { + return target_write_memory(bank->target, addr, bank->bus_width, + count, buffer); + } +} + +int cfi_target_read_memory(struct flash_bank *bank, target_addr_t addr, + uint32_t count, uint8_t *buffer) +{ + struct cfi_flash_bank *cfi_info = bank->driver_priv; + if (cfi_info->read_mem) { + return cfi_info->read_mem(bank, addr, count, buffer); + } else { + return target_read_memory(bank->target, addr, bank->bus_width, + count, buffer); + } +} + static void cfi_command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf) { - int i; struct cfi_flash_bank *cfi_info = bank->driver_priv; /* clear whole buffer, to ensure bits that exceed the bus_width * are set to zero */ - for (i = 0; i < CFI_MAX_BUS_WIDTH; i++) + for (size_t i = 0; i < CFI_MAX_BUS_WIDTH; i++) cmd_buf[i] = 0; if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) { - for (i = bank->bus_width; i > 0; i--) + for (int i = bank->bus_width; i > 0; i--) *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd; } else { - for (i = 1; i <= bank->bus_width; i++) + for (int i = 1; i <= bank->bus_width; i++) *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd; } } -static int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t address) +int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t address) { uint8_t command[CFI_MAX_BUS_WIDTH]; cfi_command(bank, cmd, command); - return target_write_memory(bank->target, address, bank->bus_width, 1, command); + return cfi_target_write_memory(bank, address, 1, command); } /* read unsigned 8-bit value from the bank @@ -165,13 +184,12 @@ static int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t addre */ static int cfi_query_u8(struct flash_bank *bank, int sector, uint32_t offset, uint8_t *val) { - struct target *target = bank->target; struct cfi_flash_bank *cfi_info = bank->driver_priv; uint8_t data[CFI_MAX_BUS_WIDTH]; int retval; - retval = target_read_memory(target, flash_address(bank, sector, offset), - bank->bus_width, 1, data); + retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset), + 1, data); if (retval != ERROR_OK) return retval; @@ -189,25 +207,23 @@ static int cfi_query_u8(struct flash_bank *bank, int sector, uint32_t offset, ui */ static int cfi_get_u8(struct flash_bank *bank, int sector, uint32_t offset, uint8_t *val) { - struct target *target = bank->target; struct cfi_flash_bank *cfi_info = bank->driver_priv; uint8_t data[CFI_MAX_BUS_WIDTH]; - int i; int retval; - retval = target_read_memory(target, flash_address(bank, sector, offset), - bank->bus_width, 1, data); + retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset), + 1, data); if (retval != ERROR_OK) return retval; if (cfi_info->endianness == TARGET_LITTLE_ENDIAN) { - for (i = 0; i < bank->bus_width / bank->chip_width; i++) + for (int i = 0; i < bank->bus_width / bank->chip_width; i++) data[0] |= data[i]; *val = data[0]; } else { uint8_t value = 0; - for (i = 0; i < bank->bus_width / bank->chip_width; i++) + for (int i = 0; i < bank->bus_width / bank->chip_width; i++) value |= data[bank->bus_width - 1 - i]; *val = value; @@ -217,22 +233,20 @@ static int cfi_get_u8(struct flash_bank *bank, int sector, uint32_t offset, uint static int cfi_query_u16(struct flash_bank *bank, int sector, uint32_t offset, uint16_t *val) { - struct target *target = bank->target; struct cfi_flash_bank *cfi_info = bank->driver_priv; uint8_t data[CFI_MAX_BUS_WIDTH * 2]; int retval; if (cfi_info->x16_as_x8) { - uint8_t i; - for (i = 0; i < 2; i++) { - retval = target_read_memory(target, flash_address(bank, sector, offset + i), - bank->bus_width, 1, &data[i * bank->bus_width]); + for (uint8_t i = 0; i < 2; i++) { + retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset + i), + 1, &data[i * bank->bus_width]); if (retval != ERROR_OK) return retval; } } else { - retval = target_read_memory(target, flash_address(bank, sector, offset), - bank->bus_width, 2, data); + retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset), + 2, data); if (retval != ERROR_OK) return retval; } @@ -247,22 +261,20 @@ static int cfi_query_u16(struct flash_bank *bank, int sector, uint32_t offset, u static int cfi_query_u32(struct flash_bank *bank, int sector, uint32_t offset, uint32_t *val) { - struct target *target = bank->target; struct cfi_flash_bank *cfi_info = bank->driver_priv; uint8_t data[CFI_MAX_BUS_WIDTH * 4]; int retval; if (cfi_info->x16_as_x8) { - uint8_t i; - for (i = 0; i < 4; i++) { - retval = target_read_memory(target, flash_address(bank, sector, offset + i), - bank->bus_width, 1, &data[i * bank->bus_width]); + for (uint8_t i = 0; i < 4; i++) { + retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset + i), + 1, &data[i * bank->bus_width]); if (retval != ERROR_OK) return retval; } } else { - retval = target_read_memory(target, flash_address(bank, sector, offset), - bank->bus_width, 4, data); + retval = cfi_target_read_memory(bank, cfi_flash_address(bank, sector, offset), + 4, data); if (retval != ERROR_OK) return retval; } @@ -278,16 +290,16 @@ static int cfi_query_u32(struct flash_bank *bank, int sector, uint32_t offset, u return ERROR_OK; } -static int cfi_reset(struct flash_bank *bank) +int cfi_reset(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; int retval = ERROR_OK; - retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -295,7 +307,7 @@ static int cfi_reset(struct flash_bank *bank) (cfi_info->device_id == 0x227E || cfi_info->device_id == 0x7E)) { /* Numonix M29W128G is cmd 0xFF intolerant - causes internal undefined state * so we send an extra 0xF0 reset to fix the bug */ - retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x00)); + retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x00)); if (retval != ERROR_OK) return retval; } @@ -305,7 +317,7 @@ static int cfi_reset(struct flash_bank *bank) static void cfi_intel_clear_status_register(struct flash_bank *bank) { - cfi_send_command(bank, 0x50, flash_address(bank, 0, 0x0)); + cfi_send_command(bank, 0x50, cfi_flash_address(bank, 0, 0x0)); } static int cfi_intel_wait_status_busy(struct flash_bank *bank, int timeout, uint8_t *val) @@ -359,7 +371,7 @@ static int cfi_intel_wait_status_busy(struct flash_bank *bank, int timeout, uint return retval; } -static int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout) +int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout) { uint8_t status, oldstatus; struct cfi_flash_bank *cfi_info = bank->driver_priv; @@ -534,7 +546,7 @@ static int cfi_read_spansion_pri_ext(struct flash_bank *bank) pri_ext->_reversed_geometry = 0; if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I')) { - retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("Could not read spansion bank information"); @@ -641,7 +653,7 @@ static int cfi_read_atmel_pri_ext(struct flash_bank *bank) if ((atmel_pri_ext.pri[0] != 'P') || (atmel_pri_ext.pri[1] != 'R') || (atmel_pri_ext.pri[2] != 'I')) { - retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("Could not read atmel bank information"); @@ -799,14 +811,12 @@ static int cfi_intel_info(struct flash_bank *bank, char *buf, int buf_size) return ERROR_OK; } -/* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#> [options] - */ -FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command) +int cfi_flash_bank_cmd(struct flash_bank *bank, unsigned int argc, const char **argv) { struct cfi_flash_bank *cfi_info; int bus_swap = 0; - if (CMD_ARGC < 6) + if (argc < 6) return ERROR_COMMAND_SYNTAX_ERROR; /* both widths must: @@ -826,7 +836,7 @@ FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command) } cfi_info = malloc(sizeof(struct cfi_flash_bank)); - cfi_info->probed = 0; + cfi_info->probed = false; cfi_info->erase_region_info = NULL; cfi_info->pri_ext = NULL; bank->driver_priv = cfi_info; @@ -836,14 +846,14 @@ FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command) cfi_info->not_cfi = 0; cfi_info->data_swap = 0; - for (unsigned i = 6; i < CMD_ARGC; i++) { - if (strcmp(CMD_ARGV[i], "x16_as_x8") == 0) + for (unsigned i = 6; i < argc; i++) { + if (strcmp(argv[i], "x16_as_x8") == 0) cfi_info->x16_as_x8 = 1; - else if (strcmp(CMD_ARGV[i], "data_swap") == 0) + else if (strcmp(argv[i], "data_swap") == 0) cfi_info->data_swap = 1; - else if (strcmp(CMD_ARGV[i], "bus_swap") == 0) + else if (strcmp(argv[i], "bus_swap") == 0) bus_swap = 1; - else if (strcmp(CMD_ARGV[i], "jedec_probe") == 0) + else if (strcmp(argv[i], "jedec_probe") == 0) cfi_info->jedec_probe = 1; } @@ -860,20 +870,26 @@ FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command) return ERROR_OK; } +/* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#> [options] + */ +FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command) +{ + return cfi_flash_bank_cmd(bank, CMD_ARGC, CMD_ARGV); +} + static int cfi_intel_erase(struct flash_bank *bank, int first, int last) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; - int i; cfi_intel_clear_status_register(bank); - for (i = first; i <= last; i++) { - retval = cfi_send_command(bank, 0x20, flash_address(bank, i, 0x0)); + for (int i = first; i <= last; i++) { + retval = cfi_send_command(bank, 0x20, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0xd0, flash_address(bank, i, 0x0)); + retval = cfi_send_command(bank, 0xd0, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; @@ -885,7 +901,7 @@ static int cfi_intel_erase(struct flash_bank *bank, int first, int last) if (status == 0x80) bank->sectors[i].is_erased = 1; else { - retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -895,45 +911,53 @@ static int cfi_intel_erase(struct flash_bank *bank, int first, int last) } } - return cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); + return cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); } -static int cfi_spansion_erase(struct flash_bank *bank, int first, int last) +int cfi_spansion_unlock_seq(struct flash_bank *bank) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; - int i; - for (i = first; i <= last; i++) { - retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1)); - if (retval != ERROR_OK) - return retval; + retval = cfi_send_command(bank, 0xaa, cfi_flash_address(bank, 0, pri_ext->_unlock1)); + if (retval != ERROR_OK) + return retval; - retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2)); - if (retval != ERROR_OK) - return retval; + retval = cfi_send_command(bank, 0x55, cfi_flash_address(bank, 0, pri_ext->_unlock2)); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} - retval = cfi_send_command(bank, 0x80, flash_address(bank, 0, pri_ext->_unlock1)); +static int cfi_spansion_erase(struct flash_bank *bank, int first, int last) +{ + int retval; + struct cfi_flash_bank *cfi_info = bank->driver_priv; + struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; + + for (int i = first; i <= last; i++) { + retval = cfi_spansion_unlock_seq(bank); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1)); + retval = cfi_send_command(bank, 0x80, cfi_flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2)); + retval = cfi_spansion_unlock_seq(bank); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0x30, flash_address(bank, i, 0x0)); + retval = cfi_send_command(bank, 0x30, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; if (cfi_spansion_wait_status_busy(bank, cfi_info->block_erase_timeout) == ERROR_OK) bank->sectors[i].is_erased = 1; else { - retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -943,10 +967,10 @@ static int cfi_spansion_erase(struct flash_bank *bank, int first, int last) } } - return cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); + return cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); } -static int cfi_erase(struct flash_bank *bank, int first, int last) +int cfi_erase(struct flash_bank *bank, int first, int last) { struct cfi_flash_bank *cfi_info = bank->driver_priv; @@ -965,10 +989,8 @@ static int cfi_erase(struct flash_bank *bank, int first, int last) case 1: case 3: return cfi_intel_erase(bank, first, last); - break; case 2: return cfi_spansion_erase(bank, first, last); - break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; @@ -983,7 +1005,6 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext; int retry = 0; - int i; /* if the device supports neither legacy lock/unlock (bit 3) nor * instant individual block locking (bit 5). @@ -995,17 +1016,17 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la cfi_intel_clear_status_register(bank); - for (i = first; i <= last; i++) { - retval = cfi_send_command(bank, 0x60, flash_address(bank, i, 0x0)); + for (int i = first; i <= last; i++) { + retval = cfi_send_command(bank, 0x60, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; if (set) { - retval = cfi_send_command(bank, 0x01, flash_address(bank, i, 0x0)); + retval = cfi_send_command(bank, 0x01, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; bank->sectors[i].is_protected = 1; } else { - retval = cfi_send_command(bank, 0xd0, flash_address(bank, i, 0x0)); + retval = cfi_send_command(bank, 0xd0, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; bank->sectors[i].is_protected = 0; @@ -1022,7 +1043,7 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la } else { uint8_t block_status; /* read block lock bit, to verify status */ - retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, 0x55)); + retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, 0x55)); if (retval != ERROR_OK) return retval; retval = cfi_get_u8(bank, i, 0x2, &block_status); @@ -1033,7 +1054,7 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la LOG_ERROR( "couldn't change block lock status (set = %i, block_status = 0x%2.2x)", set, block_status); - retval = cfi_send_command(bank, 0x70, flash_address(bank, 0, 0x55)); + retval = cfi_send_command(bank, 0x70, cfi_flash_address(bank, 0, 0x55)); if (retval != ERROR_OK) return retval; uint8_t status; @@ -1066,15 +1087,15 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la * 3. re-protect what should be protected. * */ - for (i = 0; i < bank->num_sectors; i++) { + for (int i = 0; i < bank->num_sectors; i++) { if (bank->sectors[i].is_protected == 1) { cfi_intel_clear_status_register(bank); - retval = cfi_send_command(bank, 0x60, flash_address(bank, i, 0x0)); + retval = cfi_send_command(bank, 0x60, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0x01, flash_address(bank, i, 0x0)); + retval = cfi_send_command(bank, 0x01, cfi_flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; @@ -1086,10 +1107,10 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la } } - return cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); + return cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); } -static int cfi_protect(struct flash_bank *bank, int set, int first, int last) +int cfi_protect(struct flash_bank *bank, int set, int first, int last) { struct cfi_flash_bank *cfi_info = bank->driver_priv; @@ -1105,7 +1126,6 @@ static int cfi_protect(struct flash_bank *bank, int set, int first, int last) case 1: case 3: return cfi_intel_protect(bank, set, first, last); - break; default: LOG_WARNING("protect: cfi primary command set %i unsupported", cfi_info->pri_id); return ERROR_OK; @@ -1121,13 +1141,10 @@ static uint32_t cfi_command_val(struct flash_bank *bank, uint8_t cmd) switch (bank->bus_width) { case 1: return buf[0]; - break; case 2: return target_buffer_get_u16(target, buf); - break; case 4: return target_buffer_get_u32(target, buf); - break; default: LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width); @@ -1558,9 +1575,9 @@ static int cfi_spansion_write_block_mips(struct flash_bank *bank, const uint8_t buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width); buf_set_u32(reg_params[3].value, 0, 32, cfi_command_val(bank, 0xA0)); buf_set_u32(reg_params[4].value, 0, 32, cfi_command_val(bank, 0x80)); - buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock1)); + buf_set_u32(reg_params[6].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock1)); buf_set_u32(reg_params[7].value, 0, 32, 0xaaaaaaaa); - buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock2)); + buf_set_u32(reg_params[8].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock2)); buf_set_u32(reg_params[9].value, 0, 32, 0x55555555); retval = target_run_algorithm(target, 0, NULL, 10, reg_params, @@ -1937,9 +1954,9 @@ static int cfi_spansion_write_block(struct flash_bank *bank, const uint8_t *buff buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width); buf_set_u32(reg_params[3].value, 0, 32, cfi_command_val(bank, 0xA0)); buf_set_u32(reg_params[4].value, 0, 32, cfi_command_val(bank, 0x80)); - buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock1)); + buf_set_u32(reg_params[6].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock1)); buf_set_u32(reg_params[7].value, 0, 32, 0xaaaaaaaa); - buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock2)); + buf_set_u32(reg_params[8].value, 0, 32, cfi_flash_address(bank, 0, pri_ext->_unlock2)); buf_set_u32(reg_params[9].value, 0, 32, 0x55555555); retval = target_run_algorithm(target, 0, NULL, 10, reg_params, @@ -1981,14 +1998,13 @@ static int cfi_intel_write_word(struct flash_bank *bank, uint8_t *word, uint32_t { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; - struct target *target = bank->target; cfi_intel_clear_status_register(bank); retval = cfi_send_command(bank, 0x40, address); if (retval != ERROR_OK) return retval; - retval = target_write_memory(target, address, bank->bus_width, 1, word); + retval = cfi_target_write_memory(bank, address, 1, word); if (retval != ERROR_OK) return retval; @@ -1997,7 +2013,7 @@ static int cfi_intel_write_word(struct flash_bank *bank, uint8_t *word, uint32_t if (retval != ERROR_OK) return retval; if (status != 0x80) { - retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -2015,7 +2031,6 @@ static int cfi_intel_write_words(struct flash_bank *bank, const uint8_t *word, { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; - struct target *target = bank->target; /* Calculate buffer size and boundary mask * buffersize is (buffer size per chip) * (number of chips) @@ -2052,7 +2067,7 @@ static int cfi_intel_write_words(struct flash_bank *bank, const uint8_t *word, if (retval != ERROR_OK) return retval; if (status != 0x80) { - retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -2069,7 +2084,7 @@ static int cfi_intel_write_words(struct flash_bank *bank, const uint8_t *word, if (retval != ERROR_OK) return retval; - retval = target_write_memory(target, address, bank->bus_width, bufferwsize, word); + retval = cfi_target_write_memory(bank, address, bufferwsize, word); if (retval != ERROR_OK) return retval; @@ -2083,7 +2098,7 @@ static int cfi_intel_write_words(struct flash_bank *bank, const uint8_t *word, return retval; if (status != 0x80) { - retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -2100,26 +2115,21 @@ static int cfi_spansion_write_word(struct flash_bank *bank, uint8_t *word, uint3 int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; - struct target *target = bank->target; - - retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1)); - if (retval != ERROR_OK) - return retval; - retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2)); + retval = cfi_spansion_unlock_seq(bank); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0xa0, flash_address(bank, 0, pri_ext->_unlock1)); + retval = cfi_send_command(bank, 0xa0, cfi_flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; - retval = target_write_memory(target, address, bank->bus_width, 1, word); + retval = cfi_target_write_memory(bank, address, 1, word); if (retval != ERROR_OK) return retval; if (cfi_spansion_wait_status_busy(bank, cfi_info->word_write_timeout) != ERROR_OK) { - retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -2136,8 +2146,6 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; - struct target *target = bank->target; - struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; /* Calculate buffer size and boundary mask * buffersize is (buffer size per chip) * (number of chips) @@ -2163,11 +2171,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word } /* Unlock */ - retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1)); - if (retval != ERROR_OK) - return retval; - - retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2)); + retval = cfi_spansion_unlock_seq(bank); if (retval != ERROR_OK) return retval; @@ -2181,7 +2185,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word if (retval != ERROR_OK) return retval; - retval = target_write_memory(target, address, bank->bus_width, bufferwsize, word); + retval = cfi_target_write_memory(bank, address, bufferwsize, word); if (retval != ERROR_OK) return retval; @@ -2191,7 +2195,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word return retval; if (cfi_spansion_wait_status_busy(bank, cfi_info->buf_write_timeout) != ERROR_OK) { - retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); + retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; @@ -2204,7 +2208,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, const uint8_t *word return ERROR_OK; } -static int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address) +int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address) { struct cfi_flash_bank *cfi_info = bank->driver_priv; @@ -2212,10 +2216,8 @@ static int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t addre case 1: case 3: return cfi_intel_write_word(bank, word, address); - break; case 2: return cfi_spansion_write_word(bank, word, address); - break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; @@ -2239,10 +2241,8 @@ static int cfi_write_words(struct flash_bank *bank, const uint8_t *word, case 1: case 3: return cfi_intel_write_words(bank, word, wordcount, address); - break; case 2: return cfi_spansion_write_words(bank, word, wordcount, address); - break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; @@ -2254,12 +2254,10 @@ static int cfi_write_words(struct flash_bank *bank, const uint8_t *word, static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct cfi_flash_bank *cfi_info = bank->driver_priv; - struct target *target = bank->target; uint32_t address = bank->base + offset; uint32_t read_p; int align; /* number of unaligned bytes */ uint8_t current_word[CFI_MAX_BUS_WIDTH]; - int i; int retval; LOG_DEBUG("reading buffer of %i byte at 0x%8.8x", @@ -2283,12 +2281,12 @@ static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, u LOG_INFO("Fixup %d unaligned read head bytes", align); /* read a complete word from flash */ - retval = target_read_memory(target, read_p, bank->bus_width, 1, current_word); + retval = cfi_target_read_memory(bank, read_p, 1, current_word); if (retval != ERROR_OK) return retval; /* take only bytes we need */ - for (i = align; (i < bank->bus_width) && (count > 0); i++, count--) + for (int i = align; (i < bank->bus_width) && (count > 0); i++, count--) *buffer++ = current_word[i]; read_p += bank->bus_width; @@ -2296,7 +2294,7 @@ static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, u align = count / bank->bus_width; if (align) { - retval = target_read_memory(target, read_p, bank->bus_width, align, buffer); + retval = cfi_target_read_memory(bank, read_p, align, buffer); if (retval != ERROR_OK) return retval; @@ -2309,12 +2307,12 @@ static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, u LOG_INFO("Fixup %" PRIu32 " unaligned read tail bytes", count); /* read a complete word from flash */ - retval = target_read_memory(target, read_p, bank->bus_width, 1, current_word); + retval = cfi_target_read_memory(bank, read_p, 1, current_word); if (retval != ERROR_OK) return retval; /* take only bytes we need */ - for (i = 0; (i < bank->bus_width) && (count > 0); i++, count--) + for (int i = 0; (i < bank->bus_width) && (count > 0); i++, count--) *buffer++ = current_word[i]; } @@ -2324,7 +2322,6 @@ static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, u static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct cfi_flash_bank *cfi_info = bank->driver_priv; - struct target *target = bank->target; uint32_t address = bank->base + offset; /* address of first byte to be programmed */ uint32_t write_p; int align; /* number of unaligned bytes */ @@ -2333,7 +2330,6 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of *programmed */ uint8_t *swapped_buffer = NULL; const uint8_t *real_buffer = NULL; - int i; int retval; if (bank->target->state != TARGET_HALTED) { @@ -2354,12 +2350,12 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of LOG_INFO("Fixup %d unaligned head bytes", align); /* read a complete word from flash */ - retval = target_read_memory(target, write_p, bank->bus_width, 1, current_word); + retval = cfi_target_read_memory(bank, write_p, 1, current_word); if (retval != ERROR_OK) return retval; /* replace only bytes that must be written */ - for (i = align; + for (int i = align; (i < bank->bus_width) && (count > 0); i++, count--) if (cfi_info->data_swap) @@ -2425,12 +2421,12 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of /* fall back to memory writes */ while (count >= (uint32_t)bank->bus_width) { - int fallback; + bool fallback; if ((write_p & 0xff) == 0) { LOG_INFO("Programming at 0x%08" PRIx32 ", count 0x%08" PRIx32 " bytes remaining", write_p, count); } - fallback = 1; + fallback = true; if ((bufferwsize > 0) && (count >= buffersize) && !(write_p & buffermask)) { retval = cfi_write_words(bank, buffer, bufferwsize, write_p); @@ -2438,13 +2434,13 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of buffer += buffersize; write_p += buffersize; count -= buffersize; - fallback = 0; + fallback = false; } else if (retval != ERROR_FLASH_OPER_UNSUPPORTED) return retval; } /* try the slow way? */ if (fallback) { - for (i = 0; i < bank->bus_width; i++) + for (int i = 0; i < bank->bus_width; i++) current_word[i] = *buffer++; retval = cfi_write_word(bank, current_word, write_p); @@ -2474,12 +2470,12 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of LOG_INFO("Fixup %" PRId32 " unaligned tail bytes", count); /* read a complete word from flash */ - retval = target_read_memory(target, write_p, bank->bus_width, 1, current_word); + retval = cfi_target_read_memory(bank, write_p, 1, current_word); if (retval != ERROR_OK) return retval; /* replace only bytes that must be written */ - for (i = 0; (i < bank->bus_width) && (count > 0); i++, count--) + for (int i = 0; (i < bank->bus_width) && (count > 0); i++, count--) if (cfi_info->data_swap) /* data bytes are swapped (reverse endianness) */ current_word[bank->bus_width - i] = *buffer++; @@ -2506,7 +2502,6 @@ static void cfi_fixup_reversed_erase_regions(struct flash_bank *bank, const void static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, const void *param) { - int i; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; (void) param; @@ -2514,7 +2509,7 @@ static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, const void *pa if ((pri_ext->_reversed_geometry) || (pri_ext->TopBottom == 3)) { LOG_DEBUG("swapping reversed erase region information on cmdset 0002 device"); - for (i = 0; i < cfi_info->num_erase_regions / 2; i++) { + for (unsigned int i = 0; i < cfi_info->num_erase_regions / 2; i++) { int j = (cfi_info->num_erase_regions - 1) - i; uint32_t swap; @@ -2549,7 +2544,7 @@ static int cfi_query_string(struct flash_bank *bank, int address) struct cfi_flash_bank *cfi_info = bank->driver_priv; int retval; - retval = cfi_send_command(bank, 0x98, flash_address(bank, 0, address)); + retval = cfi_send_command(bank, 0x98, cfi_flash_address(bank, 0, address)); if (retval != ERROR_OK) return retval; @@ -2577,12 +2572,11 @@ static int cfi_query_string(struct flash_bank *bank, int address) return ERROR_OK; } -static int cfi_probe(struct flash_bank *bank) +int cfi_probe(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; struct target *target = bank->target; int num_sectors = 0; - int i; int sector = 0; uint32_t unlock1 = 0x555; uint32_t unlock2 = 0x2aa; @@ -2594,7 +2588,7 @@ static int cfi_probe(struct flash_bank *bank) return ERROR_TARGET_NOT_HALTED; } - cfi_info->probed = 0; + cfi_info->probed = false; cfi_info->num_erase_regions = 0; if (bank->sectors) { free(bank->sectors); @@ -2614,22 +2608,22 @@ static int cfi_probe(struct flash_bank *bank) } /* switch to read identifier codes mode ("AUTOSELECT") */ - retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, unlock1)); + retval = cfi_send_command(bank, 0xaa, cfi_flash_address(bank, 0, unlock1)); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, unlock2)); + retval = cfi_send_command(bank, 0x55, cfi_flash_address(bank, 0, unlock2)); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, unlock1)); + retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, unlock1)); if (retval != ERROR_OK) return retval; - retval = target_read_memory(target, flash_address(bank, 0, 0x00), - bank->bus_width, 1, value_buf0); + retval = cfi_target_read_memory(bank, cfi_flash_address(bank, 0, 0x00), + 1, value_buf0); if (retval != ERROR_OK) return retval; - retval = target_read_memory(target, flash_address(bank, 0, 0x01), - bank->bus_width, 1, value_buf1); + retval = cfi_target_read_memory(bank, cfi_flash_address(bank, 0, 0x01), + 1, value_buf1); if (retval != ERROR_OK) return retval; switch (bank->chip_width) { @@ -2766,7 +2760,7 @@ static int cfi_probe(struct flash_bank *bank) if (cfi_info->num_erase_regions) { cfi_info->erase_region_info = malloc(sizeof(*cfi_info->erase_region_info) * cfi_info->num_erase_regions); - for (i = 0; i < cfi_info->num_erase_regions; i++) { + for (unsigned int i = 0; i < cfi_info->num_erase_regions; i++) { retval = cfi_query_u32(bank, 0, 0x2d + (4 * i), @@ -2881,15 +2875,14 @@ static int cfi_probe(struct flash_bank *bank) } else { uint32_t offset = 0; - for (i = 0; i < cfi_info->num_erase_regions; i++) + for (unsigned int i = 0; i < cfi_info->num_erase_regions; i++) num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1; bank->num_sectors = num_sectors; bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); - for (i = 0; i < cfi_info->num_erase_regions; i++) { - uint32_t j; - for (j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++) { + for (unsigned int i = 0; i < cfi_info->num_erase_regions; i++) { + for (uint32_t j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++) { bank->sectors[sector].offset = offset; bank->sectors[sector].size = ((cfi_info->erase_region_info[i] >> 16) * 256) @@ -2902,18 +2895,18 @@ static int cfi_probe(struct flash_bank *bank) } if (offset != (cfi_info->dev_size * bank->bus_width / bank->chip_width)) { LOG_WARNING( - "CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "", \ + "CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "", (cfi_info->dev_size * bank->bus_width / bank->chip_width), offset); } } - cfi_info->probed = 1; + cfi_info->probed = true; return ERROR_OK; } -static int cfi_auto_probe(struct flash_bank *bank) +int cfi_auto_probe(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (cfi_info->probed) @@ -2926,17 +2919,16 @@ static int cfi_intel_protect_check(struct flash_bank *bank) int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext; - int i; /* check if block lock bits are supported on this device */ if (!(pri_ext->blk_status_reg_mask & 0x1)) return ERROR_FLASH_OPERATION_FAILED; - retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, 0x55)); + retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, 0x55)); if (retval != ERROR_OK) return retval; - for (i = 0; i < bank->num_sectors; i++) { + for (int i = 0; i < bank->num_sectors; i++) { uint8_t block_status; retval = cfi_get_u8(bank, i, 0x2, &block_status); if (retval != ERROR_OK) @@ -2948,7 +2940,7 @@ static int cfi_intel_protect_check(struct flash_bank *bank) bank->sectors[i].is_protected = 0; } - return cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); + return cfi_send_command(bank, 0xff, cfi_flash_address(bank, 0, 0x0)); } static int cfi_spansion_protect_check(struct flash_bank *bank) @@ -2956,21 +2948,16 @@ static int cfi_spansion_protect_check(struct flash_bank *bank) int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; - int i; - retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1)); + retval = cfi_spansion_unlock_seq(bank); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2)); + retval = cfi_send_command(bank, 0x90, cfi_flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; - retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, pri_ext->_unlock1)); - if (retval != ERROR_OK) - return retval; - - for (i = 0; i < bank->num_sectors; i++) { + for (int i = 0; i < bank->num_sectors; i++) { uint8_t block_status; retval = cfi_get_u8(bank, i, 0x2, &block_status); if (retval != ERROR_OK) @@ -2982,10 +2969,10 @@ static int cfi_spansion_protect_check(struct flash_bank *bank) bank->sectors[i].is_protected = 0; } - return cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); + return cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); } -static int cfi_protect_check(struct flash_bank *bank) +int cfi_protect_check(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; @@ -3001,10 +2988,8 @@ static int cfi_protect_check(struct flash_bank *bank) case 1: case 3: return cfi_intel_protect_check(bank); - break; case 2: return cfi_spansion_protect_check(bank); - break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; @@ -3013,7 +2998,7 @@ static int cfi_protect_check(struct flash_bank *bank) return ERROR_OK; } -static int get_cfi_info(struct flash_bank *bank, char *buf, int buf_size) +int cfi_get_info(struct flash_bank *bank, char *buf, int buf_size) { int printed; struct cfi_flash_bank *cfi_info = bank->driver_priv; @@ -3124,6 +3109,6 @@ const struct flash_driver cfi_flash = { /* FIXME: access flash at bus_width size */ .erase_check = default_flash_blank_check, .protect_check = cfi_protect_check, - .info = get_cfi_info, + .info = cfi_get_info, .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/cfi.h b/src/flash/nor/cfi.h index ed858a9..aef7a04 100644 --- a/src/flash/nor/cfi.h +++ b/src/flash/nor/cfi.h @@ -73,6 +73,12 @@ struct cfi_flash_bank { unsigned buf_write_timeout; unsigned block_erase_timeout; unsigned chip_erase_timeout; + + /* memory accessors */ + int (*write_mem)(struct flash_bank *bank, target_addr_t addr, + uint32_t count, const uint8_t *buffer); + int (*read_mem)(struct flash_bank *bank, target_addr_t addr, + uint32_t count, uint8_t *buffer); }; /* Intel primary extended query table @@ -148,6 +154,24 @@ struct cfi_fixup { const void *param; }; +int cfi_erase(struct flash_bank *bank, int first, int last); +int cfi_protect(struct flash_bank *bank, int set, int first, int last); +int cfi_probe(struct flash_bank *bank); +int cfi_auto_probe(struct flash_bank *bank); +int cfi_protect_check(struct flash_bank *bank); +int cfi_get_info(struct flash_bank *bank, char *buf, int buf_size); +int cfi_flash_bank_cmd(struct flash_bank *bank, unsigned int argc, const char **argv); + +uint32_t cfi_flash_address(struct flash_bank *bank, int sector, uint32_t offset); +int cfi_spansion_unlock_seq(struct flash_bank *bank); +int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t address); +int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address); +int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout); +int cfi_reset(struct flash_bank *bank); + +int cfi_target_read_memory(struct flash_bank *bank, target_addr_t addr, + uint32_t count, uint8_t *buffer); + #define CFI_MFR_AMD 0x0001 #define CFI_MFR_FUJITSU 0x0004 #define CFI_MFR_ATMEL 0x001F @@ -160,4 +184,7 @@ struct cfi_fixup { #define CFI_MFR_ANY 0xffff #define CFI_ID_ANY 0xffff +#define CFI_MAX_BUS_WIDTH 4 +#define CFI_MAX_CHIP_WIDTH 4 + #endif /* OPENOCD_FLASH_NOR_CFI_H */ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 551f389..d52e072 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -66,6 +66,8 @@ extern const struct flash_driver psoc5lp_flash; extern const struct flash_driver psoc5lp_eeprom_flash; extern const struct flash_driver psoc5lp_nvl_flash; extern const struct flash_driver psoc6_flash; +extern const struct flash_driver renesas_rpchf_flash; +extern const struct flash_driver sh_qspi_flash; extern const struct flash_driver sim3x_flash; extern const struct flash_driver stellaris_flash; extern const struct flash_driver stm32f1x_flash; @@ -136,6 +138,8 @@ static const struct flash_driver * const flash_drivers[] = { &psoc5lp_eeprom_flash, &psoc5lp_nvl_flash, &psoc6_flash, + &renesas_rpchf_flash, + &sh_qspi_flash, &sim3x_flash, &stellaris_flash, &stm32f1x_flash, diff --git a/src/flash/nor/dsp5680xx_flash.c b/src/flash/nor/dsp5680xx_flash.c index 37b60f0..da67585 100644 --- a/src/flash/nor/dsp5680xx_flash.c +++ b/src/flash/nor/dsp5680xx_flash.c @@ -154,7 +154,7 @@ static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, int first, * * @return */ -static int dsp5680xx_flash_write(struct flash_bank *bank, const uint8_t* buffer, +static int dsp5680xx_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int retval; diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c index 83d133f..fe4ddd4 100644 --- a/src/flash/nor/efm32.c +++ b/src/flash/nor/efm32.c @@ -99,7 +99,7 @@ struct efm32_family_data { }; struct efm32x_flash_bank { - int probed; + bool probed; uint32_t lb_page[LOCKBITS_PAGE_SZ/4]; uint32_t reg_base; uint32_t reg_lock; @@ -140,6 +140,7 @@ static const struct efm32_family_data efm32_families[] = { { 43, "EFR32BG13P Blue", .series = 1 }, { 44, "EFR32BG13B Blue", .series = 1 }, { 45, "EFR32BG13V Blue", .series = 1 }, + { 46, "EFR32ZG13P Zen", .series = 1 }, { 49, "EFR32FG13P Flex", .series = 1 }, { 50, "EFR32FG13B Flex", .series = 1 }, { 51, "EFR32FG13V Flex", .series = 1 }, @@ -149,6 +150,7 @@ static const struct efm32_family_data efm32_families[] = { { 55, "EFR32BG14P Blue", .series = 1 }, { 56, "EFR32BG14B Blue", .series = 1 }, { 57, "EFR32BG14V Blue", .series = 1 }, + { 58, "EFR32ZG14P Zen", .series = 1 }, { 61, "EFR32FG14P Flex", .series = 1 }, { 62, "EFR32FG14B Flex", .series = 1 }, { 63, "EFR32FG14V Flex", .series = 1 }, @@ -166,7 +168,8 @@ static const struct efm32_family_data efm32_families[] = { { 89, "EFM32PG13B Pearl", .series = 1 }, { 91, "EFM32JG13B Jade", .series = 1 }, { 100, "EFM32GG11B Giant", .series = 1, .msc_regbase = 0x40000000 }, - { 103, "EFM32TG11B Tiny", .series = 1 }, + { 103, "EFM32TG11B Tiny", .series = 1, .msc_regbase = 0x40000000 }, + { 106, "EFM32GG12B Giant", .series = 1, .msc_regbase = 0x40000000 }, { 120, "EZR32WG Wonder", .series = 0 }, { 121, "EZR32LG Leopard", .series = 0 }, { 122, "EZR32HG Happy", .series = 0, .page_size = 1024 }, @@ -348,7 +351,7 @@ FLASH_BANK_COMMAND_HANDLER(efm32x_flash_bank_command) efm32x_info = malloc(sizeof(struct efm32x_flash_bank)); bank->driver_priv = efm32x_info; - efm32x_info->probed = 0; + efm32x_info->probed = false; memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ); return ERROR_OK; @@ -467,7 +470,6 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr) static int efm32x_erase(struct flash_bank *bank, int first, int last) { struct target *target = bank->target; - int i = 0; int ret = 0; if (TARGET_HALTED != target->state) { @@ -482,7 +484,7 @@ static int efm32x_erase(struct flash_bank *bank, int first, int last) return ret; } - for (i = first; i <= last; i++) { + for (int i = first; i <= last; i++) { ret = efm32x_erase_page(bank, bank->sectors[i].offset); if (ERROR_OK != ret) LOG_ERROR("Failed to erase page %d", i); @@ -498,7 +500,6 @@ static int efm32x_read_lock_data(struct flash_bank *bank) { struct efm32x_flash_bank *efm32x_info = bank->driver_priv; struct target *target = bank->target; - int i = 0; int data_size = 0; uint32_t *ptr = NULL; int ret = 0; @@ -510,7 +511,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank) ptr = efm32x_info->lb_page; - for (i = 0; i < data_size; i++, ptr++) { + for (int i = 0; i < data_size; i++, ptr++) { ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+i*4, ptr); if (ERROR_OK != ret) { LOG_ERROR("Failed to read PLW %d", i); @@ -616,7 +617,6 @@ static int efm32x_set_page_lock(struct flash_bank *bank, size_t page, int set) static int efm32x_protect(struct flash_bank *bank, int set, int first, int last) { struct target *target = bank->target; - int i = 0; int ret = 0; if (!set) { @@ -629,7 +629,7 @@ static int efm32x_protect(struct flash_bank *bank, int set, int first, int last) return ERROR_TARGET_NOT_HALTED; } - for (i = first; i <= last; i++) { + for (int i = first; i <= last; i++) { ret = efm32x_set_page_lock(bank, i, set); if (ERROR_OK != ret) { LOG_ERROR("Failed to set lock on page %d", i); @@ -960,11 +960,10 @@ static int efm32x_probe(struct flash_bank *bank) struct efm32x_flash_bank *efm32x_info = bank->driver_priv; struct efm32_info efm32_mcu_info; int ret; - int i; uint32_t base_address = 0x00000000; char buf[256]; - efm32x_info->probed = 0; + efm32x_info->probed = false; memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ); ret = efm32x_read_info(bank, &efm32_mcu_info); @@ -1003,14 +1002,14 @@ static int efm32x_probe(struct flash_bank *bank) bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); - for (i = 0; i < num_pages; i++) { + for (int i = 0; i < num_pages; i++) { bank->sectors[i].offset = i * efm32_mcu_info.page_size; bank->sectors[i].size = efm32_mcu_info.page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } - efm32x_info->probed = 1; + efm32x_info->probed = true; return ERROR_OK; } @@ -1027,7 +1026,6 @@ static int efm32x_protect_check(struct flash_bank *bank) { struct target *target = bank->target; int ret = 0; - int i = 0; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -1042,7 +1040,7 @@ static int efm32x_protect_check(struct flash_bank *bank) assert(NULL != bank->sectors); - for (i = 0; i < bank->num_sectors; i++) + for (int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = efm32x_get_page_lock(bank, i); return ERROR_OK; diff --git a/src/flash/nor/fespi.c b/src/flash/nor/fespi.c index 6b05332..bc192b6 100644 --- a/src/flash/nor/fespi.c +++ b/src/flash/nor/fespi.c @@ -183,7 +183,7 @@ static int fespi_read_reg(struct flash_bank *bank, uint32_t *value, target_addr_ } static int fespi_write_reg(struct flash_bank *bank, target_addr_t address, uint32_t value) -{ \ +{ struct target *target = bank->target; struct fespi_flash_bank *fespi_info = bank->driver_priv; diff --git a/src/flash/nor/fm4.c b/src/flash/nor/fm4.c index a8877b4..7e3a1c5 100644 --- a/src/flash/nor/fm4.c +++ b/src/flash/nor/fm4.c @@ -207,7 +207,7 @@ static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t halfword_count = DIV_ROUND_UP(byte_count, 2); uint32_t result; unsigned i; - int retval; + int retval, retval2 = ERROR_OK; const uint8_t write_block_code[] = { #include "../../../contrib/loaders/flash/fm4/write.inc" }; @@ -327,7 +327,7 @@ static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer, err_run_ret: err_run: err_write_data: - retval = fm4_enter_flash_cpu_rom_mode(target); + retval2 = fm4_enter_flash_cpu_rom_mode(target); err_flash_mode: for (i = 0; i < ARRAY_SIZE(reg_params); i++) @@ -338,7 +338,9 @@ err_alloc_data: err_write_code: target_free_working_area(target, code_workarea); - return retval; + if (retval != ERROR_OK) + return retval; + return retval2; } static int mb9bf_probe(struct flash_bank *bank) diff --git a/src/flash/nor/jtagspi.c b/src/flash/nor/jtagspi.c index a9f2dd4..d841579 100644 --- a/src/flash/nor/jtagspi.c +++ b/src/flash/nor/jtagspi.c @@ -59,7 +59,7 @@ static void jtagspi_set_ir(struct flash_bank *bank) { struct jtagspi_flash_bank *info = bank->driver_priv; struct scan_field field; - uint8_t buf[4]; + uint8_t buf[4] = { 0 }; LOG_DEBUG("loading jtagspi ir"); buf_set_u32(buf, 0, info->tap->ir_length, info->ir); @@ -153,12 +153,12 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd, jtagspi_set_ir(bank); /* passing from an IR scan to SHIFT-DR clears BYPASS registers */ jtag_add_dr_scan(info->tap, n, fields, TAP_IDLE); - jtag_execute_queue(); + int retval = jtag_execute_queue(); if (is_read) flip_u8(data_buf, data, lenb); free(data_buf); - return ERROR_OK; + return retval; } static int jtagspi_probe(struct flash_bank *bank) @@ -228,13 +228,16 @@ static int jtagspi_probe(struct flash_bank *bank) return ERROR_OK; } -static void jtagspi_read_status(struct flash_bank *bank, uint32_t *status) +static int jtagspi_read_status(struct flash_bank *bank, uint32_t *status) { uint8_t buf; - if (jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, &buf, -8) == ERROR_OK) { + int err = jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, &buf, -8); + if (err == ERROR_OK) { *status = buf; /* LOG_DEBUG("status=0x%08" PRIx32, *status); */ } + + return err; } static int jtagspi_wait(struct flash_bank *bank, int timeout_ms) @@ -245,7 +248,11 @@ static int jtagspi_wait(struct flash_bank *bank, int timeout_ms) do { dt = timeval_ms() - t0; - jtagspi_read_status(bank, &status); + + int retval = jtagspi_read_status(bank, &status); + if (retval != ERROR_OK) + return retval; + if ((status & SPIFLASH_BSY_BIT) == 0) { LOG_DEBUG("waited %" PRId64 " ms", dt); return ERROR_OK; @@ -262,7 +269,11 @@ static int jtagspi_write_enable(struct flash_bank *bank) uint32_t status; jtagspi_cmd(bank, SPIFLASH_WRITE_ENABLE, NULL, NULL, 0); - jtagspi_read_status(bank, &status); + + int retval = jtagspi_read_status(bank, &status); + if (retval != ERROR_OK) + return retval; + if ((status & SPIFLASH_WE_BIT) == 0) { LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32, status); return ERROR_FAIL; diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index 687a337..084e009 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -787,9 +787,8 @@ COMMAND_HANDLER(kinetis_check_flash_security_status) if ((val & (MDM_STAT_SYSSEC | MDM_STAT_FREADY)) != MDM_STAT_FREADY) { uint32_t stats[32]; - int i; - for (i = 0; i < 32; i++) { + for (unsigned int i = 0; i < 32; i++) { stats[i] = MDM_STAT_FREADY; dap_queue_ap_read(dap_ap(dap, MDM_AP), MDM_REG_STAT, &stats[i]); } @@ -798,7 +797,7 @@ COMMAND_HANDLER(kinetis_check_flash_security_status) LOG_DEBUG("MDM: dap_run failed when validating secured state"); return ERROR_OK; } - for (i = 0; i < 32; i++) { + for (unsigned int i = 0; i < 32; i++) { if (stats[i] & MDM_STAT_SYSSEC) secured_score++; if (!(stats[i] & MDM_STAT_FREADY)) @@ -860,8 +859,7 @@ static struct kinetis_chip *kinetis_get_chip(struct target *target) static int kinetis_chip_options(struct kinetis_chip *k_chip, int argc, const char *argv[]) { - int i; - for (i = 0; i < argc; i++) { + for (int i = 0; i < argc; i++) { if (strcmp(argv[i], "-sim-base") == 0) { if (i + 1 < argc) k_chip->sim_base = strtoul(argv[++i], NULL, 0); @@ -933,7 +931,6 @@ static void kinetis_free_driver_priv(struct flash_bank *bank) static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) { - unsigned bank_idx; unsigned num_blocks; struct kinetis_flash_bank *k_bank; struct flash_bank *bank; @@ -968,7 +965,7 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) *p = '\0'; } - for (bank_idx = 1; bank_idx < num_blocks; bank_idx++) { + for (unsigned int bank_idx = 1; bank_idx < num_blocks; bank_idx++) { k_bank = &(k_chip->banks[bank_idx]); bank = k_bank->bank; @@ -1219,11 +1216,11 @@ static int kinetis_ftfx_clear_error(struct target *target) static int kinetis_ftfx_prepare(struct target *target) { - int result, i; + int result; uint8_t fstat; /* wait until busy */ - for (i = 0; i < 50; i++) { + for (unsigned int i = 0; i < 50; i++) { result = target_read_u8(target, FTFx_FSTAT, &fstat); if (result != ERROR_OK) return result; @@ -1343,8 +1340,6 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer, static int kinetis_protect(struct flash_bank *bank, int set, int first, int last) { - int i; - if (allow_fcf_writes) { LOG_ERROR("Protection setting is possible with 'kinetis fcf_source protection' only!"); return ERROR_FAIL; @@ -1355,7 +1350,7 @@ static int kinetis_protect(struct flash_bank *bank, int set, int first, int last return ERROR_FLASH_BANK_INVALID; } - for (i = first; i < bank->num_prot_blocks && i <= last; i++) + for (int i = first; i < bank->num_prot_blocks && i <= last; i++) bank->prot_blocks[i].is_protected = set; LOG_INFO("Protection bits will be written at the next FCF sector erase or write."); @@ -1369,7 +1364,7 @@ static int kinetis_protect_check(struct flash_bank *bank) { struct kinetis_flash_bank *k_bank = bank->driver_priv; int result; - int i, b; + int b; uint32_t fprot; if (k_bank->flash_class == FC_PFLASH) { @@ -1397,7 +1392,7 @@ static int kinetis_protect_check(struct flash_bank *bank) } b = k_bank->protection_block; - for (i = 0; i < bank->num_prot_blocks; i++) { + for (int i = 0; i < bank->num_prot_blocks; i++) { if ((fprot >> b) & 1) bank->prot_blocks[i].is_protected = 0; else @@ -1415,8 +1410,6 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) uint32_t fprot = 0xffffffff; uint8_t fsec = 0xfe; /* set MCU unsecure */ uint8_t fdprot = 0xff; - int i; - unsigned bank_idx; unsigned num_blocks; uint32_t pflash_bit; uint8_t dflash_bit; @@ -1432,7 +1425,7 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) /* iterate over all kinetis banks */ /* current bank is bank 0, it contains FCF */ num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks; - for (bank_idx = 0; bank_idx < num_blocks; bank_idx++) { + for (unsigned int bank_idx = 0; bank_idx < num_blocks; bank_idx++) { k_bank = &(k_chip->banks[bank_idx]); bank_iter = k_bank->bank; @@ -1443,8 +1436,10 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) kinetis_auto_probe(bank_iter); + assert(bank_iter->prot_blocks); + if (k_bank->flash_class == FC_PFLASH) { - for (i = 0; i < bank_iter->num_prot_blocks; i++) { + for (int i = 0; i < bank_iter->num_prot_blocks; i++) { if (bank_iter->prot_blocks[i].is_protected == 1) fprot &= ~pflash_bit; @@ -1452,7 +1447,7 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) } } else if (k_bank->flash_class == FC_FLEX_NVM) { - for (i = 0; i < bank_iter->num_prot_blocks; i++) { + for (int i = 0; i < bank_iter->num_prot_blocks; i++) { if (bank_iter->prot_blocks[i].is_protected == 1) fdprot &= ~dflash_bit; @@ -1540,7 +1535,7 @@ static int kinetis_read_pmstat(struct kinetis_chip *k_chip, uint8_t *pmstat) static int kinetis_check_run_mode(struct kinetis_chip *k_chip) { - int result, i; + int result; uint8_t pmstat; struct target *target; @@ -1578,7 +1573,7 @@ static int kinetis_check_run_mode(struct kinetis_chip *k_chip) if (result != ERROR_OK) return result; - for (i = 100; i; i--) { + for (unsigned int i = 100; i > 0; i--) { result = kinetis_read_pmstat(k_chip, &pmstat); if (result != ERROR_OK) return result; @@ -1623,7 +1618,7 @@ static void kinetis_invalidate_flash_cache(struct kinetis_chip *k_chip) static int kinetis_erase(struct flash_bank *bank, int first, int last) { - int result, i; + int result; struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_chip *k_chip = k_bank->k_chip; @@ -1644,7 +1639,7 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last) * requested erase is PFlash or NVM and encompasses the entire * block. Should be quicker. */ - for (i = first; i <= last; i++) { + for (int i = first; i <= last; i++) { /* set command and sector address */ result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTERASE, k_bank->prog_base + bank->sectors[i].offset, 0, 0, 0, 0, 0, 0, 0, 0, NULL); @@ -1798,6 +1793,8 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer buffer += size; offset += size; count -= size; + + keep_alive(); } free(buffer_aligned); @@ -1808,25 +1805,26 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { - int result, fallback = 0; + int result; + bool fallback = false; struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_chip *k_chip = k_bank->k_chip; if (!(k_chip->flash_support & FS_PROGRAM_SECTOR)) { /* fallback to longword write */ - fallback = 1; + fallback = true; LOG_INFO("This device supports Program Longword execution only."); } else { result = kinetis_make_ram_ready(bank->target); if (result != ERROR_OK) { - fallback = 1; + fallback = true; LOG_WARNING("FlexRAM not ready, fallback to slow longword write."); } } LOG_DEBUG("flash write @ " TARGET_ADDR_FMT, bank->base + offset); - if (fallback == 0) { + if (!fallback) { /* program section command */ kinetis_write_sections(bank, buffer, offset, count); } else if (k_chip->flash_support & FS_PROGRAM_LONGWORD) { @@ -1889,6 +1887,8 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, buffer += 4; offset += 4; words_remaining--; + + keep_alive(); } } free(new_buffer); @@ -2018,7 +2018,6 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) unsigned familyid = 0, subfamid = 0; unsigned cpu_mhz = 120; - unsigned idx; bool use_nvm_marking = false; char flash_marking[12], nvm_marking[2]; char name[40]; @@ -2113,7 +2112,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) LOG_ERROR("Unsupported K-family FAMID"); } - for (idx = 0; idx < ARRAY_SIZE(kinetis_types_old); idx++) { + for (size_t idx = 0; idx < ARRAY_SIZE(kinetis_types_old); idx++) { if (kinetis_types_old[idx].sdid == mcu_type) { strcpy(name, kinetis_types_old[idx].name); use_nvm_marking = true; @@ -2619,12 +2618,15 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) static int kinetis_probe(struct flash_bank *bank) { - int result, i; + int result; uint8_t fcfg2_maxaddr0, fcfg2_pflsh, fcfg2_maxaddr1; unsigned num_blocks, first_nvm_bank; uint32_t size_k; struct kinetis_flash_bank *k_bank = bank->driver_priv; - struct kinetis_chip *k_chip = k_bank->k_chip; + struct kinetis_chip *k_chip; + + assert(k_bank); + k_chip = k_bank->k_chip; k_bank->probed = false; @@ -2668,6 +2670,7 @@ static int kinetis_probe(struct flash_bank *bank) if (k_chip->dflash_size == 0) { k_bank->protection_size = 0; } else { + int i; for (i = k_chip->dflash_size; ~i & 1; i >>= 1) ; if (i == 1) @@ -2824,8 +2827,7 @@ static int kinetis_blank_check(struct flash_bank *bank) if (block_dirty) { /* the whole bank is not erased, check sector-by-sector */ - int i; - for (i = 0; i < bank->num_sectors; i++) { + for (int i = 0; i < bank->num_sectors; i++) { /* normal margin */ result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTSTAT, k_bank->prog_base + bank->sectors[i].offset, @@ -2841,8 +2843,7 @@ static int kinetis_blank_check(struct flash_bank *bank) } } else { /* the whole bank is erased, update all sectors */ - int i; - for (i = 0; i < bank->num_sectors; i++) + for (int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; } } else { diff --git a/src/flash/nor/kinetis_ke.c b/src/flash/nor/kinetis_ke.c index 27b6d3a..cfc0492 100644 --- a/src/flash/nor/kinetis_ke.c +++ b/src/flash/nor/kinetis_ke.c @@ -814,7 +814,7 @@ static int kinetis_ke_protect_check(struct flash_bank *bank) kinfo->protection_size = 0; } else { - LOG_WARNING("Flash protected. FPOPEN=%i FPLDIS=%i FPHDIS=%i FPLS=%i FPHS=%i", \ + LOG_WARNING("Flash protected. FPOPEN=%i FPLDIS=%i FPHDIS=%i FPLS=%i FPHS=%i", fpopen ? 1 : 0, fpldis ? 1 : 0, fphdis ? 1 : 0, fpls, fphs); /* Retrieve which region is protected and how much */ diff --git a/src/flash/nor/lpcspifi.c b/src/flash/nor/lpcspifi.c index 19d754b..04ac3bb 100644 --- a/src/flash/nor/lpcspifi.c +++ b/src/flash/nor/lpcspifi.c @@ -177,8 +177,8 @@ static int lpcspifi_set_hw_mode(struct flash_bank *bank) retval = target_alloc_working_area(target, sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE, &spifi_init_algorithm); if (retval != ERROR_OK) { - LOG_ERROR("Insufficient working area to initialize SPIFI "\ - "module. You must allocate at least %zdB of working "\ + LOG_ERROR("Insufficient working area to initialize SPIFI " + "module. You must allocate at least %zdB of working " "area in order to use this driver.", sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE ); @@ -452,7 +452,7 @@ static int lpcspifi_erase(struct flash_bank *bank, int first, int last) * it, use a bulk erase instead of going sector-by-sector. */ if (first == 0 && last == (bank->num_sectors - 1) && lpcspifi_info->dev->chip_erase_cmd != lpcspifi_info->dev->erase_cmd) { - LOG_DEBUG("Chip supports the bulk erase command."\ + LOG_DEBUG("Chip supports the bulk erase command." " Will use bulk erase instead of sector-by-sector erase."); retval = lpcspifi_bulk_erase(bank); @@ -525,7 +525,7 @@ static int lpcspifi_erase(struct flash_bank *bank, int first, int last) retval = target_alloc_working_area(target, sizeof(lpcspifi_flash_erase_code), &erase_algorithm); if (retval != ERROR_OK) { - LOG_ERROR("Insufficient working area. You must configure a working"\ + LOG_ERROR("Insufficient working area. You must configure a working" " area of at least %zdB in order to erase SPIFI flash.", sizeof(lpcspifi_flash_erase_code)); return retval; @@ -685,7 +685,7 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer, if (target_alloc_working_area(target, sizeof(lpcspifi_flash_write_code), &write_algorithm) != ERROR_OK) { - LOG_ERROR("Insufficient working area. You must configure"\ + LOG_ERROR("Insufficient working area. You must configure" " a working area > %zdB in order to write to SPIFI flash.", sizeof(lpcspifi_flash_write_code)); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; @@ -707,15 +707,15 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer, * space, free the algorithm */ target_free_working_area(target, write_algorithm); - LOG_ERROR("Insufficient working area. Please allocate at least"\ + LOG_ERROR("Insufficient working area. Please allocate at least" " %zdB of working area to enable flash writes.", sizeof(lpcspifi_flash_write_code) + 1 ); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } else if (fifo_size < page_size) - LOG_WARNING("Working area size is limited; flash writes may be"\ - " slow. Increase working area size to at least %zdB"\ + LOG_WARNING("Working area size is limited; flash writes may be" + " slow. Increase working area size to at least %zdB" " to reduce write times.", (size_t)(sizeof(lpcspifi_flash_write_code) + page_size) ); diff --git a/src/flash/nor/mrvlqspi.c b/src/flash/nor/mrvlqspi.c index 803e84a..7a06b3d 100644 --- a/src/flash/nor/mrvlqspi.c +++ b/src/flash/nor/mrvlqspi.c @@ -563,7 +563,7 @@ static int mrvlqspi_flash_erase(struct flash_bank *bank, int first, int last) if (first == 0 && last == (bank->num_sectors - 1) && mrvlqspi_info->dev->chip_erase_cmd != mrvlqspi_info->dev->erase_cmd) { - LOG_DEBUG("Chip supports the bulk erase command."\ + LOG_DEBUG("Chip supports the bulk erase command." " Will use bulk erase instead of sector-by-sector erase."); retval = mrvlqspi_bulk_erase(bank); if (retval == ERROR_OK) { @@ -681,7 +681,7 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer, if (target_alloc_working_area(target, sizeof(mrvlqspi_flash_write_code), &write_algorithm) != ERROR_OK) { - LOG_ERROR("Insufficient working area. You must configure"\ + LOG_ERROR("Insufficient working area. You must configure" " a working area > %zdB in order to write to SPIFI flash.", sizeof(mrvlqspi_flash_write_code)); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; @@ -703,15 +703,15 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer, * space, free the algorithm */ target_free_working_area(target, write_algorithm); - LOG_ERROR("Insufficient working area. Please allocate at least"\ + LOG_ERROR("Insufficient working area. Please allocate at least" " %zdB of working area to enable flash writes.", sizeof(mrvlqspi_flash_write_code) + 1 ); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } else if (fifo_size < page_size) - LOG_WARNING("Working area size is limited; flash writes may be"\ - " slow. Increase working area size to at least %zdB"\ + LOG_WARNING("Working area size is limited; flash writes may be" + " slow. Increase working area size to at least %zdB" " to reduce write times.", (size_t)(sizeof(mrvlqspi_flash_write_code) + page_size) ); diff --git a/src/flash/nor/msp432.c b/src/flash/nor/msp432.c index e9e4be3..95c99b9 100644 --- a/src/flash/nor/msp432.c +++ b/src/flash/nor/msp432.c @@ -49,7 +49,8 @@ struct msp432_bank { int family_type; int device_type; uint32_t sector_length; - bool probed[2]; + bool probed_main; + bool probed_info; bool unlock_bsl; struct working_area *working_area; struct armv7m_algorithm armv7m_info; @@ -194,8 +195,7 @@ static int msp432_exec_cmd(struct target *target, struct msp432_algo_params return retval; /* Write out command to target memory */ - retval = target_write_buffer(target, ALGO_FLASH_COMMAND_ADDR, - sizeof(command), (uint8_t *)&command); + retval = target_write_u32(target, ALGO_FLASH_COMMAND_ADDR, command); return retval; } @@ -210,8 +210,7 @@ static int msp432_wait_return_code(struct target *target) 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); + retval = target_read_u32(target, ALGO_RETURN_CODE_ADDR, &return_code); if (ERROR_OK != retval) return retval; @@ -253,8 +252,7 @@ static int msp432_wait_inactive(struct target *target, uint32_t buffer) start_ms = timeval_ms(); while (BUFFER_INACTIVE != status_code) { - retval = target_read_buffer(target, status_addr, sizeof(status_code), - (uint8_t *)&status_code); + retval = target_read_u32(target, status_addr, &status_code); if (ERROR_OK != retval) return retval; @@ -477,15 +475,23 @@ COMMAND_HANDLER(msp432_mass_erase_command) struct flash_bank *bank; struct msp432_bank *msp432_bank; bool all; + int retval; - if (0 == CMD_ARGC) { + if (1 > CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (retval != ERROR_OK) + return retval; + + if (1 == CMD_ARGC) { all = false; - } else if (1 == CMD_ARGC) { + } else if (2 == CMD_ARGC) { /* Check argument for how much to erase */ - if (0 == strcmp(CMD_ARGV[0], "main")) + if (0 == strcmp(CMD_ARGV[1], "main")) all = false; - else if (0 == strcmp(CMD_ARGV[0], "all")) + else if (0 == strcmp(CMD_ARGV[1], "all")) all = true; else return ERROR_COMMAND_SYNTAX_ERROR; @@ -493,10 +499,6 @@ COMMAND_HANDLER(msp432_mass_erase_command) 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) { @@ -513,7 +515,7 @@ COMMAND_HANDLER(msp432_mass_erase_command) 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"); + all ? "main + information flash" : "main flash"); } return ERROR_OK; @@ -523,13 +525,14 @@ COMMAND_HANDLER(msp432_bsl_command) { struct flash_bank *bank; struct msp432_bank *msp432_bank; + int retval; - if (1 < CMD_ARGC) + if (1 > CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; - retval = get_flash_bank_by_num(0, &bank); - if (ERROR_OK != retval) + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (retval != ERROR_OK) return retval; msp432_bank = bank->driver_priv; @@ -539,13 +542,16 @@ COMMAND_HANDLER(msp432_bsl_command) return ERROR_OK; } - if (1 == CMD_ARGC) { - if (0 == strcmp(CMD_ARGV[0], "lock")) + if (2 == CMD_ARGC) { + if (0 == strcmp(CMD_ARGV[1], "lock")) msp432_bank->unlock_bsl = false; - else if (0 == strcmp(CMD_ARGV[0], "unlock")) + else if (0 == strcmp(CMD_ARGV[1], "unlock")) msp432_bank->unlock_bsl = true; else return ERROR_COMMAND_SYNTAX_ERROR; + } else if (1 != CMD_ARGC) { + /* Extra, unknown argument passed in */ + return ERROR_COMMAND_SYNTAX_ERROR; } LOG_INFO("msp432: BSL flash region is currently %slocked", @@ -561,6 +567,7 @@ FLASH_BANK_COMMAND_HANDLER(msp432_flash_bank_command) if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; + /* Create shared private struct for flash banks */ msp432_bank = malloc(sizeof(struct msp432_bank)); if (NULL == msp432_bank) return ERROR_FAIL; @@ -571,14 +578,14 @@ FLASH_BANK_COMMAND_HANDLER(msp432_flash_bank_command) 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->probed_main = false; + msp432_bank->probed_info = false; msp432_bank->unlock_bsl = false; msp432_bank->working_area = NULL; - /* Finish initialization of bank 0 (main flash) */ + /* Finish up initial settings here */ bank->driver_priv = msp432_bank; - bank->next = NULL; + bank->base = FLASH_BASE; return ERROR_OK; } @@ -589,6 +596,9 @@ static int msp432_erase(struct flash_bank *bank, int first, int last) struct msp432_bank *msp432_bank = bank->driver_priv; struct msp432_algo_params algo_params; + bool is_main = FLASH_BASE == bank->base; + bool is_info = P4_FLASH_INFO_BASE == bank->base; + int retval; if (TARGET_HALTED != target->state) { @@ -597,8 +607,7 @@ static int msp432_erase(struct flash_bank *bank, int first, int last) } /* Do a mass erase if user requested all sectors of main flash */ - if ((0 == bank->bank_number) && (first == 0) && - (last == (bank->num_sectors - 1))) { + if (is_main && (first == 0) && (last == (bank->num_sectors - 1))) { /* Request mass erase of main flash */ return msp432_mass_erase(bank, false); } @@ -611,7 +620,7 @@ static int msp432_erase(struct flash_bank *bank, int first, int last) msp432_init_params(&algo_params); /* Adjust params if this is the info bank */ - if (1 == bank->bank_number) { + if (is_info) { buf_set_u32(algo_params.erase_param, 0, 32, FLASH_ERASE_INFO); /* And flag if BSL is unlocked */ if (msp432_bank->unlock_bsl) @@ -622,11 +631,11 @@ static int msp432_erase(struct flash_bank *bank, int first, int last) for (int i = first; i <= last; i++) { /* Skip TVL (read-only) sector of the info bank */ - if (1 == bank->bank_number && 1 == i) + if (is_info && 1 == i) continue; /* Skip BSL sectors of info bank if locked */ - if (1 == bank->bank_number && (2 == i || 3 == i) && + if (is_info && (2 == i || 3 == i) && !msp432_bank->unlock_bsl) continue; @@ -666,6 +675,8 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, long long start_ms; long long elapsed_ms; + bool is_info = P4_FLASH_INFO_BASE == bank->base; + int retval; if (TARGET_HALTED != target->state) { @@ -679,7 +690,7 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, * 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) { + if (is_info) { /* Set read-only start to TVL sector */ uint32_t start = 0x1000; /* Set read-only end after BSL region if locked */ @@ -722,7 +733,7 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, buf_set_u32(algo_params.length, 0, 32, count); /* Check if this is the info bank */ - if (1 == bank->bank_number) { + if (is_info) { /* And flag if BSL is unlocked */ if (msp432_bank->unlock_bsl) buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL); @@ -753,8 +764,8 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, } /* 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); + retval = target_write_u32(target, ALGO_BUFFER1_STATUS_ADDR, + data_ready); if (ERROR_OK != retval) { (void)msp432_quit(bank); return ERROR_FLASH_OPERATION_FAILED; @@ -793,20 +804,23 @@ 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; + + bool is_main = FLASH_BASE == bank->base; + bool is_info = P4_FLASH_INFO_BASE == bank->base; int retval; - bank_id = bank->bank_number; + /* Check if this bank has already been successfully probed */ + if (is_main && msp432_bank->probed_main) + return ERROR_OK; + if (is_info && msp432_bank->probed_info) + return ERROR_OK; /* Read the flash size register to determine this is a P4 or not */ /* MSP432P4s will return the size of flash. MSP432E4s will return zero */ @@ -849,63 +863,16 @@ static int msp432_probe(struct flash_bank *bank) 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) { + if (is_main) { 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) { + } else if (is_info) { if (msp432_bank->device_type == MSP432P411X || msp432_bank->device_type == MSP432P411X_GUESS) { /* MSP432P411x has an info size register, use that for size */ @@ -916,19 +883,22 @@ static int msp432_probe(struct flash_bank *bank) /* 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 */ + /* Invalid bank 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 (is_main) { + size = E4_FLASH_SIZE; + sector_length = E4_SECTOR_LENGTH; + num_sectors = size / sector_length; + } else { + /* Invalid bank somehow */ + return ERROR_FAIL; + } } if (NULL != bank->sectors) { @@ -936,11 +906,12 @@ static int msp432_probe(struct flash_bank *bank) bank->sectors = NULL; } - bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); - if (NULL == bank->sectors) - return ERROR_FAIL; + if (num_sectors > 0) { + 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; @@ -955,7 +926,31 @@ static int msp432_probe(struct flash_bank *bank) } /* We've successfully determined the stats on this flash bank */ - msp432_bank->probed[bank_id] = true; + if (is_main) + msp432_bank->probed_main = true; + if (is_info) + msp432_bank->probed_info = true; + + if (is_main && MSP432P4 == msp432_bank->family_type) { + /* Create the info flash bank needed by MSP432P4 variants */ + struct flash_bank *info = calloc(sizeof(struct flash_bank), 1); + if (NULL == info) + return ERROR_FAIL; + + /* Create a name for the info bank, append "_1" to main name */ + char *name = malloc(strlen(bank->name) + 3); + strcpy(name, bank->name); + strcat(name, "_1"); + + /* Initialize info bank */ + info->name = name; + info->target = bank->target; + info->driver = bank->driver; + info->driver_priv = msp432_bank; + info->base = P4_FLASH_INFO_BASE; + + flash_bank_add(info); + } /* If we fall through to here, then all went well */ @@ -966,15 +961,17 @@ static int msp432_auto_probe(struct flash_bank *bank) { struct msp432_bank *msp432_bank = bank->driver_priv; - int retval = ERROR_OK; + bool is_main = FLASH_BASE == bank->base; + bool is_info = P4_FLASH_INFO_BASE == bank->base; - if (bank->bank_number < 0 || bank->bank_number > 1) { - /* Invalid bank number somehow */ - return ERROR_FAIL; - } + int retval = ERROR_OK; - if (!msp432_bank->probed[bank->bank_number]) - retval = msp432_probe(bank); + if (is_main) + if (!msp432_bank->probed_main) + retval = msp432_probe(bank); + if (is_info) + if (!msp432_bank->probed_info) + retval = msp432_probe(bank); return retval; } @@ -1036,12 +1033,21 @@ static int msp432_info(struct flash_bank *bank, char *buf, int buf_size) return ERROR_OK; } +static int msp432_protect_check(struct flash_bank *bank) +{ + /* Added to suppress warning, not needed for MSP432 flash */ + return ERROR_OK; +} + static void msp432_flash_free_driver_priv(struct flash_bank *bank) { + bool is_main = FLASH_BASE == bank->base; + /* 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)) + /* Only free it on the call for main bank */ + if (is_main && (NULL != bank->driver_priv)) free(bank->driver_priv); + /* Forget about the private struct on both main and info banks */ bank->driver_priv = NULL; } @@ -1052,14 +1058,14 @@ static const struct command_registration msp432_exec_command_handlers[] = { .handler = msp432_mass_erase_command, .mode = COMMAND_EXEC, .help = "Erase entire flash memory on device.", - .usage = "['main' | 'all']", + .usage = "bank_id ['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']", + .usage = "bank_id ['unlock' | 'lock']", }, COMMAND_REGISTRATION_DONE }; @@ -1085,6 +1091,7 @@ const struct flash_driver msp432_flash = { .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 index ffefa8f..663393b 100644 --- a/src/flash/nor/msp432.h +++ b/src/flash/nor/msp432.h @@ -34,14 +34,17 @@ #define MSP432E411Y 7 /* MSP432E401Y device */ #define MSP432E4X_GUESS 8 /* Assuming it's an MSP432E4x device */ +/* Common MSP432 flash parameters */ +#define FLASH_BASE 0x00000000 + /* MSP432P4 flash parameters */ -#define P4_FLASH_MAIN_BASE 0x00000000 +#define P4_FLASH_MAIN_BASE FLASH_BASE #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_BASE FLASH_BASE #define E4_FLASH_SIZE 0x100000 #define E4_SECTOR_LENGTH 0x4000 #define E4_ALGO_ENTRY_ADDR 0x20000110 diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index 4041bfb..9a68b5f 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -28,6 +28,10 @@ #include <helper/types.h> #include <helper/time_support.h> +/* Both those values are constant across the current spectrum ofr nRF5 devices */ +#define WATCHDOG_REFRESH_REGISTER 0x40010600 +#define WATCHDOG_REFRESH_VALUE 0x6e524635 + enum { NRF5_FLASH_BASE = 0x00000000, }; @@ -39,13 +43,15 @@ enum nrf5_ficr_registers { NRF5_FICR_CODEPAGESIZE = NRF5_FICR_REG(0x010), NRF5_FICR_CODESIZE = NRF5_FICR_REG(0x014), - NRF5_FICR_CLENR0 = NRF5_FICR_REG(0x028), - NRF5_FICR_PPFC = NRF5_FICR_REG(0x02C), - NRF5_FICR_NUMRAMBLOCK = NRF5_FICR_REG(0x034), - NRF5_FICR_SIZERAMBLOCK0 = NRF5_FICR_REG(0x038), - NRF5_FICR_SIZERAMBLOCK1 = NRF5_FICR_REG(0x03C), - NRF5_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040), - NRF5_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044), + + NRF51_FICR_CLENR0 = NRF5_FICR_REG(0x028), + NRF51_FICR_PPFC = NRF5_FICR_REG(0x02C), + NRF51_FICR_NUMRAMBLOCK = NRF5_FICR_REG(0x034), + NRF51_FICR_SIZERAMBLOCK0 = NRF5_FICR_REG(0x038), + NRF51_FICR_SIZERAMBLOCK1 = NRF5_FICR_REG(0x03C), + NRF51_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040), + NRF51_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044), + NRF5_FICR_CONFIGID = NRF5_FICR_REG(0x05C), NRF5_FICR_DEVICEID0 = NRF5_FICR_REG(0x060), NRF5_FICR_DEVICEID1 = NRF5_FICR_REG(0x064), @@ -60,36 +66,42 @@ enum nrf5_ficr_registers { NRF5_FICR_DEVICEADDRTYPE = NRF5_FICR_REG(0x0A0), NRF5_FICR_DEVICEADDR0 = NRF5_FICR_REG(0x0A4), NRF5_FICR_DEVICEADDR1 = NRF5_FICR_REG(0x0A8), - NRF5_FICR_OVERRIDEN = NRF5_FICR_REG(0x0AC), - NRF5_FICR_NRF_1MBIT0 = NRF5_FICR_REG(0x0B0), - NRF5_FICR_NRF_1MBIT1 = NRF5_FICR_REG(0x0B4), - NRF5_FICR_NRF_1MBIT2 = NRF5_FICR_REG(0x0B8), - NRF5_FICR_NRF_1MBIT3 = NRF5_FICR_REG(0x0BC), - NRF5_FICR_NRF_1MBIT4 = NRF5_FICR_REG(0x0C0), - NRF5_FICR_BLE_1MBIT0 = NRF5_FICR_REG(0x0EC), - NRF5_FICR_BLE_1MBIT1 = NRF5_FICR_REG(0x0F0), - NRF5_FICR_BLE_1MBIT2 = NRF5_FICR_REG(0x0F4), - NRF5_FICR_BLE_1MBIT3 = NRF5_FICR_REG(0x0F8), - NRF5_FICR_BLE_1MBIT4 = NRF5_FICR_REG(0x0FC), + + NRF51_FICR_OVERRIDEN = NRF5_FICR_REG(0x0AC), + NRF51_FICR_NRF_1MBIT0 = NRF5_FICR_REG(0x0B0), + NRF51_FICR_NRF_1MBIT1 = NRF5_FICR_REG(0x0B4), + NRF51_FICR_NRF_1MBIT2 = NRF5_FICR_REG(0x0B8), + NRF51_FICR_NRF_1MBIT3 = NRF5_FICR_REG(0x0BC), + NRF51_FICR_NRF_1MBIT4 = NRF5_FICR_REG(0x0C0), + NRF51_FICR_BLE_1MBIT0 = NRF5_FICR_REG(0x0EC), + NRF51_FICR_BLE_1MBIT1 = NRF5_FICR_REG(0x0F0), + NRF51_FICR_BLE_1MBIT2 = NRF5_FICR_REG(0x0F4), + NRF51_FICR_BLE_1MBIT3 = NRF5_FICR_REG(0x0F8), + NRF51_FICR_BLE_1MBIT4 = NRF5_FICR_REG(0x0FC), + + /* Following registers are available on nRF52 and on nRF51 since rev 3 */ + NRF5_FICR_INFO_PART = NRF5_FICR_REG(0x100), + NRF5_FICR_INFO_VARIANT = NRF5_FICR_REG(0x104), + NRF5_FICR_INFO_PACKAGE = NRF5_FICR_REG(0x108), + NRF5_FICR_INFO_RAM = NRF5_FICR_REG(0x10C), + NRF5_FICR_INFO_FLASH = NRF5_FICR_REG(0x110), }; enum nrf5_uicr_registers { NRF5_UICR_BASE = 0x10001000, /* User Information * Configuration Regsters */ - NRF5_UICR_SIZE = 0x100, - #define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + offset) - NRF5_UICR_CLENR0 = NRF5_UICR_REG(0x000), - NRF5_UICR_RBPCONF = NRF5_UICR_REG(0x004), - NRF5_UICR_XTALFREQ = NRF5_UICR_REG(0x008), - NRF5_UICR_FWID = NRF5_UICR_REG(0x010), + NRF51_UICR_CLENR0 = NRF5_UICR_REG(0x000), + NRF51_UICR_RBPCONF = NRF5_UICR_REG(0x004), + NRF51_UICR_XTALFREQ = NRF5_UICR_REG(0x008), + NRF51_UICR_FWID = NRF5_UICR_REG(0x010), }; enum nrf5_nvmc_registers { NRF5_NVMC_BASE = 0x4001E000, /* Non-Volatile Memory - * Controller Regsters */ + * Controller Registers */ #define NRF5_NVMC_REG(offset) (NRF5_NVMC_BASE + offset) @@ -98,6 +110,8 @@ enum nrf5_nvmc_registers { NRF5_NVMC_ERASEPAGE = NRF5_NVMC_REG(0x508), NRF5_NVMC_ERASEALL = NRF5_NVMC_REG(0x50C), NRF5_NVMC_ERASEUICR = NRF5_NVMC_REG(0x514), + + NRF5_BPROT_BASE = 0x40000000, }; enum nrf5_nvmc_config_bits { @@ -107,17 +121,19 @@ enum nrf5_nvmc_config_bits { }; -struct nrf5_info { - uint32_t code_page_size; - uint32_t refcount; +struct nrf52_ficr_info { + uint32_t part; + uint32_t variant; + uint32_t package; + uint32_t ram; + uint32_t flash; +}; - struct { - bool probed; - int (*write) (struct flash_bank *bank, - struct nrf5_info *chip, - const uint8_t *buffer, uint32_t offset, uint32_t count); - } bank[2]; - struct target *target; +enum nrf5_features { + NRF5_FEATURE_SERIES_51 = 1 << 0, + NRF5_FEATURE_SERIES_52 = 1 << 1, + NRF5_FEATURE_BPROT = 1 << 2, + NRF5_FEATURE_ACL_PROT = 1 << 3, }; struct nrf5_device_spec { @@ -126,22 +142,58 @@ struct nrf5_device_spec { const char *variant; const char *build_code; unsigned int flash_size_kb; + enum nrf5_features features; }; -#define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize) \ +struct nrf5_info { + uint32_t refcount; + + struct nrf5_bank { + struct nrf5_info *chip; + bool probed; + } bank[2]; + struct target *target; + + /* chip identification stored in nrf5_probe() for use in nrf5_info() */ + bool ficr_info_valid; + struct nrf52_ficr_info ficr_info; + const struct nrf5_device_spec *spec; + uint32_t hwid; + enum nrf5_features features; + unsigned int flash_size_kb; + unsigned int ram_size_kb; +}; + +#define NRF51_DEVICE_DEF(id, pt, var, bcode, fsize) \ { \ .hwid = (id), \ .part = pt, \ .variant = var, \ .build_code = bcode, \ .flash_size_kb = (fsize), \ +.features = NRF5_FEATURE_SERIES_51, \ } -/* The known devices table below is derived from the "nRF51 Series - * Compatibility Matrix" document, which can be found by searching for - * ATTN-51 on the Nordic Semi website: +#define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize, features) \ +{ \ +.hwid = (id), \ +.part = pt, \ +.variant = var, \ +.build_code = bcode, \ +.flash_size_kb = (fsize), \ +.features = features, \ +} + +/* The known devices table below is derived from the "nRF5x series + * compatibility matrix" documents, which can be found in the "DocLib" of + * nordic: * - * http://www.nordicsemi.com/eng/content/search?SearchText=ATTN-51 + * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51422_ic_revision_overview + * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51822_ic_revision_overview + * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF51/latest/COMP/nrf51/nRF51824_ic_revision_overview + * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52810/latest/COMP/nrf52810/nRF52810_ic_revision_overview + * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52832/latest/COMP/nrf52832/ic_revision_overview + * https://www.nordicsemi.com/DocLib/Content/Comp_Matrix/nRF52840/latest/COMP/nrf52840/nRF52840_ic_revision_overview * * Up to date with Matrix v2.0, plus some additional HWIDs. * @@ -151,79 +203,99 @@ struct nrf5_device_spec { */ static const struct nrf5_device_spec nrf5_known_devices_table[] = { /* nRF51822 Devices (IC rev 1). */ - NRF5_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256), - NRF5_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128), - NRF5_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128), - NRF5_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256), - NRF5_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256), + NRF51_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256), + NRF51_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128), + NRF51_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128), + NRF51_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256), + NRF51_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256), /* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards with built-in jlink seem to use engineering samples not listed in the nRF51 Series Compatibility Matrix V1.0. */ - NRF5_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256), + NRF51_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256), /* nRF51822 Devices (IC rev 2). */ - NRF5_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256), - NRF5_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256), - NRF5_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256), - NRF5_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256), - NRF5_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256), - NRF5_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128), - NRF5_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256), - NRF5_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256), - NRF5_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256), + NRF51_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256), + NRF51_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256), + NRF51_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256), + NRF51_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256), + NRF51_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256), + NRF51_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128), + NRF51_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256), + NRF51_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256), + NRF51_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256), /* nRF51822 Devices (IC rev 3). */ - NRF5_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256), - NRF5_DEVICE_DEF(0x00D1, "51822", "QFAA", "H2", 256), - NRF5_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128), - NRF5_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256), - NRF5_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256), - NRF5_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128), - NRF5_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256), - NRF5_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256), - NRF5_DEVICE_DEF(0x008F, "51822", "QFAA", "H1", 256), + NRF51_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256), + NRF51_DEVICE_DEF(0x00D1, "51822", "QFAA", "H2", 256), + NRF51_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128), + NRF51_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256), + NRF51_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256), + NRF51_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128), + NRF51_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256), + NRF51_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256), + NRF51_DEVICE_DEF(0x008F, "51822", "QFAA", "H1", 256), /* nRF51422 Devices (IC rev 1). */ - NRF5_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256), - NRF5_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256), - NRF5_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256), + NRF51_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256), + NRF51_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256), + NRF51_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256), /* nRF51422 Devices (IC rev 2). */ - NRF5_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256), - NRF5_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256), - NRF5_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128), - NRF5_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256), + NRF51_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256), + NRF51_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256), + NRF51_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128), + NRF51_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256), /* nRF51422 Devices (IC rev 3). */ - NRF5_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256), - NRF5_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128), - NRF5_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256), - NRF5_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256), - NRF5_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128), - NRF5_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256), - NRF5_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256), - + NRF51_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256), + NRF51_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128), + NRF51_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256), + NRF51_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256), + NRF51_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128), + NRF51_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256), + NRF51_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256), + + /* The driver fully autodects nRF52 series devices by FICR INFO, + * no need for nRF52xxx HWIDs in this table */ +#if 0 /* nRF52810 Devices */ - NRF5_DEVICE_DEF(0x0142, "52810", "QFAA", "B0", 192), - NRF5_DEVICE_DEF(0x0143, "52810", "QCAA", "C0", 192), + NRF5_DEVICE_DEF(0x0142, "52810", "QFAA", "B0", 192, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), + NRF5_DEVICE_DEF(0x0143, "52810", "QCAA", "C0", 192, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), /* nRF52832 Devices */ - NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512), - NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512), - NRF5_DEVICE_DEF(0x00E3, "52832", "CIAA", "B0", 512), + NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), + NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), + NRF5_DEVICE_DEF(0x00E3, "52832", "CIAA", "B0", 512, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_BPROT), /* nRF52840 Devices */ - NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024), + NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024, NRF5_FEATURE_SERIES_52 | NRF5_FEATURE_ACL_PROT), +#endif +}; + +struct nrf5_device_package { + uint32_t package; + const char *code; }; +/* Newer devices have FICR INFO.PACKAGE. + * This table converts its value to two character code */ +static const struct nrf5_device_package nrf5_packages_table[] = { + { 0x2000, "QF" }, + { 0x2001, "CH" }, + { 0x2002, "CI" }, + { 0x2005, "CK" }, +}; + +const struct flash_driver nrf5_flash, nrf51_flash; + static int nrf5_bank_is_probed(struct flash_bank *bank) { - struct nrf5_info *chip = bank->driver_priv; + struct nrf5_bank *nbank = bank->driver_priv; - assert(chip != NULL); + assert(nbank != NULL); - return chip->bank[bank->bank_number].probed; + return nbank->probed; } static int nrf5_probe(struct flash_bank *bank); @@ -234,7 +306,8 @@ static int nrf5_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf5_i return ERROR_TARGET_NOT_HALTED; } - *chip = bank->driver_priv; + struct nrf5_bank *nbank = bank->driver_priv; + *chip = nbank->chip; int probed = nrf5_bank_is_probed(bank); if (probed < 0) @@ -367,6 +440,33 @@ error: return ERROR_FAIL; } +static int nrf5_protect_check_bprot(struct flash_bank *bank) +{ + struct nrf5_bank *nbank = bank->driver_priv; + struct nrf5_info *chip = nbank->chip; + + assert(chip != NULL); + + static uint32_t nrf5_bprot_offsets[4] = { 0x600, 0x604, 0x610, 0x614 }; + uint32_t bprot_reg = 0; + int res; + + for (int i = 0; i < bank->num_sectors; i++) { + unsigned int bit = i % 32; + if (bit == 0) { + unsigned int n_reg = i / 32; + if (n_reg >= ARRAY_SIZE(nrf5_bprot_offsets)) + break; + + res = target_read_u32(chip->target, NRF5_BPROT_BASE + nrf5_bprot_offsets[n_reg], &bprot_reg); + if (res != ERROR_OK) + return res; + } + bank->sectors[i].is_protected = (bprot_reg & (1 << bit)) ? 1 : 0; + } + return ERROR_OK; +} + static int nrf5_protect_check(struct flash_bank *bank) { int res; @@ -376,11 +476,20 @@ static int nrf5_protect_check(struct flash_bank *bank) if (bank->base == NRF5_UICR_BASE) return ERROR_OK; - struct nrf5_info *chip = bank->driver_priv; + struct nrf5_bank *nbank = bank->driver_priv; + struct nrf5_info *chip = nbank->chip; assert(chip != NULL); - res = target_read_u32(chip->target, NRF5_FICR_CLENR0, + if (chip->features & NRF5_FEATURE_BPROT) + return nrf5_protect_check_bprot(bank); + + if (!(chip->features & NRF5_FEATURE_SERIES_51)) { + LOG_WARNING("Flash protection of this nRF device is not supported"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + + res = target_read_u32(chip->target, NRF51_FICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[FICR]"); @@ -388,7 +497,7 @@ static int nrf5_protect_check(struct flash_bank *bank) } if (clenr0 == 0xFFFFFFFF) { - res = target_read_u32(chip->target, NRF5_UICR_CLENR0, + res = target_read_u32(chip->target, NRF51_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[UICR]"); @@ -417,12 +526,17 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last) if (res != ERROR_OK) return res; + if (!(chip->features & NRF5_FEATURE_SERIES_51)) { + LOG_ERROR("Flash protection setting of this nRF device is not supported"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + if (first != 0) { LOG_ERROR("Code region 0 must start at the begining of the bank"); return ERROR_FAIL; } - res = target_read_u32(chip->target, NRF5_FICR_PPFC, + res = target_read_u32(chip->target, NRF51_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); @@ -434,7 +548,7 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last) return ERROR_FAIL; } - res = target_read_u32(chip->target, NRF5_UICR_CLENR0, + res = target_read_u32(chip->target, NRF51_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[UICR]"); @@ -442,7 +556,7 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last) } if (clenr0 == 0xFFFFFFFF) { - res = target_write_u32(chip->target, NRF5_UICR_CLENR0, + res = target_write_u32(chip->target, NRF51_UICR_CLENR0, clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't write code region 0 size[UICR]"); @@ -458,93 +572,265 @@ static int nrf5_protect(struct flash_bank *bank, int set, int first, int last) return ERROR_OK; } +static bool nrf5_info_variant_to_str(uint32_t variant, char *bf) +{ + uint8_t b[4]; + + h_u32_to_be(b, variant); + if (isalnum(b[0]) && isalnum(b[1]) && isalnum(b[2]) && isalnum(b[3])) { + memcpy(bf, b, 4); + bf[4] = 0; + return true; + } + + strcpy(bf, "xxxx"); + return false; +} + +static const char *nrf5_decode_info_package(uint32_t package) +{ + for (size_t i = 0; i < ARRAY_SIZE(nrf5_packages_table); i++) { + if (nrf5_packages_table[i].package == package) + return nrf5_packages_table[i].code; + } + return "xx"; +} + +static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct nrf5_bank *nbank = bank->driver_priv; + struct nrf5_info *chip = nbank->chip; + int res; + + if (chip->spec) { + res = snprintf(buf, buf_size, + "nRF%s-%s(build code: %s)", + chip->spec->part, chip->spec->variant, chip->spec->build_code); + + } else if (chip->ficr_info_valid) { + char variant[5]; + nrf5_info_variant_to_str(chip->ficr_info.variant, variant); + res = snprintf(buf, buf_size, + "nRF%" PRIx32 "-%s%.2s(build code: %s)", + chip->ficr_info.part, + nrf5_decode_info_package(chip->ficr_info.package), + variant, &variant[2]); + + } else { + res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%08" PRIx32 ")", + chip->hwid); + } + if (res <= 0) + return ERROR_FAIL; + + snprintf(buf + res, buf_size - res, " %ukB Flash, %ukB RAM", + chip->flash_size_kb, chip->ram_size_kb); + return ERROR_OK; +} + +static int nrf5_read_ficr_info(struct nrf5_info *chip) +{ + int res; + struct target *target = chip->target; + + chip->ficr_info_valid = false; + + res = target_read_u32(target, NRF5_FICR_INFO_PART, &chip->ficr_info.part); + if (res != ERROR_OK) { + LOG_DEBUG("Couldn't read FICR INFO.PART register"); + return res; + } + + uint32_t series = chip->ficr_info.part & 0xfffff000; + switch (series) { + case 0x51000: + chip->features = NRF5_FEATURE_SERIES_51; + break; + + case 0x52000: + chip->features = NRF5_FEATURE_SERIES_52; + + switch (chip->ficr_info.part) { + case 0x52810: + case 0x52832: + chip->features |= NRF5_FEATURE_BPROT; + break; + + case 0x52840: + chip->features |= NRF5_FEATURE_ACL_PROT; + break; + } + break; + + default: + LOG_DEBUG("FICR INFO likely not implemented. Invalid PART value 0x%08" + PRIx32, chip->ficr_info.part); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* Now we know the device has FICR INFO filled by something relevant: + * Although it is not documented, the tested nRF51 rev 3 devices + * have FICR INFO.PART, RAM and FLASH of the same format as nRF52. + * VARIANT and PACKAGE coding is unknown for a nRF51 device. + * nRF52 devices have FICR INFO documented and always filled. */ + + res = target_read_u32(target, NRF5_FICR_INFO_VARIANT, &chip->ficr_info.variant); + if (res != ERROR_OK) + return res; + + res = target_read_u32(target, NRF5_FICR_INFO_PACKAGE, &chip->ficr_info.package); + if (res != ERROR_OK) + return res; + + res = target_read_u32(target, NRF5_FICR_INFO_RAM, &chip->ficr_info.ram); + if (res != ERROR_OK) + return res; + + res = target_read_u32(target, NRF5_FICR_INFO_FLASH, &chip->ficr_info.flash); + if (res != ERROR_OK) + return res; + + chip->ficr_info_valid = true; + return ERROR_OK; +} + +static int nrf5_get_ram_size(struct target *target, uint32_t *ram_size) +{ + int res; + + *ram_size = 0; + + uint32_t numramblock; + res = target_read_u32(target, NRF51_FICR_NUMRAMBLOCK, &numramblock); + if (res != ERROR_OK) { + LOG_DEBUG("Couldn't read FICR NUMRAMBLOCK register"); + return res; + } + + if (numramblock < 1 || numramblock > 4) { + LOG_DEBUG("FICR NUMRAMBLOCK strange value %" PRIx32, numramblock); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + for (unsigned int i = 0; i < numramblock; i++) { + uint32_t sizeramblock; + res = target_read_u32(target, NRF51_FICR_SIZERAMBLOCK0 + sizeof(uint32_t)*i, &sizeramblock); + if (res != ERROR_OK) { + LOG_DEBUG("Couldn't read FICR NUMRAMBLOCK register"); + return res; + } + if (sizeramblock < 1024 || sizeramblock > 65536) + LOG_DEBUG("FICR SIZERAMBLOCK strange value %" PRIx32, sizeramblock); + else + *ram_size += sizeramblock; + } + return res; +} + static int nrf5_probe(struct flash_bank *bank) { - uint32_t hwid; int res; - struct nrf5_info *chip = bank->driver_priv; + struct nrf5_bank *nbank = bank->driver_priv; + struct nrf5_info *chip = nbank->chip; + struct target *target = chip->target; - res = target_read_u32(chip->target, NRF5_FICR_CONFIGID, &hwid); + res = target_read_u32(target, NRF5_FICR_CONFIGID, &chip->hwid); if (res != ERROR_OK) { LOG_ERROR("Couldn't read CONFIGID register"); return res; } - hwid &= 0xFFFF; /* HWID is stored in the lower two + chip->hwid &= 0xFFFF; /* HWID is stored in the lower two * bytes of the CONFIGID register */ - const struct nrf5_device_spec *spec = NULL; + /* guess a nRF51 series if the device has no FICR INFO and we don't know HWID */ + chip->features = NRF5_FEATURE_SERIES_51; + + /* Don't bail out on error for the case that some old engineering + * sample has FICR INFO registers unreadable. We can proceed anyway. */ + (void)nrf5_read_ficr_info(chip); + + chip->spec = NULL; for (size_t i = 0; i < ARRAY_SIZE(nrf5_known_devices_table); i++) { - if (hwid == nrf5_known_devices_table[i].hwid) { - spec = &nrf5_known_devices_table[i]; + if (chip->hwid == nrf5_known_devices_table[i].hwid) { + chip->spec = &nrf5_known_devices_table[i]; + chip->features = chip->spec->features; break; } } + if (chip->spec && chip->ficr_info_valid) { + /* check if HWID table gives the same part as FICR INFO */ + if (chip->ficr_info.part != strtoul(chip->spec->part, NULL, 16)) + LOG_WARNING("HWID 0x%04" PRIx32 " mismatch: FICR INFO.PART %" + PRIx32, chip->hwid, chip->ficr_info.part); + } + + if (chip->ficr_info_valid) { + chip->ram_size_kb = chip->ficr_info.ram; + } else { + uint32_t ram_size; + nrf5_get_ram_size(target, &ram_size); + chip->ram_size_kb = ram_size / 1024; + } + + /* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */ + uint32_t flash_page_size; + res = target_read_u32(chip->target, NRF5_FICR_CODEPAGESIZE, + &flash_page_size); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read code page size"); + return res; + } + + /* Note the register name is misleading, + * NRF5_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */ + uint32_t num_sectors; + res = target_read_u32(chip->target, NRF5_FICR_CODESIZE, &num_sectors); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read code memory size"); + return res; + } + + chip->flash_size_kb = num_sectors * flash_page_size / 1024; + if (!chip->bank[0].probed && !chip->bank[1].probed) { - if (spec) - LOG_INFO("nRF%s-%s(build code: %s) %ukB Flash", - spec->part, spec->variant, spec->build_code, - spec->flash_size_kb); + char buf[80]; + nrf5_info(bank, buf, sizeof(buf)); + if (!chip->spec && !chip->ficr_info_valid) + LOG_INFO("Unknown device: %s", buf); else - LOG_WARNING("Unknown device (HWID 0x%08" PRIx32 ")", hwid); + LOG_INFO("%s", buf); } - if (bank->base == NRF5_FLASH_BASE) { - /* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */ - res = target_read_u32(chip->target, NRF5_FICR_CODEPAGESIZE, - &chip->code_page_size); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't read code page size"); - return res; - } + free(bank->sectors); - /* Note the register name is misleading, - * NRF5_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */ - uint32_t num_sectors; - res = target_read_u32(chip->target, NRF5_FICR_CODESIZE, &num_sectors); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't read code memory size"); - return res; - } + if (bank->base == NRF5_FLASH_BASE) { + /* Sanity check */ + if (chip->spec && chip->flash_size_kb != chip->spec->flash_size_kb) + LOG_WARNING("Chip's reported Flash capacity does not match expected one"); + if (chip->ficr_info_valid && chip->flash_size_kb != chip->ficr_info.flash) + LOG_WARNING("Chip's reported Flash capacity does not match FICR INFO.FLASH"); bank->num_sectors = num_sectors; - bank->size = num_sectors * chip->code_page_size; - - if (spec && bank->size / 1024 != spec->flash_size_kb) - LOG_WARNING("Chip's reported Flash capacity does not match expected one"); + bank->size = num_sectors * flash_page_size; - bank->sectors = calloc(bank->num_sectors, - sizeof((bank->sectors)[0])); + bank->sectors = alloc_block_array(0, flash_page_size, num_sectors); if (!bank->sectors) - return ERROR_FLASH_BANK_NOT_PROBED; - - /* Fill out the sector information: all NRF5 sectors are the same size and - * there is always a fixed number of them. */ - for (int i = 0; i < bank->num_sectors; i++) { - bank->sectors[i].size = chip->code_page_size; - bank->sectors[i].offset = i * chip->code_page_size; - - /* mark as unknown */ - bank->sectors[i].is_erased = -1; - bank->sectors[i].is_protected = -1; - } + return ERROR_FAIL; nrf5_protect_check(bank); chip->bank[0].probed = true; + } else { - bank->size = NRF5_UICR_SIZE; bank->num_sectors = 1; - bank->sectors = calloc(bank->num_sectors, - sizeof((bank->sectors)[0])); - if (!bank->sectors) - return ERROR_FLASH_BANK_NOT_PROBED; + bank->size = flash_page_size; - bank->sectors[0].size = bank->size; - bank->sectors[0].offset = 0; + bank->sectors = alloc_block_array(0, flash_page_size, num_sectors); + if (!bank->sectors) + return ERROR_FAIL; - bank->sectors[0].is_erased = 0; bank->sectors[0].is_protected = 0; chip->bank[1].probed = true; @@ -580,29 +866,27 @@ static int nrf5_erase_page(struct flash_bank *bank, int res; LOG_DEBUG("Erasing page at 0x%"PRIx32, sector->offset); - if (sector->is_protected) { - LOG_ERROR("Cannot erase protected sector at 0x%" PRIx32, sector->offset); - return ERROR_FAIL; - } if (bank->base == NRF5_UICR_BASE) { - uint32_t ppfc; - res = target_read_u32(chip->target, NRF5_FICR_PPFC, + if (chip->features & NRF5_FEATURE_SERIES_51) { + uint32_t ppfc; + res = target_read_u32(chip->target, NRF51_FICR_PPFC, &ppfc); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't read PPFC register"); - return res; - } - - if ((ppfc & 0xFF) == 0xFF) { - /* We can't erase the UICR. Double-check to - see if it's already erased before complaining. */ - default_flash_blank_check(bank); - if (sector->is_erased == 1) - return ERROR_OK; - - LOG_ERROR("The chip was not pre-programmed with SoftDevice stack and UICR cannot be erased separately. Please issue mass erase before trying to write to this region"); - return ERROR_FAIL; + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read PPFC register"); + return res; + } + + if ((ppfc & 0xFF) == 0xFF) { + /* We can't erase the UICR. Double-check to + see if it's already erased before complaining. */ + default_flash_blank_check(bank); + if (sector->is_erased == 1) + return ERROR_OK; + + LOG_ERROR("The chip was not pre-programmed with SoftDevice stack and UICR cannot be erased separately. Please issue mass erase before trying to write to this region"); + return ERROR_FAIL; + } } res = nrf5_nvmc_generic_erase(chip, @@ -619,44 +903,22 @@ static int nrf5_erase_page(struct flash_bank *bank, return res; } -static const uint8_t nrf5_flash_write_code[] = { - /* See contrib/loaders/flash/cortex-m0.S */ -/* <wait_fifo>: */ - 0x0d, 0x68, /* ldr r5, [r1, #0] */ - 0x00, 0x2d, /* cmp r5, #0 */ - 0x0b, 0xd0, /* beq.n 1e <exit> */ - 0x4c, 0x68, /* ldr r4, [r1, #4] */ - 0xac, 0x42, /* cmp r4, r5 */ - 0xf9, 0xd0, /* beq.n 0 <wait_fifo> */ - 0x20, 0xcc, /* ldmia r4!, {r5} */ - 0x20, 0xc3, /* stmia r3!, {r5} */ - 0x94, 0x42, /* cmp r4, r2 */ - 0x01, 0xd3, /* bcc.n 18 <no_wrap> */ - 0x0c, 0x46, /* mov r4, r1 */ - 0x08, 0x34, /* adds r4, #8 */ -/* <no_wrap>: */ - 0x4c, 0x60, /* str r4, [r1, #4] */ - 0x04, 0x38, /* subs r0, #4 */ - 0xf0, 0xd1, /* bne.n 0 <wait_fifo> */ -/* <exit>: */ - 0x00, 0xbe /* bkpt 0x0000 */ -}; - - /* Start a low level flash write for the specified region */ -static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes) +static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const uint8_t *buffer, uint32_t bytes) { struct target *target = chip->target; uint32_t buffer_size = 8192; struct working_area *write_algorithm; struct working_area *source; - uint32_t address = NRF5_FLASH_BASE + offset; - struct reg_param reg_params[4]; + struct reg_param reg_params[6]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; + static const uint8_t nrf5_flash_write_code[] = { +#include "../../../contrib/loaders/flash/nrf5/nrf5.inc" + }; - LOG_DEBUG("Writing buffer to flash offset=0x%"PRIx32" bytes=0x%"PRIx32, offset, bytes); + LOG_DEBUG("Writing buffer to flash address=0x%"PRIx32" bytes=0x%"PRIx32, address, bytes); assert(bytes % 4 == 0); /* allocate working area with flash programming code */ @@ -665,7 +927,7 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const ui LOG_WARNING("no working area available, falling back to slow memory writes"); for (; bytes > 0; bytes -= 4) { - retval = target_write_memory(chip->target, offset, 4, 1, buffer); + retval = target_write_memory(target, address, 4, 1, buffer); if (retval != ERROR_OK) return retval; @@ -673,17 +935,13 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const ui if (retval != ERROR_OK) return retval; - offset += 4; + address += 4; buffer += 4; } return ERROR_OK; } - LOG_WARNING("using fast async flash loader. This is currently supported"); - LOG_WARNING("only with ST-Link and CMSIS-DAP. If you have issues, add"); - LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf51.cfg/nrf52.cfg to disable it"); - retval = target_write_buffer(target, write_algorithm->address, sizeof(nrf5_flash_write_code), nrf5_flash_write_code); @@ -710,15 +968,19 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const ui init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer start */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[3], "r3", 32, PARAM_IN_OUT); /* target address */ + init_reg_param(®_params[4], "r6", 32, PARAM_OUT); /* watchdog refresh value */ + init_reg_param(®_params[5], "r7", 32, PARAM_OUT); /* watchdog refresh register address */ buf_set_u32(reg_params[0].value, 0, 32, bytes); buf_set_u32(reg_params[1].value, 0, 32, source->address); buf_set_u32(reg_params[2].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[3].value, 0, 32, address); + buf_set_u32(reg_params[4].value, 0, 32, WATCHDOG_REFRESH_VALUE); + buf_set_u32(reg_params[5].value, 0, 32, WATCHDOG_REFRESH_REGISTER); retval = target_run_flash_async_algorithm(target, buffer, bytes/4, 4, 0, NULL, - 4, reg_params, + ARRAY_SIZE(reg_params), reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); @@ -730,26 +992,29 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const ui destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + destroy_reg_param(®_params[5]); return retval; } -/* Check and erase flash sectors in specified range then start a low level page write. - start/end must be sector aligned. -*/ -static int nrf5_write_pages(struct flash_bank *bank, uint32_t start, uint32_t end, const uint8_t *buffer) +static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) { - int res = ERROR_FAIL; - struct nrf5_info *chip = bank->driver_priv; + struct nrf5_info *chip; - assert(start % chip->code_page_size == 0); - assert(end % chip->code_page_size == 0); + int res = nrf5_get_probed_chip_if_halted(bank, &chip); + if (res != ERROR_OK) + return res; + + assert(offset % 4 == 0); + assert(count % 4 == 0); res = nrf5_nvmc_write_enable(chip); if (res != ERROR_OK) goto error; - res = nrf5_ll_flash_write(chip, start, buffer, (end - start)); + res = nrf5_ll_flash_write(chip, bank->base + offset, buffer, count); if (res != ERROR_OK) goto error; @@ -777,139 +1042,57 @@ static int nrf5_erase(struct flash_bank *bank, int first, int last) return res; } -static int nrf5_code_flash_write(struct flash_bank *bank, - struct nrf5_info *chip, - const uint8_t *buffer, uint32_t offset, uint32_t count) -{ - - int res; - /* Need to perform reads to fill any gaps we need to preserve in the first page, - before the start of buffer, or in the last page, after the end of buffer */ - uint32_t first_page = offset/chip->code_page_size; - uint32_t last_page = DIV_ROUND_UP(offset+count, chip->code_page_size); - - uint32_t first_page_offset = first_page * chip->code_page_size; - uint32_t last_page_offset = last_page * chip->code_page_size; - - LOG_DEBUG("Padding write from 0x%08"PRIx32"-0x%08"PRIx32" as 0x%08"PRIx32"-0x%08"PRIx32, - offset, offset+count, first_page_offset, last_page_offset); - - uint32_t page_cnt = last_page - first_page; - uint8_t buffer_to_flash[page_cnt*chip->code_page_size]; - - /* Fill in any space between start of first page and start of buffer */ - uint32_t pre = offset - first_page_offset; - if (pre > 0) { - res = target_read_memory(bank->target, - first_page_offset, - 1, - pre, - buffer_to_flash); - if (res != ERROR_OK) - return res; - } - - /* Fill in main contents of buffer */ - memcpy(buffer_to_flash+pre, buffer, count); - - /* Fill in any space between end of buffer and end of last page */ - uint32_t post = last_page_offset - (offset+count); - if (post > 0) { - /* Retrieve the full row contents from Flash */ - res = target_read_memory(bank->target, - offset + count, - 1, - post, - buffer_to_flash+pre+count); - if (res != ERROR_OK) - return res; - } - - return nrf5_write_pages(bank, first_page_offset, last_page_offset, buffer_to_flash); -} - -static int nrf5_uicr_flash_write(struct flash_bank *bank, - struct nrf5_info *chip, - const uint8_t *buffer, uint32_t offset, uint32_t count) +static void nrf5_free_driver_priv(struct flash_bank *bank) { - int res; - uint8_t uicr[NRF5_UICR_SIZE]; - struct flash_sector *sector = &bank->sectors[0]; - - if ((offset + count) > NRF5_UICR_SIZE) - return ERROR_FAIL; - - res = target_read_memory(bank->target, - NRF5_UICR_BASE, - 1, - NRF5_UICR_SIZE, - uicr); - - 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) - return res; - - memcpy(&uicr[offset], buffer, count); + struct nrf5_bank *nbank = bank->driver_priv; + struct nrf5_info *chip = nbank->chip; + if (chip == NULL) + return; - res = nrf5_ll_flash_write(chip, NRF5_UICR_BASE, uicr, NRF5_UICR_SIZE); - if (res != ERROR_OK) { - nrf5_nvmc_read_only(chip); - return res; + chip->refcount--; + if (chip->refcount == 0) { + free(chip); + bank->driver_priv = NULL; } - - return nrf5_nvmc_read_only(chip); } - -static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) +static struct nrf5_info *nrf5_get_chip(struct target *target) { - int res; - struct nrf5_info *chip; + struct flash_bank *bank_iter; - res = nrf5_get_probed_chip_if_halted(bank, &chip); - if (res != ERROR_OK) - return res; + /* iterate over nrf5 banks of same target */ + for (bank_iter = flash_bank_list(); bank_iter; bank_iter = bank_iter->next) { + if (bank_iter->driver != &nrf5_flash && bank_iter->driver != &nrf51_flash) + continue; - return chip->bank[bank->bank_number].write(bank, chip, buffer, offset, count); -} + if (bank_iter->target != target) + continue; -static void nrf5_free_driver_priv(struct flash_bank *bank) -{ - struct nrf5_info *chip = bank->driver_priv; - if (chip == NULL) - return; + struct nrf5_bank *nbank = bank_iter->driver_priv; + if (!nbank) + continue; - chip->refcount--; - if (chip->refcount == 0) { - free(chip); - bank->driver_priv = NULL; + if (nbank->chip) + return nbank->chip; } + return NULL; } FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) { - static struct nrf5_info *chip; + struct nrf5_info *chip; + struct nrf5_bank *nbank = NULL; switch (bank->base) { case NRF5_FLASH_BASE: - bank->bank_number = 0; - break; case NRF5_UICR_BASE: - bank->bank_number = 1; break; default: LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base); return ERROR_FAIL; } + chip = nrf5_get_chip(bank->target); if (!chip) { /* Create a new chip */ chip = calloc(1, sizeof(*chip)); @@ -921,16 +1104,19 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) switch (bank->base) { case NRF5_FLASH_BASE: - chip->bank[bank->bank_number].write = nrf5_code_flash_write; + nbank = &chip->bank[0]; break; case NRF5_UICR_BASE: - chip->bank[bank->bank_number].write = nrf5_uicr_flash_write; + nbank = &chip->bank[1]; break; } + assert(nbank != NULL); chip->refcount++; - chip->bank[bank->bank_number].probed = false; - bank->driver_priv = chip; + nbank->chip = chip; + nbank->probed = false; + bank->driver_priv = nbank; + bank->write_start_alignment = bank->write_end_alignment = 4; return ERROR_OK; } @@ -953,19 +1139,20 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command) if (res != ERROR_OK) return res; - uint32_t ppfc; - - res = target_read_u32(target, NRF5_FICR_PPFC, + if (chip->features & NRF5_FEATURE_SERIES_51) { + uint32_t ppfc; + res = target_read_u32(target, NRF51_FICR_PPFC, &ppfc); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't read PPFC register"); - return res; - } + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read PPFC register"); + return res; + } - if ((ppfc & 0xFF) == 0x00) { - LOG_ERROR("Code region 0 size was pre-programmed at the factory, " - "mass erase command won't work."); - return ERROR_FAIL; + if ((ppfc & 0xFF) == 0x00) { + LOG_ERROR("Code region 0 size was pre-programmed at the factory, " + "mass erase command won't work."); + return ERROR_FAIL; + } } res = nrf5_erase_all(chip); @@ -988,9 +1175,17 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command) return ERROR_OK; } -static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size) +COMMAND_HANDLER(nrf5_handle_info_command) { int res; + struct flash_bank *bank = NULL; + struct target *target = get_current_target(CMD_CTX); + + res = get_flash_bank_by_addr(target, NRF5_FLASH_BASE, true, &bank); + if (res != ERROR_OK) + return res; + + assert(bank != NULL); struct nrf5_info *chip; @@ -1004,13 +1199,13 @@ static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size) } ficr[] = { { .address = NRF5_FICR_CODEPAGESIZE }, { .address = NRF5_FICR_CODESIZE }, - { .address = NRF5_FICR_CLENR0 }, - { .address = NRF5_FICR_PPFC }, - { .address = NRF5_FICR_NUMRAMBLOCK }, - { .address = NRF5_FICR_SIZERAMBLOCK0 }, - { .address = NRF5_FICR_SIZERAMBLOCK1 }, - { .address = NRF5_FICR_SIZERAMBLOCK2 }, - { .address = NRF5_FICR_SIZERAMBLOCK3 }, + { .address = NRF51_FICR_CLENR0 }, + { .address = NRF51_FICR_PPFC }, + { .address = NRF51_FICR_NUMRAMBLOCK }, + { .address = NRF51_FICR_SIZERAMBLOCK0 }, + { .address = NRF51_FICR_SIZERAMBLOCK1 }, + { .address = NRF51_FICR_SIZERAMBLOCK2 }, + { .address = NRF51_FICR_SIZERAMBLOCK3 }, { .address = NRF5_FICR_CONFIGID }, { .address = NRF5_FICR_DEVICEID0 }, { .address = NRF5_FICR_DEVICEID1 }, @@ -1025,22 +1220,22 @@ static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size) { .address = NRF5_FICR_DEVICEADDRTYPE }, { .address = NRF5_FICR_DEVICEADDR0 }, { .address = NRF5_FICR_DEVICEADDR1 }, - { .address = NRF5_FICR_OVERRIDEN }, - { .address = NRF5_FICR_NRF_1MBIT0 }, - { .address = NRF5_FICR_NRF_1MBIT1 }, - { .address = NRF5_FICR_NRF_1MBIT2 }, - { .address = NRF5_FICR_NRF_1MBIT3 }, - { .address = NRF5_FICR_NRF_1MBIT4 }, - { .address = NRF5_FICR_BLE_1MBIT0 }, - { .address = NRF5_FICR_BLE_1MBIT1 }, - { .address = NRF5_FICR_BLE_1MBIT2 }, - { .address = NRF5_FICR_BLE_1MBIT3 }, - { .address = NRF5_FICR_BLE_1MBIT4 }, + { .address = NRF51_FICR_OVERRIDEN }, + { .address = NRF51_FICR_NRF_1MBIT0 }, + { .address = NRF51_FICR_NRF_1MBIT1 }, + { .address = NRF51_FICR_NRF_1MBIT2 }, + { .address = NRF51_FICR_NRF_1MBIT3 }, + { .address = NRF51_FICR_NRF_1MBIT4 }, + { .address = NRF51_FICR_BLE_1MBIT0 }, + { .address = NRF51_FICR_BLE_1MBIT1 }, + { .address = NRF51_FICR_BLE_1MBIT2 }, + { .address = NRF51_FICR_BLE_1MBIT3 }, + { .address = NRF51_FICR_BLE_1MBIT4 }, }, uicr[] = { - { .address = NRF5_UICR_CLENR0, }, - { .address = NRF5_UICR_RBPCONF }, - { .address = NRF5_UICR_XTALFREQ }, - { .address = NRF5_UICR_FWID }, + { .address = NRF51_UICR_CLENR0, }, + { .address = NRF51_UICR_RBPCONF }, + { .address = NRF51_UICR_XTALFREQ }, + { .address = NRF51_UICR_FWID }, }; for (size_t i = 0; i < ARRAY_SIZE(ficr); i++) { @@ -1061,7 +1256,7 @@ static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size) } } - snprintf(buf, buf_size, + command_print(CMD, "\n[factory information control block]\n\n" "code page size: %"PRIu32"B\n" "code memory size: %"PRIu32"kB\n" @@ -1120,6 +1315,13 @@ static const struct command_registration nrf5_exec_command_handlers[] = { .help = "Erase all flash contents of the chip.", .usage = "", }, + { + .name = "info", + .handler = nrf5_handle_info_command, + .mode = COMMAND_EXEC, + .help = "Show FICR and UICR info.", + .usage = "", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/flash/nor/numicro.c b/src/flash/nor/numicro.c index c62af04..a485282 100644 --- a/src/flash/nor/numicro.c +++ b/src/flash/nor/numicro.c @@ -1216,7 +1216,7 @@ static int numicro_init_isp(struct target *target) return ERROR_OK; } -static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t addr, uint32_t wdata, uint32_t* rdata) +static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t addr, uint32_t wdata, uint32_t *rdata) { uint32_t timeout, status; int retval = ERROR_OK; @@ -1548,7 +1548,6 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer, { struct target *target = bank->target; uint32_t timeout, status; - uint8_t *new_buffer = NULL; int retval = ERROR_OK; if (target->state != TARGET_HALTED) { @@ -1566,20 +1565,8 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer, if (retval != ERROR_OK) return retval; - if (count & 0x3) { - uint32_t old_count = count; - count = (old_count | 3) + 1; - new_buffer = malloc(count); - if (new_buffer == NULL) { - LOG_ERROR("odd number of bytes to write and no memory " - "for padding buffer"); - return ERROR_FAIL; - } - LOG_INFO("odd number of bytes to write (%d), extending to %d " - "and padding with 0xff", old_count, count); - memset(new_buffer, 0xff, count); - buffer = memcpy(new_buffer, buffer, old_count); - } + assert(offset % 4 == 0); + assert(count % 4 == 0); uint32_t words_remaining = count / 4; @@ -1597,13 +1584,10 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer, LOG_DEBUG("write longword @ %08X", offset + i); - uint8_t padding[4] = {0xff, 0xff, 0xff, 0xff}; - memcpy(padding, buffer + i, MIN(4, count-i)); - retval = target_write_u32(target, NUMICRO_FLASH_ISPADR, bank->base + offset + i); if (retval != ERROR_OK) return retval; - retval = target_write_memory(target, NUMICRO_FLASH_ISPDAT, 4, 1, padding); + retval = target_write_memory(target, NUMICRO_FLASH_ISPDAT, 4, 1, buffer + i); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG, ISPTRG_ISPGO); @@ -1649,7 +1633,7 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer, return ERROR_OK; } -static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_type** cpu) +static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_type **cpu) { uint32_t part_id; int retval = ERROR_OK; @@ -1663,7 +1647,7 @@ static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_ LOG_INFO("Device ID: 0x%08" PRIx32 "", part_id); /* search part numbers */ - for (size_t i = 0; i < sizeof(NuMicroParts)/sizeof(NuMicroParts[0]); i++) { + for (size_t i = 0; i < ARRAY_SIZE(NuMicroParts); i++) { if (part_id == NuMicroParts[i].partid) { *cpu = &NuMicroParts[i]; LOG_INFO("Device Name: %s", (*cpu)->partname); @@ -1754,6 +1738,7 @@ FLASH_BANK_COMMAND_HANDLER(numicro_flash_bank_command) memset(bank_info, 0, sizeof(struct numicro_flash_bank)); bank->driver_priv = bank_info; + bank->write_start_alignment = bank->write_end_alignment = 4; return ERROR_OK; diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c index 386075e..a8f8d3f 100644 --- a/src/flash/nor/psoc6.c +++ b/src/flash/nor/psoc6.c @@ -108,7 +108,7 @@ static const struct row_region safe_sflash_regions[] = { {0x16007C00, 0x400}, /* SFLASH: TOC2 */ }; -#define SFLASH_NUM_REGIONS (sizeof(safe_sflash_regions) / sizeof(safe_sflash_regions[0])) +#define SFLASH_NUM_REGIONS ARRAY_SIZE(safe_sflash_regions) static struct working_area *g_stack_area; static struct armv7m_algorithm g_armv7m_info; @@ -481,20 +481,15 @@ static const char *protection_to_str(uint8_t protection) switch (protection) { case PROTECTION_VIRGIN: return "VIRGIN"; - break; case PROTECTION_NORMAL: return "NORMAL"; - break; case PROTECTION_SECURE: return "SECURE"; - break; case PROTECTION_DEAD: return "DEAD"; - break; case PROTECTION_UNKNOWN: default: return "UNKNOWN"; - break; } } diff --git a/src/flash/nor/renesas_rpchf.c b/src/flash/nor/renesas_rpchf.c new file mode 100644 index 0000000..3f03f92 --- /dev/null +++ b/src/flash/nor/renesas_rpchf.c @@ -0,0 +1,648 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Renesas RCar Gen3 RPC Hyperflash driver + * Based on U-Boot RPC Hyperflash driver + * + * Copyright (C) 2016 Renesas Electronics Corporation + * Copyright (C) 2016 Cogent Embedded, Inc. + * Copyright (C) 2017-2019 Marek Vasut <marek.vasut@gmail.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include "cfi.h" +#include "non_cfi.h" +#include <helper/binarybuffer.h> +#include <helper/bits.h> +#include <helper/time_support.h> + +#define RPC_CMNCR 0x0000 /* R/W */ +#define RPC_CMNCR_MD BIT(31) +#define RPC_CMNCR_MOIIO0(val) (((val) & 0x3) << 16) +#define RPC_CMNCR_MOIIO1(val) (((val) & 0x3) << 18) +#define RPC_CMNCR_MOIIO2(val) (((val) & 0x3) << 20) +#define RPC_CMNCR_MOIIO3(val) (((val) & 0x3) << 22) +#define RPC_CMNCR_MOIIO_HIZ (RPC_CMNCR_MOIIO0(3) | RPC_CMNCR_MOIIO1(3) | \ + RPC_CMNCR_MOIIO2(3) | RPC_CMNCR_MOIIO3(3)) +#define RPC_CMNCR_IO0FV(val) (((val) & 0x3) << 8) +#define RPC_CMNCR_IO2FV(val) (((val) & 0x3) << 12) +#define RPC_CMNCR_IO3FV(val) (((val) & 0x3) << 14) +#define RPC_CMNCR_IOFV_HIZ (RPC_CMNCR_IO0FV(3) | RPC_CMNCR_IO2FV(3) | \ + RPC_CMNCR_IO3FV(3)) +#define RPC_CMNCR_BSZ(val) (((val) & 0x3) << 0) + +#define RPC_SSLDR 0x0004 /* R/W */ +#define RPC_SSLDR_SPNDL(d) (((d) & 0x7) << 16) +#define RPC_SSLDR_SLNDL(d) (((d) & 0x7) << 8) +#define RPC_SSLDR_SCKDL(d) (((d) & 0x7) << 0) + +#define RPC_DRCR 0x000C /* R/W */ +#define RPC_DRCR_SSLN BIT(24) +#define RPC_DRCR_RBURST(v) (((v) & 0x1F) << 16) +#define RPC_DRCR_RCF BIT(9) +#define RPC_DRCR_RBE BIT(8) +#define RPC_DRCR_SSLE BIT(0) + +#define RPC_DRCMR 0x0010 /* R/W */ +#define RPC_DRCMR_CMD(c) (((c) & 0xFF) << 16) +#define RPC_DRCMR_OCMD(c) (((c) & 0xFF) << 0) + +#define RPC_DREAR 0x0014 /* R/W */ +#define RPC_DREAR_EAV(v) (((v) & 0xFF) << 16) +#define RPC_DREAR_EAC(v) (((v) & 0x7) << 0) + +#define RPC_DROPR 0x0018 /* R/W */ +#define RPC_DROPR_OPD3(o) (((o) & 0xFF) << 24) +#define RPC_DROPR_OPD2(o) (((o) & 0xFF) << 16) +#define RPC_DROPR_OPD1(o) (((o) & 0xFF) << 8) +#define RPC_DROPR_OPD0(o) (((o) & 0xFF) << 0) + +#define RPC_DRENR 0x001C /* R/W */ +#define RPC_DRENR_CDB(o) (uint32_t)((((o) & 0x3) << 30)) +#define RPC_DRENR_OCDB(o) (((o) & 0x3) << 28) +#define RPC_DRENR_ADB(o) (((o) & 0x3) << 24) +#define RPC_DRENR_OPDB(o) (((o) & 0x3) << 20) +#define RPC_DRENR_SPIDB(o) (((o) & 0x3) << 16) +#define RPC_DRENR_DME BIT(15) +#define RPC_DRENR_CDE BIT(14) +#define RPC_DRENR_OCDE BIT(12) +#define RPC_DRENR_ADE(v) (((v) & 0xF) << 8) +#define RPC_DRENR_OPDE(v) (((v) & 0xF) << 4) + +#define RPC_SMCR 0x0020 /* R/W */ +#define RPC_SMCR_SSLKP BIT(8) +#define RPC_SMCR_SPIRE BIT(2) +#define RPC_SMCR_SPIWE BIT(1) +#define RPC_SMCR_SPIE BIT(0) + +#define RPC_SMCMR 0x0024 /* R/W */ +#define RPC_SMCMR_CMD(c) (((c) & 0xFF) << 16) +#define RPC_SMCMR_OCMD(c) (((c) & 0xFF) << 0) + +#define RPC_SMADR 0x0028 /* R/W */ +#define RPC_SMOPR 0x002C /* R/W */ +#define RPC_SMOPR_OPD0(o) (((o) & 0xFF) << 0) +#define RPC_SMOPR_OPD1(o) (((o) & 0xFF) << 8) +#define RPC_SMOPR_OPD2(o) (((o) & 0xFF) << 16) +#define RPC_SMOPR_OPD3(o) (((o) & 0xFF) << 24) + +#define RPC_SMENR 0x0030 /* R/W */ +#define RPC_SMENR_CDB(o) (((o) & 0x3) << 30) +#define RPC_SMENR_OCDB(o) (((o) & 0x3) << 28) +#define RPC_SMENR_ADB(o) (((o) & 0x3) << 24) +#define RPC_SMENR_OPDB(o) (((o) & 0x3) << 20) +#define RPC_SMENR_SPIDB(o) (((o) & 0x3) << 16) +#define RPC_SMENR_DME BIT(15) +#define RPC_SMENR_CDE BIT(14) +#define RPC_SMENR_OCDE BIT(12) +#define RPC_SMENR_ADE(v) (((v) & 0xF) << 8) +#define RPC_SMENR_OPDE(v) (((v) & 0xF) << 4) +#define RPC_SMENR_SPIDE(v) (((v) & 0xF) << 0) + +#define RPC_SMRDR0 0x0038 /* R */ +#define RPC_SMRDR1 0x003C /* R */ +#define RPC_SMWDR0 0x0040 /* R/W */ +#define RPC_SMWDR1 0x0044 /* R/W */ +#define RPC_CMNSR 0x0048 /* R */ +#define RPC_CMNSR_SSLF BIT(1) +#define RPC_CMNSR_TEND BIT(0) + +#define RPC_DRDMCR 0x0058 /* R/W */ +#define RPC_DRDMCR_DMCYC(v) (((v) & 0xF) << 0) + +#define RPC_DRDRENR 0x005C /* R/W */ +#define RPC_DRDRENR_HYPE (0x5 << 12) +#define RPC_DRDRENR_ADDRE BIT(8) +#define RPC_DRDRENR_OPDRE BIT(4) +#define RPC_DRDRENR_DRDRE BIT(0) + +#define RPC_SMDMCR 0x0060 /* R/W */ +#define RPC_SMDMCR_DMCYC(v) (((v) & 0xF) << 0) + +#define RPC_SMDRENR 0x0064 /* R/W */ +#define RPC_SMDRENR_HYPE (0x5 << 12) +#define RPC_SMDRENR_ADDRE BIT(8) +#define RPC_SMDRENR_OPDRE BIT(4) +#define RPC_SMDRENR_SPIDRE BIT(0) + +#define RPC_PHYCNT 0x007C /* R/W */ +#define RPC_PHYCNT_CAL BIT(31) +#define PRC_PHYCNT_OCTA_AA BIT(22) +#define PRC_PHYCNT_OCTA_SA BIT(23) +#define PRC_PHYCNT_EXDS BIT(21) +#define RPC_PHYCNT_OCT BIT(20) +#define RPC_PHYCNT_WBUF2 BIT(4) +#define RPC_PHYCNT_WBUF BIT(2) +#define RPC_PHYCNT_MEM(v) (((v) & 0x3) << 0) + +#define RPC_PHYINT 0x0088 /* R/W */ +#define RPC_PHYINT_RSTEN BIT(18) +#define RPC_PHYINT_WPEN BIT(17) +#define RPC_PHYINT_INTEN BIT(16) +#define RPC_PHYINT_RST BIT(2) +#define RPC_PHYINT_WP BIT(1) +#define RPC_PHYINT_INT BIT(0) + +#define RPC_WBUF 0x8000 /* R/W size=4/8/16/32/64Bytes */ +#define RPC_WBUF_SIZE 0x100 + +static uint32_t rpc_base = 0xee200000; +static uint32_t mem_base = 0x08000000; + +enum rpc_hf_size { + RPC_HF_SIZE_16BIT = RPC_SMENR_SPIDE(0x8), + RPC_HF_SIZE_32BIT = RPC_SMENR_SPIDE(0xC), + RPC_HF_SIZE_64BIT = RPC_SMENR_SPIDE(0xF), +}; + +static int rpc_hf_wait_tend(struct target *target) +{ + uint32_t reg = rpc_base + RPC_CMNSR; + uint32_t val; + unsigned long timeout = 1000; + long long endtime; + int ret; + + endtime = timeval_ms() + timeout; + do { + ret = target_read_u32(target, reg, &val); + if (ret != ERROR_OK) + return ERROR_FAIL; + + if (val & RPC_CMNSR_TEND) + return ERROR_OK; + + alive_sleep(1); + } while (timeval_ms() < endtime); + + LOG_ERROR("timeout"); + return ERROR_TIMEOUT_REACHED; +} + +static int clrsetbits_u32(struct target *target, uint32_t reg, + uint32_t clr, uint32_t set) +{ + uint32_t val; + int ret; + + ret = target_read_u32(target, reg, &val); + if (ret != ERROR_OK) + return ret; + + val &= ~clr; + val |= set; + + return target_write_u32(target, reg, val); +} + +static int rpc_hf_mode(struct target *target, bool manual) +{ + uint32_t val; + int ret; + + ret = rpc_hf_wait_tend(target); + if (ret != ERROR_OK) { + LOG_ERROR("Mode TEND timeout"); + return ret; + } + + ret = clrsetbits_u32(target, rpc_base + RPC_PHYCNT, + RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 | + RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3), + RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)); + if (ret != ERROR_OK) + return ret; + + ret = clrsetbits_u32(target, rpc_base + RPC_CMNCR, + RPC_CMNCR_MD | RPC_CMNCR_BSZ(3), + RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | + (manual ? RPC_CMNCR_MD : 0) | RPC_CMNCR_BSZ(1)); + if (ret != ERROR_OK) + return ret; + + if (manual) + return ERROR_OK; + + ret = target_write_u32(target, rpc_base + RPC_DRCR, + RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RCF | + RPC_DRCR_RBE); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_DRCMR, + RPC_DRCMR_CMD(0xA0)); + if (ret != ERROR_OK) + return ret; + ret = target_write_u32(target, rpc_base + RPC_DRENR, + RPC_DRENR_CDB(2) | RPC_DRENR_OCDB(2) | + RPC_DRENR_ADB(2) | RPC_DRENR_SPIDB(2) | + RPC_DRENR_CDE | RPC_DRENR_OCDE | + RPC_DRENR_ADE(4)); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_DRDMCR, + RPC_DRDMCR_DMCYC(0xE)); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_DRDRENR, + RPC_DRDRENR_HYPE | RPC_DRDRENR_ADDRE | + RPC_DRDRENR_DRDRE); + if (ret != ERROR_OK) + return ret; + + /* Dummy read */ + return target_read_u32(target, rpc_base + RPC_DRCR, &val); +} + +static int rpc_hf_xfer(struct target *target, target_addr_t addr, + uint32_t wdata, uint32_t *rdata, enum rpc_hf_size size, + bool write, const uint8_t *wbuf, unsigned int wbuf_size) +{ + int ret; + uint32_t val; + + if (wbuf_size != 0) { + ret = rpc_hf_wait_tend(target); + if (ret != ERROR_OK) { + LOG_ERROR("Xfer TEND timeout"); + return ret; + } + + /* Write calibration magic */ + ret = target_write_u32(target, rpc_base + RPC_DRCR, 0x01FF0301); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_PHYCNT, 0x80030277); + if (ret != ERROR_OK) + return ret; + + ret = target_write_memory(target, rpc_base | RPC_WBUF, 4, + wbuf_size / 4, wbuf); + if (ret != ERROR_OK) + return ret; + + ret = clrsetbits_u32(target, rpc_base + RPC_CMNCR, + RPC_CMNCR_MD | RPC_CMNCR_BSZ(3), + RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | + RPC_CMNCR_MD | RPC_CMNCR_BSZ(1)); + if (ret != ERROR_OK) + return ret; + } else { + ret = rpc_hf_mode(target, 1); + if (ret != ERROR_OK) + return ret; + } + + /* Submit HF address, SMCMR CMD[7] ~= CA Bit# 47 (R/nW) */ + ret = target_write_u32(target, rpc_base + RPC_SMCMR, + write ? 0 : RPC_SMCMR_CMD(0x80)); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_SMADR, + addr >> 1); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_SMOPR, 0x0); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_SMDRENR, + RPC_SMDRENR_HYPE | RPC_SMDRENR_ADDRE | + RPC_SMDRENR_SPIDRE); + if (ret != ERROR_OK) + return ret; + + val = RPC_SMENR_CDB(2) | RPC_SMENR_OCDB(2) | + RPC_SMENR_ADB(2) | RPC_SMENR_SPIDB(2) | + (wbuf_size ? RPC_SMENR_OPDB(2) : 0) | + RPC_SMENR_CDE | RPC_SMENR_OCDE | RPC_SMENR_ADE(4) | size; + + if (write) { + ret = target_write_u32(target, rpc_base + RPC_SMENR, val); + if (ret != ERROR_OK) + return ret; + + if (wbuf_size == 0) { + buf_bswap32((uint8_t *)&wdata, (uint8_t *)&wdata, 4); + ret = target_write_u32(target, rpc_base + RPC_SMWDR0, + wdata); + if (ret != ERROR_OK) + return ret; + } + + ret = target_write_u32(target, rpc_base + RPC_SMCR, + RPC_SMCR_SPIWE | RPC_SMCR_SPIE); + if (ret != ERROR_OK) + return ret; + } else { + val |= RPC_SMENR_DME; + + ret = target_write_u32(target, rpc_base + RPC_SMDMCR, + RPC_SMDMCR_DMCYC(0xE)); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_SMENR, val); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, rpc_base + RPC_SMCR, + RPC_SMCR_SPIRE | RPC_SMCR_SPIE); + if (ret != ERROR_OK) + return ret; + + ret = rpc_hf_wait_tend(target); + if (ret != ERROR_OK) + return ret; + + uint32_t val32; + ret = target_read_u32(target, rpc_base + RPC_SMRDR0, &val32); + if (ret != ERROR_OK) + return ret; + buf_bswap32((uint8_t *)&val32, (uint8_t *)&val32, 4); + *rdata = val32; + } + + ret = rpc_hf_mode(target, 0); + if (ret != ERROR_OK) + LOG_ERROR("Xfer done TEND timeout"); + return ret; +} + +static int rpchf_target_write_memory(struct flash_bank *bank, target_addr_t addr, + uint32_t count, const uint8_t *buffer) +{ + struct target *target = bank->target; + uint32_t wdata; + + if (count != 2) + return ERROR_FAIL; + + wdata = buffer[0] | (buffer[1] << 8); + + return rpc_hf_xfer(target, addr, wdata, NULL, RPC_HF_SIZE_16BIT, + true, NULL, 0); +} + +static int rpchf_target_read_memory(struct flash_bank *bank, target_addr_t addr, + uint32_t count, uint8_t *buffer) +{ + struct target *target = bank->target; + uint32_t i, rdata; + int ret; + + for (i = 0; i < count; i++) { + ret = rpc_hf_xfer(target, addr + (2 * i), 0, &rdata, + RPC_HF_SIZE_16BIT, false, NULL, 0); + if (ret != ERROR_OK) + return ret; + buffer[(2 * i) + 0] = rdata & 0xff; + buffer[(2 * i) + 1] = (rdata >> 8) & 0xff; + } + + return ERROR_OK; +} + +FLASH_BANK_COMMAND_HANDLER(rpchf_flash_bank_command) +{ + struct cfi_flash_bank *cfi_info; + int ret; + + ret = cfi_flash_bank_cmd(bank, CMD_ARGC, CMD_ARGV); + if (ret != ERROR_OK) + return ret; + + cfi_info = bank->driver_priv; + cfi_info->read_mem = rpchf_target_read_memory; + cfi_info->write_mem = rpchf_target_write_memory; + + return ERROR_OK; +} + +static int rpchf_spansion_write_words(struct flash_bank *bank, const uint8_t *word, + uint32_t wordcount, uint32_t address) +{ + int retval; + struct cfi_flash_bank *cfi_info = bank->driver_priv; + struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; + + /* Calculate buffer size and boundary mask + * buffersize is (buffer size per chip) * (number of chips) + * bufferwsize is buffersize in words */ + uint32_t buffersize = RPC_WBUF_SIZE; + uint32_t buffermask = buffersize - 1; + uint32_t bufferwsize = buffersize / 2; + + /* Check for valid range */ + if (address & buffermask) { + LOG_ERROR("Write address at base " TARGET_ADDR_FMT + ", address 0x%" PRIx32 " not aligned to 2^%d boundary", + bank->base, address, cfi_info->max_buf_write_size); + return ERROR_FLASH_OPERATION_FAILED; + } + + /* Check for valid size */ + if (wordcount > bufferwsize) { + LOG_ERROR("Number of data words %" PRId32 " exceeds available buffersize %" + PRId32, wordcount, buffersize); + return ERROR_FLASH_OPERATION_FAILED; + } + + /* Unlock */ + retval = cfi_spansion_unlock_seq(bank); + if (retval != ERROR_OK) + return retval; + + retval = cfi_send_command(bank, 0xa0, cfi_flash_address(bank, 0, pri_ext->_unlock1)); + if (retval != ERROR_OK) + return retval; + + retval = rpc_hf_xfer(bank->target, address, 0, NULL, RPC_HF_SIZE_64BIT, true, word, wordcount * 2); + if (retval != ERROR_OK) + return retval; + + if (cfi_spansion_wait_status_busy(bank, cfi_info->word_write_timeout) != ERROR_OK) { + retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0)); + if (retval != ERROR_OK) + return retval; + + LOG_ERROR("couldn't write block at base " TARGET_ADDR_FMT + ", address 0x%" PRIx32 ", size 0x%" PRIx32, bank->base, address, + bufferwsize); + return ERROR_FLASH_OPERATION_FAILED; + } + + return ERROR_OK; +} + +static int rpchf_write_words(struct flash_bank *bank, const uint8_t *word, + uint32_t wordcount, uint32_t address) +{ + return rpchf_spansion_write_words(bank, word, wordcount, address); +} + +static int rpchf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) +{ + struct cfi_flash_bank *cfi_info = bank->driver_priv; + uint32_t address = bank->base + offset; /* address of first byte to be programmed */ + uint32_t write_p; + int align; /* number of unaligned bytes */ + uint8_t current_word[CFI_MAX_BUS_WIDTH * 4]; /* word (bus_width size) currently being + *programmed */ + int i; + int retval; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > bank->size) + return ERROR_FLASH_DST_OUT_OF_BANK; + + if (cfi_info->qry[0] != 'Q') + return ERROR_FLASH_BANK_NOT_PROBED; + + /* start at the first byte of the first word (bus_width size) */ + write_p = address & ~(bank->bus_width - 1); + align = address - write_p; + if (align != 0) { + LOG_INFO("Fixup %d unaligned head bytes", align); + + /* read a complete word from flash */ + retval = cfi_target_read_memory(bank, write_p, 1, current_word); + if (retval != ERROR_OK) + return retval; + + /* replace only bytes that must be written */ + for (i = align; + (i < bank->bus_width) && (count > 0); + i++, count--) + if (cfi_info->data_swap) + /* data bytes are swapped (reverse endianness) */ + current_word[bank->bus_width - i] = *buffer++; + else + current_word[i] = *buffer++; + + retval = cfi_write_word(bank, current_word, write_p); + if (retval != ERROR_OK) + return retval; + write_p += bank->bus_width; + } + + /* Calculate buffer size and boundary mask + * buffersize is (buffer size per chip) * (number of chips) + * bufferwsize is buffersize in words */ + uint32_t buffersize = RPC_WBUF_SIZE; + uint32_t buffermask = buffersize-1; + uint32_t bufferwsize = buffersize / bank->bus_width; + + /* fall back to memory writes */ + while (count >= (uint32_t)bank->bus_width) { + int fallback; + if ((write_p & 0xff) == 0) { + LOG_INFO("Programming at 0x%08" PRIx32 ", count 0x%08" + PRIx32 " bytes remaining", write_p, count); + } + fallback = 1; + if ((bufferwsize > 0) && (count >= buffersize) && + !(write_p & buffermask)) { + retval = rpchf_write_words(bank, buffer, bufferwsize, write_p); + if (retval == ERROR_OK) { + buffer += buffersize; + write_p += buffersize; + count -= buffersize; + fallback = 0; + } else if (retval != ERROR_FLASH_OPER_UNSUPPORTED) + return retval; + } + /* try the slow way? */ + if (fallback) { + for (i = 0; i < bank->bus_width; i++) + current_word[i] = *buffer++; + + retval = cfi_write_word(bank, current_word, write_p); + if (retval != ERROR_OK) + return retval; + + write_p += bank->bus_width; + count -= bank->bus_width; + } + } + + /* return to read array mode, so we can read from flash again for padding */ + retval = cfi_reset(bank); + if (retval != ERROR_OK) + return retval; + + /* handle unaligned tail bytes */ + if (count > 0) { + LOG_INFO("Fixup %" PRId32 " unaligned tail bytes", count); + + /* read a complete word from flash */ + retval = cfi_target_read_memory(bank, write_p, 1, current_word); + if (retval != ERROR_OK) + return retval; + + /* replace only bytes that must be written */ + for (i = 0; (i < bank->bus_width) && (count > 0); i++, count--) + if (cfi_info->data_swap) + /* data bytes are swapped (reverse endianness) */ + current_word[bank->bus_width - i] = *buffer++; + else + current_word[i] = *buffer++; + + retval = cfi_write_word(bank, current_word, write_p); + if (retval != ERROR_OK) + return retval; + } + + /* return to read array mode */ + return cfi_reset(bank); +} + +static int rpchf_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) +{ + struct cfi_flash_bank *cfi_info = bank->driver_priv; + struct target *target = bank->target; + + LOG_DEBUG("reading buffer of %" PRIi32 " byte at 0x%8.8" PRIx32, + count, offset); + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > bank->size) + return ERROR_FLASH_DST_OUT_OF_BANK; + + if (cfi_info->qry[0] != 'Q') + return ERROR_FLASH_BANK_NOT_PROBED; + + return target_read_memory(target, offset | mem_base, + 4, count / 4, buffer); +} + +const struct flash_driver renesas_rpchf_flash = { + .name = "rpchf", + .flash_bank_command = rpchf_flash_bank_command, + .erase = cfi_erase, + .protect = cfi_protect, + .write = rpchf_write, + .read = rpchf_read, + .probe = cfi_probe, + .auto_probe = cfi_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = cfi_protect_check, + .info = cfi_get_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/sh_qspi.c b/src/flash/nor/sh_qspi.c new file mode 100644 index 0000000..862e43a --- /dev/null +++ b/src/flash/nor/sh_qspi.c @@ -0,0 +1,912 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * SH QSPI (Quad SPI) driver + * Copyright (C) 2019 Marek Vasut <marek.vasut@gmail.com> + * + * Based on U-Boot SH QSPI driver + * Copyright (C) 2013 Renesas Electronics Corporation + * Copyright (C) 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include "spi.h" +#include <helper/binarybuffer.h> +#include <helper/bits.h> +#include <helper/time_support.h> +#include <helper/types.h> +#include <jtag/jtag.h> +#include <target/algorithm.h> +#include <target/arm.h> +#include <target/arm_opcodes.h> +#include <target/target.h> + +/* SH QSPI register bit masks <REG>_<BIT> */ +#define SPCR_MSTR 0x08 +#define SPCR_SPE 0x40 +#define SPSR_SPRFF 0x80 +#define SPSR_SPTEF 0x20 +#define SPPCR_IO3FV 0x04 +#define SPPCR_IO2FV 0x02 +#define SPPCR_IO1FV 0x01 +#define SPBDCR_RXBC0 BIT(0) +#define SPCMD_SCKDEN BIT(15) +#define SPCMD_SLNDEN BIT(14) +#define SPCMD_SPNDEN BIT(13) +#define SPCMD_SSLKP BIT(7) +#define SPCMD_BRDV0 BIT(2) +#define SPCMD_INIT1 (SPCMD_SCKDEN | SPCMD_SLNDEN | \ + SPCMD_SPNDEN | SPCMD_SSLKP | \ + SPCMD_BRDV0) +#define SPCMD_INIT2 (SPCMD_SPNDEN | SPCMD_SSLKP | \ + SPCMD_BRDV0) +#define SPBFCR_TXRST BIT(7) +#define SPBFCR_RXRST BIT(6) +#define SPBFCR_TXTRG 0x30 +#define SPBFCR_RXTRG 0x07 + +/* SH QSPI register set */ +#define SH_QSPI_SPCR 0x00 +#define SH_QSPI_SSLP 0x01 +#define SH_QSPI_SPPCR 0x02 +#define SH_QSPI_SPSR 0x03 +#define SH_QSPI_SPDR 0x04 +#define SH_QSPI_SPSCR 0x08 +#define SH_QSPI_SPSSR 0x09 +#define SH_QSPI_SPBR 0x0a +#define SH_QSPI_SPDCR 0x0b +#define SH_QSPI_SPCKD 0x0c +#define SH_QSPI_SSLND 0x0d +#define SH_QSPI_SPND 0x0e +#define SH_QSPI_DUMMY0 0x0f +#define SH_QSPI_SPCMD0 0x10 +#define SH_QSPI_SPCMD1 0x12 +#define SH_QSPI_SPCMD2 0x14 +#define SH_QSPI_SPCMD3 0x16 +#define SH_QSPI_SPBFCR 0x18 +#define SH_QSPI_DUMMY1 0x19 +#define SH_QSPI_SPBDCR 0x1a +#define SH_QSPI_SPBMUL0 0x1c +#define SH_QSPI_SPBMUL1 0x20 +#define SH_QSPI_SPBMUL2 0x24 +#define SH_QSPI_SPBMUL3 0x28 + +struct sh_qspi_flash_bank { + const struct flash_device *dev; + uint32_t io_base; + int probed; + struct working_area *io_algorithm; + struct working_area *source; + unsigned int buffer_size; +}; + +struct sh_qspi_target { + char *name; + uint32_t tap_idcode; + uint32_t io_base; +}; + +static const struct sh_qspi_target target_devices[] = { + /* name, tap_idcode, io_base */ + { "SH QSPI", 0x4ba00477, 0xe6b10000 }, + { NULL, 0, 0 } +}; + +static int sh_qspi_init(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + uint8_t val; + int ret; + + /* QSPI initialize */ + /* Set master mode only */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, SPCR_MSTR); + if (ret != ERROR_OK) + return ret; + + /* Set SSL signal level */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SSLP, 0x00); + if (ret != ERROR_OK) + return ret; + + /* Set MOSI signal value when transfer is in idle state */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPPCR, + SPPCR_IO3FV | SPPCR_IO2FV); + if (ret != ERROR_OK) + return ret; + + /* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPBR, 0x01); + if (ret != ERROR_OK) + return ret; + + /* Disable Dummy Data Transmission */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPDCR, 0x00); + if (ret != ERROR_OK) + return ret; + + /* Set clock delay value */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPCKD, 0x00); + if (ret != ERROR_OK) + return ret; + + /* Set SSL negation delay value */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SSLND, 0x00); + if (ret != ERROR_OK) + return ret; + + /* Set next-access delay value */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPND, 0x00); + if (ret != ERROR_OK) + return ret; + + /* Set equence command */ + ret = target_write_u16(target, info->io_base + SH_QSPI_SPCMD0, + SPCMD_INIT2); + if (ret != ERROR_OK) + return ret; + + /* Reset transfer and receive Buffer */ + ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val); + if (ret != ERROR_OK) + return ret; + + val |= SPBFCR_TXRST | SPBFCR_RXRST; + + ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val); + if (ret != ERROR_OK) + return ret; + + /* Clear transfer and receive Buffer control bit */ + ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val); + if (ret != ERROR_OK) + return ret; + + val &= ~(SPBFCR_TXRST | SPBFCR_RXRST); + + ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val); + if (ret != ERROR_OK) + return ret; + + /* Set equence control method. Use equence0 only */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPSCR, 0x00); + if (ret != ERROR_OK) + return ret; + + /* Enable SPI function */ + ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val); + if (ret != ERROR_OK) + return ret; + + val |= SPCR_SPE; + + return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val); +} + +static int sh_qspi_cs_activate(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + uint8_t val; + int ret; + + /* Set master mode only */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, SPCR_MSTR); + if (ret != ERROR_OK) + return ret; + + /* Set command */ + ret = target_write_u16(target, info->io_base + SH_QSPI_SPCMD0, + SPCMD_INIT1); + if (ret != ERROR_OK) + return ret; + + /* Reset transfer and receive Buffer */ + ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val); + if (ret != ERROR_OK) + return ret; + + val |= SPBFCR_TXRST | SPBFCR_RXRST; + + ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val); + if (ret != ERROR_OK) + return ret; + + /* Clear transfer and receive Buffer control bit */ + ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val); + if (ret != ERROR_OK) + return ret; + + val &= ~(SPBFCR_TXRST | SPBFCR_RXRST); + + ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val); + if (ret != ERROR_OK) + return ret; + + /* Set equence control method. Use equence0 only */ + ret = target_write_u8(target, info->io_base + SH_QSPI_SPSCR, 0x00); + if (ret != ERROR_OK) + return ret; + + /* Enable SPI function */ + ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val); + if (ret != ERROR_OK) + return ret; + + val |= SPCR_SPE; + + return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val); +} + +static int sh_qspi_cs_deactivate(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + uint8_t val; + int ret; + + /* Disable SPI Function */ + ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val); + if (ret != ERROR_OK) + return ret; + + val &= ~SPCR_SPE; + + return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val); +} + +static int sh_qspi_wait_for_bit(struct flash_bank *bank, uint8_t reg, + uint32_t mask, bool set, + unsigned long timeout) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + long long endtime; + uint8_t val; + int ret; + + endtime = timeval_ms() + timeout; + do { + ret = target_read_u8(target, info->io_base + reg, &val); + if (ret != ERROR_OK) + return ret; + + if (!set) + val = ~val; + + if ((val & mask) == mask) + return ERROR_OK; + + alive_sleep(1); + } while (timeval_ms() < endtime); + + LOG_ERROR("timeout"); + return ERROR_TIMEOUT_REACHED; +} + +static int sh_qspi_xfer_common(struct flash_bank *bank, + const uint8_t *dout, unsigned int outlen, + uint8_t *din, unsigned int inlen, + bool xfer_start, bool xfer_end) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + uint8_t tdata, rdata; + uint8_t val; + unsigned int nbyte = outlen + inlen; + int ret = 0; + + if (xfer_start) { + ret = sh_qspi_cs_activate(bank); + if (ret != ERROR_OK) + return ret; + + ret = target_write_u32(target, info->io_base + SH_QSPI_SPBMUL0, + nbyte); + if (ret != ERROR_OK) + return ret; + + ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, + &val); + if (ret != ERROR_OK) + return ret; + + val &= ~(SPBFCR_TXTRG | SPBFCR_RXTRG); + + ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, + val); + if (ret != ERROR_OK) + return ret; + } + + while (nbyte > 0) { + ret = sh_qspi_wait_for_bit(bank, SH_QSPI_SPSR, SPSR_SPTEF, + true, 1000); + if (ret != ERROR_OK) + return ret; + + tdata = outlen ? *dout++ : 0; + ret = target_write_u8(target, info->io_base + SH_QSPI_SPDR, + tdata); + if (ret != ERROR_OK) + return ret; + + ret = sh_qspi_wait_for_bit(bank, SH_QSPI_SPSR, SPSR_SPRFF, + true, 1000); + if (ret != ERROR_OK) + return ret; + + ret = target_read_u8(target, info->io_base + SH_QSPI_SPDR, + &rdata); + if (ret != ERROR_OK) + return ret; + if (!outlen && inlen) { + *din++ = rdata; + inlen--; + } + + if (outlen) + outlen--; + + nbyte--; + } + + if (xfer_end) + return sh_qspi_cs_deactivate(bank); + else + return ERROR_OK; +} + +/* Send "write enable" command to SPI flash chip. */ +static int sh_qspi_write_enable(struct flash_bank *bank) +{ + uint8_t dout = SPIFLASH_WRITE_ENABLE; + + return sh_qspi_xfer_common(bank, &dout, 1, NULL, 0, 1, 1); +} + +/* Read the status register of the external SPI flash chip. */ +static int read_status_reg(struct flash_bank *bank, uint32_t *status) +{ + uint8_t dout = SPIFLASH_READ_STATUS; + uint8_t din; + int ret; + + ret = sh_qspi_xfer_common(bank, &dout, 1, &din, 1, 1, 1); + if (ret != ERROR_OK) + return ret; + + *status = din & 0xff; + + return ERROR_OK; +} + +/* check for WIP (write in progress) bit in status register */ +/* timeout in ms */ +static int wait_till_ready(struct flash_bank *bank, int timeout) +{ + long long endtime; + uint32_t status; + int ret; + + endtime = timeval_ms() + timeout; + do { + /* read flash status register */ + ret = read_status_reg(bank, &status); + if (ret != ERROR_OK) + return ret; + + if ((status & SPIFLASH_BSY_BIT) == 0) + return ERROR_OK; + alive_sleep(1); + } while (timeval_ms() < endtime); + + LOG_ERROR("timeout"); + return ERROR_TIMEOUT_REACHED; +} + +static int sh_qspi_erase_sector(struct flash_bank *bank, int sector) +{ + struct sh_qspi_flash_bank *info = bank->driver_priv; + bool addr4b = info->dev->size_in_bytes > (1UL << 24); + uint32_t address = (sector * info->dev->sectorsize) << + (addr4b ? 0 : 8); + uint8_t dout[5] = { + info->dev->erase_cmd, + (address >> 24) & 0xff, (address >> 16) & 0xff, + (address >> 8) & 0xff, (address >> 0) & 0xff + }; + unsigned int doutlen = addr4b ? 5 : 4; + int ret; + + /* Write Enable */ + ret = sh_qspi_write_enable(bank); + if (ret != ERROR_OK) + return ret; + + /* Erase */ + ret = sh_qspi_xfer_common(bank, dout, doutlen, NULL, 0, 1, 1); + if (ret != ERROR_OK) + return ret; + + /* Poll status register */ + return wait_till_ready(bank, 3000); +} + +static int sh_qspi_erase(struct flash_bank *bank, int first, int last) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + int retval = ERROR_OK; + int sector; + + LOG_DEBUG("%s: from sector %d to sector %d", __func__, first, last); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if ((first < 0) || (last < first) || (last >= bank->num_sectors)) { + LOG_ERROR("Flash sector invalid"); + return ERROR_FLASH_SECTOR_INVALID; + } + + if (!info->probed) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + if (info->dev->erase_cmd == 0x00) + return ERROR_FLASH_OPER_UNSUPPORTED; + + for (sector = first; sector <= last; sector++) { + if (bank->sectors[sector].is_protected) { + LOG_ERROR("Flash sector %d protected", sector); + return ERROR_FAIL; + } + } + + for (sector = first; sector <= last; sector++) { + retval = sh_qspi_erase_sector(bank, sector); + if (retval != ERROR_OK) + break; + keep_alive(); + } + + return retval; +} + +static int sh_qspi_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + struct reg_param reg_params[4]; + struct arm_algorithm arm_algo; + uint32_t io_base = (uint32_t)(info->io_base); + uint32_t src_base = (uint32_t)(info->source->address); + uint32_t chunk; + bool addr4b = !!(info->dev->size_in_bytes > (1UL << 24)); + int ret = ERROR_OK; + int sector; + + LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, + __func__, offset, count); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > bank->size) { + LOG_WARNING("Write pasts end of flash. Extra data discarded."); + count = bank->size - offset; + } + + if (offset & 0xff) { + LOG_ERROR("sh_qspi_write_page: unaligned write address: %08x", + offset); + return ERROR_FAIL; + } + + /* Check sector protection */ + for (sector = 0; sector < bank->num_sectors; sector++) { + /* Start offset in or before this sector? */ + /* End offset in or behind this sector? */ + struct flash_sector *bs = &bank->sectors[sector]; + + if ((offset < (bs->offset + bs->size)) && + ((offset + count - 1) >= bs->offset) && + bs->is_protected) { + LOG_ERROR("Flash sector %d protected", sector); + return ERROR_FAIL; + } + } + + LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, + __func__, offset, count); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > bank->size) { + LOG_WARNING("Reads past end of flash. Extra data discarded."); + count = bank->size - offset; + } + + arm_algo.common_magic = ARM_COMMON_MAGIC; + arm_algo.core_mode = ARM_MODE_SVC; + arm_algo.core_state = ARM_STATE_ARM; + + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); + + while (count > 0) { + chunk = (count > info->buffer_size) ? + info->buffer_size : count; + + target_write_buffer(target, info->source->address, + chunk, buffer); + + buf_set_u32(reg_params[0].value, 0, 32, io_base); + buf_set_u32(reg_params[1].value, 0, 32, src_base); + buf_set_u32(reg_params[2].value, 0, 32, + (1 << 31) | (addr4b << 30) | + (info->dev->pprog_cmd << 20) | chunk); + buf_set_u32(reg_params[3].value, 0, 32, offset); + + ret = target_run_algorithm(target, 0, NULL, 4, reg_params, + info->io_algorithm->address, + 0, 10000, &arm_algo); + if (ret != ERROR_OK) { + LOG_ERROR("error executing SH QSPI flash IO algorithm"); + ret = ERROR_FLASH_OPERATION_FAILED; + break; + } + + buffer += chunk; + offset += chunk; + count -= chunk; + } + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + + return ret; +} + +static int sh_qspi_read(struct flash_bank *bank, uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + struct reg_param reg_params[4]; + struct arm_algorithm arm_algo; + uint32_t io_base = (uint32_t)(info->io_base); + uint32_t src_base = (uint32_t)(info->source->address); + uint32_t chunk; + bool addr4b = !!(info->dev->size_in_bytes > (1UL << 24)); + int ret = ERROR_OK; + + LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, + __func__, offset, count); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > bank->size) { + LOG_WARNING("Reads past end of flash. Extra data discarded."); + count = bank->size - offset; + } + + arm_algo.common_magic = ARM_COMMON_MAGIC; + arm_algo.core_mode = ARM_MODE_SVC; + arm_algo.core_state = ARM_STATE_ARM; + + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); + + while (count > 0) { + chunk = (count > info->buffer_size) ? + info->buffer_size : count; + + buf_set_u32(reg_params[0].value, 0, 32, io_base); + buf_set_u32(reg_params[1].value, 0, 32, src_base); + buf_set_u32(reg_params[2].value, 0, 32, + (addr4b << 30) | (info->dev->read_cmd << 20) | + chunk); + buf_set_u32(reg_params[3].value, 0, 32, offset); + + ret = target_run_algorithm(target, 0, NULL, 4, reg_params, + info->io_algorithm->address, + 0, 10000, &arm_algo); + if (ret != ERROR_OK) { + LOG_ERROR("error executing SH QSPI flash IO algorithm"); + ret = ERROR_FLASH_OPERATION_FAILED; + break; + } + + target_read_buffer(target, info->source->address, + chunk, buffer); + + buffer += chunk; + offset += chunk; + count -= chunk; + } + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + + return ret; +} + +/* Return ID of flash device */ +static int read_flash_id(struct flash_bank *bank, uint32_t *id) +{ + struct target *target = bank->target; + uint8_t dout = SPIFLASH_READ_ID; + uint8_t din[3] = { 0, 0, 0 }; + int ret; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + ret = sh_qspi_xfer_common(bank, &dout, 1, din, 3, 1, 1); + if (ret != ERROR_OK) + return ret; + + *id = (din[0] << 0) | (din[1] << 8) | (din[2] << 16); + + if (*id == 0xffffff) { + LOG_ERROR("No SPI flash found"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int sh_qspi_protect(struct flash_bank *bank, int set, + int first, int last) +{ + int sector; + + for (sector = first; sector <= last; sector++) + bank->sectors[sector].is_protected = set; + + return ERROR_OK; +} + +static int sh_qspi_upload_helper(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + + /* see contrib/loaders/flash/sh_qspi.s for src */ + static const uint8_t sh_qspi_io_code[] = { +#include "../../../contrib/loaders/flash/sh_qspi/sh_qspi.inc" + }; + int ret; + + if (info->source) + target_free_working_area(target, info->source); + if (info->io_algorithm) + target_free_working_area(target, info->io_algorithm); + + /* flash write code */ + if (target_alloc_working_area(target, sizeof(sh_qspi_io_code), + &info->io_algorithm) != ERROR_OK) { + LOG_WARNING("no working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + target_write_buffer(target, info->io_algorithm->address, + sizeof(sh_qspi_io_code), sh_qspi_io_code); + + /* + * Try to allocate as big work area buffer as possible, start + * with 32 kiB and count down. If there is less than 256 Bytes + * of work area available, abort. + */ + info->buffer_size = 32768; + while (true) { + ret = target_alloc_working_area_try(target, info->buffer_size, + &info->source); + if (ret == ERROR_OK) + return ret; + + info->buffer_size /= 2; + if (info->buffer_size <= 256) { + target_free_working_area(target, info->io_algorithm); + + LOG_WARNING("no large enough working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + } + + return ERROR_OK; +} + +static int sh_qspi_probe(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct sh_qspi_flash_bank *info = bank->driver_priv; + struct flash_sector *sectors; + uint32_t id = 0; /* silence uninitialized warning */ + uint32_t sectorsize; + const struct sh_qspi_target *target_device; + int ret; + + if (info->probed) + free(bank->sectors); + + info->probed = 0; + + for (target_device = target_devices; target_device->name; + ++target_device) + if (target_device->tap_idcode == target->tap->idcode) + break; + if (!target_device->name) { + LOG_ERROR("Device ID 0x%" PRIx32 " is not known", + target->tap->idcode); + return ERROR_FAIL; + } + + info->io_base = target_device->io_base; + + LOG_DEBUG("Found device %s at address " TARGET_ADDR_FMT, + target_device->name, bank->base); + + ret = sh_qspi_upload_helper(bank); + if (ret != ERROR_OK) + return ret; + + ret = sh_qspi_init(bank); + if (ret != ERROR_OK) + return ret; + + ret = read_flash_id(bank, &id); + if (ret != ERROR_OK) + return ret; + + info->dev = NULL; + for (const struct flash_device *p = flash_devices; p->name; p++) + if (p->device_id == id) { + info->dev = p; + break; + } + + if (!info->dev) { + LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id); + return ERROR_FAIL; + } + + LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")", + info->dev->name, info->dev->device_id); + + /* Set correct size value */ + bank->size = info->dev->size_in_bytes; + if (bank->size <= (1UL << 16)) + LOG_WARNING("device needs 2-byte addresses - not implemented"); + + /* if no sectors, treat whole bank as single sector */ + sectorsize = info->dev->sectorsize ? + info->dev->sectorsize : + info->dev->size_in_bytes; + + /* create and fill sectors array */ + bank->num_sectors = info->dev->size_in_bytes / sectorsize; + sectors = calloc(1, sizeof(*sectors) * bank->num_sectors); + if (!sectors) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + for (int sector = 0; sector < bank->num_sectors; sector++) { + sectors[sector].offset = sector * sectorsize; + sectors[sector].size = sectorsize; + sectors[sector].is_erased = 0; + sectors[sector].is_protected = 0; + } + + bank->sectors = sectors; + info->probed = 1; + return ERROR_OK; +} + +static int sh_qspi_auto_probe(struct flash_bank *bank) +{ + struct sh_qspi_flash_bank *info = bank->driver_priv; + + if (info->probed) + return ERROR_OK; + + return sh_qspi_probe(bank); +} + +static int sh_qspi_flash_blank_check(struct flash_bank *bank) +{ + /* Not implemented */ + return ERROR_OK; +} + +static int sh_qspi_protect_check(struct flash_bank *bank) +{ + /* Not implemented */ + return ERROR_OK; +} + +static int sh_qspi_get_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct sh_qspi_flash_bank *info = bank->driver_priv; + + if (!info->probed) { + snprintf(buf, buf_size, + "\nSH QSPI flash bank not probed yet\n"); + return ERROR_OK; + } + + snprintf(buf, buf_size, "\nSH QSPI flash information:\n" + " Device \'%s\' (ID 0x%08" PRIx32 ")\n", + info->dev->name, info->dev->device_id); + + return ERROR_OK; +} + +FLASH_BANK_COMMAND_HANDLER(sh_qspi_flash_bank_command) +{ + struct sh_qspi_flash_bank *info; + + LOG_DEBUG("%s", __func__); + + if (CMD_ARGC < 6 || CMD_ARGC > 7) + return ERROR_COMMAND_SYNTAX_ERROR; + + if ((CMD_ARGC == 7) && strcmp(CMD_ARGV[6], "cs0")) { + LOG_ERROR("Unknown arg: %s", CMD_ARGV[6]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + info = calloc(1, sizeof(struct sh_qspi_flash_bank)); + if (!info) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + bank->driver_priv = info; + + return ERROR_OK; +} + +const struct flash_driver sh_qspi_flash = { + .name = "sh_qspi", + .flash_bank_command = sh_qspi_flash_bank_command, + .erase = sh_qspi_erase, + .protect = sh_qspi_protect, + .write = sh_qspi_write, + .read = sh_qspi_read, + .probe = sh_qspi_probe, + .auto_probe = sh_qspi_auto_probe, + .erase_check = sh_qspi_flash_blank_check, + .protect_check = sh_qspi_protect_check, + .info = sh_qspi_get_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/sim3x.c b/src/flash/nor/sim3x.c index 7ccf56b..4e39705 100644 --- a/src/flash/nor/sim3x.c +++ b/src/flash/nor/sim3x.c @@ -471,7 +471,7 @@ static int sim3x_write_block(struct flash_bank *bank, const uint8_t *buf, return ret; } -static int sim3x_flash_write(struct flash_bank *bank, const uint8_t * buffer, uint32_t offset, uint32_t count) +static int sim3x_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int ret; struct target *target; diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index cf10e37..990b48a 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -116,7 +116,7 @@ struct stm32x_options { struct stm32x_flash_bank { struct stm32x_options option_bytes; int ppage_size; - int probed; + bool probed; bool has_dual_banks; /* used to access dual flash bank stm32xl */ @@ -145,7 +145,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) stm32x_info = malloc(sizeof(struct stm32x_flash_bank)); bank->driver_priv = stm32x_info; - stm32x_info->probed = 0; + stm32x_info->probed = false; stm32x_info->has_dual_banks = false; stm32x_info->can_load_options = false; stm32x_info->register_base = FLASH_REG_BASE_B0; @@ -229,34 +229,20 @@ static int stm32x_read_options(struct flash_bank *bank) uint32_t option_bytes; int retval; - /* read user and read protection option bytes */ - retval = target_read_u32(target, STM32_OB_RDP, &option_bytes); + /* read user and read protection option bytes, user data option bytes */ + retval = target_read_u32(target, STM32_FLASH_OBR_B0, &option_bytes); if (retval != ERROR_OK) return retval; - stm32x_info->option_bytes.rdp = option_bytes & 0xFF; - stm32x_info->option_bytes.user = (option_bytes >> 16) & 0xFF; - - /* read user data option bytes */ - retval = target_read_u32(target, STM32_OB_DATA0, &option_bytes); - if (retval != ERROR_OK) - return retval; - - stm32x_info->option_bytes.data = ((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF); + stm32x_info->option_bytes.rdp = (option_bytes & (1 << OPT_READOUT)) ? 0 : stm32x_info->default_rdp; + stm32x_info->option_bytes.user = (option_bytes >> stm32x_info->option_offset >> 2) & 0xff; + stm32x_info->option_bytes.data = (option_bytes >> stm32x_info->user_data_offset) & 0xffff; /* read write protection option bytes */ - retval = target_read_u32(target, STM32_OB_WRP0, &option_bytes); + retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &stm32x_info->option_bytes.protection); if (retval != ERROR_OK) return retval; - stm32x_info->option_bytes.protection = ((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF); - - retval = target_read_u32(target, STM32_OB_WRP2, &option_bytes); - if (retval != ERROR_OK) - return retval; - - stm32x_info->option_bytes.protection |= (((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF)) << 16; - return ERROR_OK; } @@ -382,7 +368,6 @@ static int stm32x_protect_check(struct flash_bank *bank) static int stm32x_erase(struct flash_bank *bank, int first, int last) { struct target *target = bank->target; - int i; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -400,7 +385,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) if (retval != ERROR_OK) return retval; - for (i = first; i <= last; i++) { + for (int i = first; i <= last; i++) { retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PER); if (retval != ERROR_OK) return retval; @@ -711,7 +696,7 @@ static int stm32x_probe(struct flash_bank *bank) int page_size; uint32_t base_address = 0x08000000; - stm32x_info->probed = 0; + stm32x_info->probed = false; stm32x_info->register_base = FLASH_REG_BASE_B0; stm32x_info->user_data_offset = 10; stm32x_info->option_offset = 0; @@ -728,31 +713,79 @@ static int stm32x_probe(struct flash_bank *bank) /* set page size, protection granularity and max flash size depending on family */ switch (device_id & 0xfff) { - case 0x410: /* medium density */ + case 0x440: /* stm32f05x */ + page_size = 1024; + stm32x_info->ppage_size = 4; + max_flash_size_in_kb = 64; + stm32x_info->user_data_offset = 16; + stm32x_info->option_offset = 6; + stm32x_info->default_rdp = 0xAA; + stm32x_info->can_load_options = true; + break; + case 0x444: /* stm32f03x */ + case 0x445: /* stm32f04x */ + page_size = 1024; + stm32x_info->ppage_size = 4; + max_flash_size_in_kb = 32; + stm32x_info->user_data_offset = 16; + stm32x_info->option_offset = 6; + stm32x_info->default_rdp = 0xAA; + stm32x_info->can_load_options = true; + break; + case 0x448: /* stm32f07x */ + page_size = 2048; + stm32x_info->ppage_size = 4; + max_flash_size_in_kb = 128; + stm32x_info->user_data_offset = 16; + stm32x_info->option_offset = 6; + stm32x_info->default_rdp = 0xAA; + stm32x_info->can_load_options = true; + break; + case 0x442: /* stm32f09x */ + page_size = 2048; + stm32x_info->ppage_size = 4; + max_flash_size_in_kb = 256; + stm32x_info->user_data_offset = 16; + stm32x_info->option_offset = 6; + stm32x_info->default_rdp = 0xAA; + stm32x_info->can_load_options = true; + break; + case 0x410: /* stm32f1x medium-density */ page_size = 1024; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 128; break; - case 0x412: /* low density */ + case 0x412: /* stm32f1x low-density */ page_size = 1024; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 32; break; - case 0x414: /* high density */ + case 0x414: /* stm32f1x high-density */ page_size = 2048; stm32x_info->ppage_size = 2; max_flash_size_in_kb = 512; break; - case 0x418: /* connectivity line density */ + case 0x418: /* stm32f1x connectivity */ page_size = 2048; stm32x_info->ppage_size = 2; max_flash_size_in_kb = 256; break; - case 0x420: /* value line density */ + case 0x430: /* stm32f1 XL-density (dual flash banks) */ + page_size = 2048; + stm32x_info->ppage_size = 2; + max_flash_size_in_kb = 1024; + stm32x_info->has_dual_banks = true; + break; + case 0x420: /* stm32f100xx low- and medium-density value line */ page_size = 1024; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 128; break; + case 0x428: /* stm32f100xx high-density value line */ + page_size = 2048; + stm32x_info->ppage_size = 4; + max_flash_size_in_kb = 512; + break; case 0x422: /* stm32f302/3xb/c */ page_size = 2048; stm32x_info->ppage_size = 2; @@ -771,17 +804,6 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->default_rdp = 0xAA; stm32x_info->can_load_options = true; break; - case 0x428: /* value line High density */ - page_size = 2048; - stm32x_info->ppage_size = 4; - max_flash_size_in_kb = 128; - break; - case 0x430: /* xl line density (dual flash banks) */ - page_size = 2048; - stm32x_info->ppage_size = 2; - max_flash_size_in_kb = 1024; - stm32x_info->has_dual_banks = true; - break; case 0x432: /* stm32f37x */ page_size = 2048; stm32x_info->ppage_size = 2; @@ -801,27 +823,6 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->default_rdp = 0xAA; stm32x_info->can_load_options = true; break; - case 0x440: /* stm32f05x */ - case 0x444: /* stm32f03x */ - case 0x445: /* stm32f04x */ - page_size = 1024; - stm32x_info->ppage_size = 4; - max_flash_size_in_kb = 64; - stm32x_info->user_data_offset = 16; - stm32x_info->option_offset = 6; - stm32x_info->default_rdp = 0xAA; - stm32x_info->can_load_options = true; - break; - case 0x448: /* stm32f07x */ - case 0x442: /* stm32f09x */ - page_size = 2048; - stm32x_info->ppage_size = 4; - max_flash_size_in_kb = 256; - stm32x_info->user_data_offset = 16; - stm32x_info->option_offset = 6; - stm32x_info->default_rdp = 0xAA; - stm32x_info->can_load_options = true; - break; default: LOG_WARNING("Cannot identify target as a STM32 family."); return ERROR_FAIL; @@ -900,7 +901,7 @@ static int stm32x_probe(struct flash_bank *bank) if (num_prot_blocks == 32) bank->prot_blocks[31].size = (num_pages - (31 * stm32x_info->ppage_size)) * page_size; - stm32x_info->probed = 1; + stm32x_info->probed = true; return ERROR_OK; } @@ -1368,8 +1369,7 @@ COMMAND_HANDLER(stm32x_handle_options_write_command) COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], useropt); CMD_ARGC--; CMD_ARGV++; - } - else if (stm32x_info->has_dual_banks) { + } else if (stm32x_info->has_dual_banks) { if (strcmp("BOOT0", CMD_ARGV[0]) == 0) optionbyte |= (1 << 3); else if (strcmp("BOOT1", CMD_ARGV[0]) == 0) @@ -1488,8 +1488,6 @@ static int stm32x_mass_erase(struct flash_bank *bank) COMMAND_HANDLER(stm32x_handle_mass_erase_command) { - int i; - if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; @@ -1501,7 +1499,7 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command) retval = stm32x_mass_erase(bank); if (retval == ERROR_OK) { /* set all sectors as erased */ - for (i = 0; i < bank->num_sectors; i++) + for (int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; command_print(CMD, "stm32x mass erase complete"); diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index b49e76e..c1283bb 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -634,7 +634,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) */ for (i = first; i <= last; i++) { - int snb; + unsigned int snb; if (stm32x_info->has_large_mem && i >= 12) snb = (i - 12) | 0x10; else @@ -894,31 +894,68 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, return target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK); } -static int setup_sector(struct flash_bank *bank, int start, int num, int size) +static void setup_sector(struct flash_bank *bank, int i, int size) { + assert(i < bank->num_sectors); + bank->sectors[i].offset = bank->size; + bank->sectors[i].size = size; + bank->size += bank->sectors[i].size; + LOG_DEBUG("sector %d: %dkBytes", i, size >> 10); +} + +static uint16_t sector_size_in_kb(int i, uint16_t max_sector_size_in_kb) +{ + assert(i >= 0); + if (i < 4) + return max_sector_size_in_kb / 8; + if (i == 4) + return max_sector_size_in_kb / 2; + return max_sector_size_in_kb; +} + +static int calculate_number_of_sectors(struct flash_bank *bank, + uint16_t flash_size_in_kb, + uint16_t max_sector_size_in_kb) +{ + struct stm32x_flash_bank *stm32x_info = bank->driver_priv; + uint16_t remaining_flash_size_in_kb = flash_size_in_kb; + int nr_sectors; - for (int i = start; i < (start + num) ; i++) { - assert(i < bank->num_sectors); - bank->sectors[i].offset = bank->size; - bank->sectors[i].size = size; - bank->size += bank->sectors[i].size; - LOG_DEBUG("sector %d: %d kBytes", i, size >> 10); + /* Dual Bank Flash has two identically-arranged banks of sectors. */ + if (stm32x_info->has_large_mem) + remaining_flash_size_in_kb /= 2; + + for (nr_sectors = 0; remaining_flash_size_in_kb > 0; nr_sectors++) { + uint16_t size_in_kb = sector_size_in_kb(nr_sectors, max_sector_size_in_kb); + if (size_in_kb > remaining_flash_size_in_kb) { + LOG_INFO("%s Bank %" PRIu16 " kiB final sector clipped to %" PRIu16 " kiB", + stm32x_info->has_large_mem ? "Dual" : "Single", + flash_size_in_kb, remaining_flash_size_in_kb); + remaining_flash_size_in_kb = 0; + } else { + remaining_flash_size_in_kb -= size_in_kb; + } } - return start + num; + return stm32x_info->has_large_mem ? nr_sectors*2 : nr_sectors; } static void setup_bank(struct flash_bank *bank, int start, uint16_t flash_size_in_kb, uint16_t max_sector_size_in_kb) { - int remain; - - start = setup_sector(bank, start, 4, (max_sector_size_in_kb / 8) * 1024); - start = setup_sector(bank, start, 1, (max_sector_size_in_kb / 2) * 1024); - - /* remaining sectors all of size max_sector_size_in_kb */ - remain = (flash_size_in_kb / max_sector_size_in_kb) - 1; - start = setup_sector(bank, start, remain, max_sector_size_in_kb * 1024); + uint16_t remaining_flash_size_in_kb = flash_size_in_kb; + int sector_index = 0; + while (remaining_flash_size_in_kb > 0) { + uint16_t size_in_kb = sector_size_in_kb(sector_index, max_sector_size_in_kb); + if (size_in_kb > remaining_flash_size_in_kb) { + /* Clip last sector. Already warned in + * calculate_number_of_sectors. */ + size_in_kb = remaining_flash_size_in_kb; + } + setup_sector(bank, start + sector_index, size_in_kb * 1024); + remaining_flash_size_in_kb -= size_in_kb; + sector_index++; + } } static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) @@ -1150,12 +1187,12 @@ static int stm32x_probe(struct flash_bank *bank) } /* calculate numbers of pages */ - int num_pages = flash_size_in_kb / max_sector_size_in_kb - + (stm32x_info->has_large_mem ? 8 : 4); + int num_pages = calculate_number_of_sectors( + bank, flash_size_in_kb, max_sector_size_in_kb); bank->base = base_address; bank->num_sectors = num_pages; - bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); + bank->sectors = calloc(num_pages, sizeof(struct flash_sector)); for (i = 0; i < num_pages; i++) { bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index fd6bf9a..7b6fdb3 100644 --- a/src/flash/nor/stm32h7x.c +++ b/src/flash/nor/stm32h7x.c @@ -57,8 +57,6 @@ #define FLASH_FW (1 << 6) #define FLASH_START (1 << 7) -#define FLASH_SNB(a) ((a) << 8) - /* FLASH_SR register bits */ #define FLASH_BSY (1 << 0) /* Operation in progress */ #define FLASH_QW (1 << 2) /* Operation queue in progress */ @@ -79,6 +77,15 @@ #define OPT_LOCK (1 << 0) #define OPT_START (1 << 1) +/* FLASH_OPTSR register bits */ +#define OPT_BSY (1 << 0) +#define OPT_RDP_POS 8 +#define OPT_RDP_MASK (0xff << OPT_RDP_POS) +#define OPT_OPTCHANGEERR (1 << 30) + +/* FLASH_OPTCCR register bits */ +#define OPT_CLR_OPTCHANGEERR (1 << 30) + /* register unlock keys */ #define KEY1 0x45670123 #define KEY2 0xCDEF89AB @@ -92,68 +99,103 @@ #define FLASH_BANK1_ADDRESS 0x08100000 #define FLASH_REG_BASE_B0 0x52002000 #define FLASH_REG_BASE_B1 0x52002100 -#define FLASH_SIZE_ADDRESS 0x1FF1E880 -#define FLASH_BLOCK_SIZE 32 struct stm32h7x_rev { uint16_t rev; const char *str; }; -struct stm32x_options { - uint8_t RDP; - uint32_t protection; /* bank1 WRP */ - uint32_t protection2; /* bank2 WRP */ - uint8_t user_options; - uint8_t user2_options; - uint8_t user3_options; -}; +/* stm32h7x_part_info permits the store each device information and specificities. + * the default unit is byte unless the suffix '_kb' is used. */ struct stm32h7x_part_info { uint16_t id; const char *device_str; const struct stm32h7x_rev *revs; size_t num_revs; - unsigned int page_size; + unsigned int page_size_kb; + unsigned int block_size; /* flash write word size in bytes */ uint16_t max_flash_size_kb; - uint8_t has_dual_bank; - uint16_t first_bank_size_kb; /* Used when has_dual_bank is true */ - uint32_t flash_base; /* Flash controller registers location */ - uint32_t fsize_base; /* Location of FSIZE register */ + bool has_dual_bank; + uint16_t max_bank_size_kb; /* Used when has_dual_bank is true */ + uint32_t fsize_addr; /* Location of FSIZE register */ + uint32_t wps_group_size; /* write protection group sectors' count */ + uint32_t wps_mask; + /* function to compute flash_cr register values */ + uint32_t (*compute_flash_cr)(uint32_t cmd, int snb); }; struct stm32h7x_flash_bank { - int probed; + bool probed; uint32_t idcode; uint32_t user_bank_size; - uint32_t flash_base; /* Address of flash reg controller */ - struct stm32x_options option_bytes; + uint32_t flash_regs_base; /* Address of flash reg controller */ const struct stm32h7x_part_info *part_info; }; +enum stm32h7x_opt_rdp { + OPT_RDP_L0 = 0xaa, + OPT_RDP_L1 = 0x00, + OPT_RDP_L2 = 0xcc +}; + static const struct stm32h7x_rev stm32_450_revs[] = { - { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2001, "X" }, + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2001, "X" }, { 0x2003, "V" }, +}; + +static const struct stm32h7x_rev stm32_480_revs[] = { + { 0x1000, "A"}, }; +static uint32_t stm32x_compute_flash_cr_450(uint32_t cmd, int snb) +{ + return cmd | (snb << 8); +} + +static uint32_t stm32x_compute_flash_cr_480(uint32_t cmd, int snb) +{ + /* save FW and START bits, to be right shifted by 2 bits later */ + const uint32_t tmp = cmd & (FLASH_FW | FLASH_START); + + /* mask parallelism (ignored), FW and START bits */ + cmd &= ~(FLASH_PSIZE_64 | FLASH_FW | FLASH_START); + + return cmd | (tmp >> 2) | (snb << 6); +} + static const struct stm32h7x_part_info stm32h7x_parts[] = { { .id = 0x450, .revs = stm32_450_revs, .num_revs = ARRAY_SIZE(stm32_450_revs), .device_str = "STM32H74x/75x", - .page_size = 128, /* 128 KB */ + .page_size_kb = 128, + .block_size = 32, + .max_flash_size_kb = 2048, + .max_bank_size_kb = 1024, + .has_dual_bank = true, + .fsize_addr = 0x1FF1E880, + .wps_group_size = 1, + .wps_mask = 0xFF, + .compute_flash_cr = stm32x_compute_flash_cr_450, + }, + { + .id = 0x480, + .revs = stm32_480_revs, + .num_revs = ARRAY_SIZE(stm32_480_revs), + .device_str = "STM32H7Ax/7Bx", + .page_size_kb = 8, + .block_size = 16, .max_flash_size_kb = 2048, - .first_bank_size_kb = 1024, - .has_dual_bank = 1, - .flash_base = FLASH_REG_BASE_B0, - .fsize_base = FLASH_SIZE_ADDRESS, + .max_bank_size_kb = 1024, + .has_dual_bank = true, + .fsize_addr = 0x08FFF80C, + .wps_group_size = 4, + .wps_mask = 0xFFFFFFFF, + .compute_flash_cr = stm32x_compute_flash_cr_480, }, }; -static int stm32x_unlock_reg(struct flash_bank *bank); -static int stm32x_lock_reg(struct flash_bank *bank); -static int stm32x_probe(struct flash_bank *bank); - /* flash bank stm32x <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) @@ -166,51 +208,68 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) stm32x_info = malloc(sizeof(struct stm32h7x_flash_bank)); bank->driver_priv = stm32x_info; - stm32x_info->probed = 0; + stm32x_info->probed = false; stm32x_info->user_bank_size = bank->size; return ERROR_OK; } -static inline uint32_t stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg) +static inline uint32_t stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset) { struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; - return reg + stm32x_info->flash_base; + return reg_offset + stm32x_info->flash_regs_base; +} + +static inline int stm32x_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value) +{ + uint32_t reg_addr = stm32x_get_flash_reg(bank, reg_offset); + int retval = target_read_u32(bank->target, reg_addr, value); + + if (retval != ERROR_OK) + LOG_ERROR("error while reading from address 0x%" PRIx32, reg_addr); + + return retval; +} + +static inline int stm32x_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) +{ + uint32_t reg_addr = stm32x_get_flash_reg(bank, reg_offset); + int retval = target_write_u32(bank->target, reg_addr, value); + + if (retval != ERROR_OK) + LOG_ERROR("error while writing to address 0x%" PRIx32, reg_addr); + + return retval; } static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *status) { - struct target *target = bank->target; - return target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_SR), status); + return stm32x_read_flash_reg(bank, FLASH_SR, status); } static int stm32x_wait_flash_op_queue(struct flash_bank *bank, int timeout) { - struct target *target = bank->target; - struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; uint32_t status; int retval; /* wait for flash operations completion */ for (;;) { retval = stm32x_get_flash_status(bank, &status); - if (retval != ERROR_OK) { - LOG_INFO("wait_flash_op_queue, target_read_u32 : error : remote address 0x%x", stm32x_info->flash_base); + if (retval != ERROR_OK) return retval; - } if ((status & FLASH_QW) == 0) break; if (timeout-- <= 0) { - LOG_INFO("wait_flash_op_queue, time out expired, status: 0x%" PRIx32 "", status); + LOG_ERROR("wait_flash_op_queue, time out expired, status: 0x%" PRIx32 "", status); return ERROR_FAIL; } alive_sleep(1); } if (status & FLASH_WRPERR) { - LOG_INFO("wait_flash_op_queue, WRPERR : error : remote address 0x%x", stm32x_info->flash_base); + LOG_ERROR("wait_flash_op_queue, WRPERR detected"); retval = ERROR_FAIL; } @@ -219,7 +278,7 @@ static int stm32x_wait_flash_op_queue(struct flash_bank *bank, int timeout) 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); + stm32x_write_flash_reg(bank, FLASH_CCR, status); } return retval; } @@ -227,12 +286,11 @@ static int stm32x_wait_flash_op_queue(struct flash_bank *bank, int timeout) static int stm32x_unlock_reg(struct flash_bank *bank) { uint32_t ctrl; - struct target *target = bank->target; /* first check if not already unlocked * otherwise writing on FLASH_KEYR will fail */ - int retval = target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), &ctrl); + int retval = stm32x_read_flash_reg(bank, FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; @@ -240,15 +298,15 @@ static int stm32x_unlock_reg(struct flash_bank *bank) return ERROR_OK; /* unlock flash registers for bank */ - retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_KEYR), KEY1); + retval = stm32x_write_flash_reg(bank, FLASH_KEYR, KEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_KEYR), KEY2); + retval = stm32x_write_flash_reg(bank, FLASH_KEYR, KEY2); if (retval != ERROR_OK) return retval; - retval = target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), &ctrl); + retval = stm32x_read_flash_reg(bank, FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; @@ -262,9 +320,8 @@ static int stm32x_unlock_reg(struct flash_bank *bank) static int stm32x_unlock_option_reg(struct flash_bank *bank) { uint32_t ctrl; - struct target *target = bank->target; - int retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, &ctrl); + int retval = stm32x_read_flash_reg(bank, FLASH_OPTCR, &ctrl); if (retval != ERROR_OK) return retval; @@ -272,15 +329,15 @@ static int stm32x_unlock_option_reg(struct flash_bank *bank) return ERROR_OK; /* unlock option registers */ - retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTKEYR, OPTKEY1); + retval = stm32x_write_flash_reg(bank, FLASH_OPTKEYR, OPTKEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTKEYR, OPTKEY2); + retval = stm32x_write_flash_reg(bank, FLASH_OPTKEYR, OPTKEY2); if (retval != ERROR_OK) return retval; - retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, &ctrl); + retval = stm32x_read_flash_reg(bank, FLASH_OPTCR, &ctrl); if (retval != ERROR_OK) return retval; @@ -292,159 +349,108 @@ static int stm32x_unlock_option_reg(struct flash_bank *bank) return ERROR_OK; } -static int stm32x_lock_reg(struct flash_bank *bank) +static inline int stm32x_lock_reg(struct flash_bank *bank) { - struct target *target = bank->target; - - /* Lock bank reg */ - int retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_LOCK); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; + return stm32x_write_flash_reg(bank, FLASH_CR, FLASH_LOCK); } -static int stm32x_read_options(struct flash_bank *bank) +static inline int stm32x_lock_option_reg(struct flash_bank *bank) { - uint32_t optiondata; - struct stm32h7x_flash_bank *stm32x_info = NULL; - struct target *target = bank->target; - - stm32x_info = bank->driver_priv; - - /* read current option bytes */ - int retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTSR_CUR, &optiondata); - if (retval != ERROR_OK) - return retval; - - /* decode option data */ - stm32x_info->option_bytes.user_options = optiondata & 0xfc; - stm32x_info->option_bytes.RDP = (optiondata >> 8) & 0xff; - stm32x_info->option_bytes.user2_options = (optiondata >> 16) & 0xff; - stm32x_info->option_bytes.user3_options = (optiondata >> 24) & 0xa3; - - if (stm32x_info->option_bytes.RDP != 0xAA) - LOG_INFO("Device Security Bit Set"); - - /* read current WPSN option bytes */ - retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_WPSN_CUR, &optiondata); - if (retval != ERROR_OK) - return retval; - stm32x_info->option_bytes.protection = optiondata & 0xff; - - /* read current WPSN2 option bytes */ - retval = target_read_u32(target, FLASH_REG_BASE_B1 + FLASH_WPSN_CUR, &optiondata); - if (retval != ERROR_OK) - return retval; - stm32x_info->option_bytes.protection2 = optiondata & 0xff; - - return ERROR_OK; + return stm32x_write_flash_reg(bank, FLASH_OPTCR, OPT_LOCK); } -static int stm32x_write_options(struct flash_bank *bank) +static int stm32x_write_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) { - struct stm32h7x_flash_bank *stm32x_info = NULL; - struct target *target = bank->target; - uint32_t optiondata; - - stm32x_info = bank->driver_priv; - - int retval = stm32x_unlock_option_reg(bank); - if (retval != ERROR_OK) - return retval; - - /* rebuild option data */ - optiondata = stm32x_info->option_bytes.user_options; - optiondata |= (stm32x_info->option_bytes.RDP << 8); - optiondata |= (stm32x_info->option_bytes.user2_options & 0xff) << 16; - optiondata |= (stm32x_info->option_bytes.user3_options & 0xa3) << 24; + int retval, retval2; - /* program options */ - retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTSR_PRG, optiondata); + /* unlock option bytes for modification */ + retval = stm32x_unlock_option_reg(bank); if (retval != ERROR_OK) - return retval; + goto flash_options_lock; - optiondata = stm32x_info->option_bytes.protection & 0xff; - /* Program protection WPSNPRG */ - retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_WPSN_PRG, optiondata); + /* write option bytes */ + retval = stm32x_write_flash_reg(bank, reg_offset, value); if (retval != ERROR_OK) - return retval; + goto flash_options_lock; - optiondata = stm32x_info->option_bytes.protection2 & 0xff; - /* Program protection WPSNPRG2 */ - retval = target_write_u32(target, FLASH_REG_BASE_B1 + FLASH_WPSN_PRG, optiondata); - if (retval != ERROR_OK) - return retval; - - optiondata = 0x40000000; /* Remove OPT error flag before programming */ - retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCCR, optiondata); + retval = stm32x_write_flash_reg(bank, FLASH_OPTCCR, OPT_CLR_OPTCHANGEERR); if (retval != ERROR_OK) - return retval; + goto flash_options_lock; /* start programming cycle */ - retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, OPT_START); + retval = stm32x_write_flash_reg(bank, FLASH_OPTCR, OPT_START); if (retval != ERROR_OK) - return retval; + goto flash_options_lock; /* wait for completion */ int timeout = FLASH_ERASE_TIMEOUT; + uint32_t status; for (;;) { - uint32_t status; - retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_SR, &status); + retval = stm32x_read_flash_reg(bank, FLASH_OPTSR_CUR, &status); if (retval != ERROR_OK) { - LOG_INFO("stm32x_write_options: wait_flash_op_queue : error"); - return retval; + LOG_ERROR("stm32x_options_program: failed to read FLASH_OPTSR_CUR"); + goto flash_options_lock; } - if ((status & FLASH_QW) == 0) + if ((status & OPT_BSY) == 0) break; if (timeout-- <= 0) { - LOG_INFO("wait_flash_op_queue, time out expired, status: 0x%" PRIx32 "", status); - return ERROR_FAIL; + LOG_ERROR("waiting for OBL launch, time out expired, OPTSR: 0x%" PRIx32 "", status); + retval = ERROR_FAIL; + goto flash_options_lock; } alive_sleep(1); } - /* relock option registers */ - retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, OPT_LOCK); + /* check for failure */ + if (status & OPT_OPTCHANGEERR) { + LOG_ERROR("error changing option bytes (OPTCHANGEERR=1)"); + retval = ERROR_FLASH_OPERATION_FAILED; + } + +flash_options_lock: + retval2 = stm32x_lock_option_reg(bank); + if (retval2 != ERROR_OK) + LOG_ERROR("error during the lock of flash options"); + + return (retval == ERROR_OK) ? retval2 : retval; +} + +static int stm32x_modify_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value, uint32_t mask) +{ + uint32_t data; + + int retval = stm32x_read_flash_reg(bank, reg_offset, &data); if (retval != ERROR_OK) return retval; - return ERROR_OK; + data = (data & ~mask) | (value & mask); + + return stm32x_write_option(bank, reg_offset, data); } static int stm32x_protect_check(struct flash_bank *bank) { - struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + uint32_t protection; /* read 'write protection' settings */ - int retval = stm32x_read_options(bank); + int retval = stm32x_read_flash_reg(bank, FLASH_WPSN_CUR, &protection); if (retval != ERROR_OK) { - LOG_DEBUG("unable to read option bytes"); + LOG_DEBUG("unable to read WPSN_CUR register"); return retval; } - for (int i = 0; i < bank->num_sectors; i++) { - if (stm32x_info->flash_base == FLASH_REG_BASE_B0) { - if (stm32x_info->option_bytes.protection & (1 << i)) - bank->sectors[i].is_protected = 0; - else - bank->sectors[i].is_protected = 1; - } else { - if (stm32x_info->option_bytes.protection2 & (1 << i)) - bank->sectors[i].is_protected = 0; - else - bank->sectors[i].is_protected = 1; - } - } + for (int i = 0; i < bank->num_prot_blocks; i++) + bank->prot_blocks[i].is_protected = protection & (1 << i) ? 0 : 1; + return ERROR_OK; } static int stm32x_erase(struct flash_bank *bank, int first, int last) { - struct target *target = bank->target; - int retval; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + int retval, retval2; assert(first < bank->num_sectors); assert(last < bank->num_sectors); @@ -454,7 +460,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) retval = stm32x_unlock_reg(bank); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* Sector Erase @@ -468,92 +474,84 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) */ for (int i = first; i <= last; i++) { LOG_DEBUG("erase sector %d", i); - retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), - FLASH_SER | FLASH_SNB(i) | FLASH_PSIZE_64); + retval = stm32x_write_flash_reg(bank, FLASH_CR, + stm32x_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64, i)); if (retval != ERROR_OK) { LOG_ERROR("Error erase sector %d", i); - return retval; + goto flash_lock; } - retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), - FLASH_SER | FLASH_SNB(i) | FLASH_PSIZE_64 | FLASH_START); + retval = stm32x_write_flash_reg(bank, FLASH_CR, + stm32x_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64 | FLASH_START, i)); if (retval != ERROR_OK) { LOG_ERROR("Error erase sector %d", i); - return retval; + goto flash_lock; } retval = stm32x_wait_flash_op_queue(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) { LOG_ERROR("erase time-out or operation error sector %d", i); - return retval; + goto flash_lock; } bank->sectors[i].is_erased = 1; } - retval = stm32x_lock_reg(bank); - if (retval != ERROR_OK) { +flash_lock: + retval2 = stm32x_lock_reg(bank); + if (retval2 != ERROR_OK) LOG_ERROR("error during the lock of flash"); - return retval; - } - return ERROR_OK; + return (retval == ERROR_OK) ? retval2 : retval; } static int stm32x_protect(struct flash_bank *bank, int set, int first, int last) { struct target *target = bank->target; - struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + uint32_t protection; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - /* read protection settings */ - int retval = stm32x_read_options(bank); + + /* read 'write protection' settings */ + int retval = stm32x_read_flash_reg(bank, FLASH_WPSN_CUR, &protection); if (retval != ERROR_OK) { - LOG_DEBUG("unable to read option bytes"); + LOG_DEBUG("unable to read WPSN_CUR register"); return retval; } for (int i = first; i <= last; i++) { - if (stm32x_info->flash_base == FLASH_REG_BASE_B0) { - if (set) - stm32x_info->option_bytes.protection &= ~(1 << i); - else - stm32x_info->option_bytes.protection |= (1 << i); - } else { - if (set) - stm32x_info->option_bytes.protection2 &= ~(1 << i); - else - stm32x_info->option_bytes.protection2 |= (1 << i); - } + if (set) + protection &= ~(1 << i); + else + protection |= (1 << i); } - LOG_INFO("stm32x_protect, option_bytes written WRP1 0x%x , WRP2 0x%x", - (stm32x_info->option_bytes.protection & 0xff), (stm32x_info->option_bytes.protection2 & 0xff)); + /* apply WRPSN mask */ + protection &= 0xff; - retval = stm32x_write_options(bank); - if (retval != ERROR_OK) - return retval; + LOG_DEBUG("stm32x_protect, option_bytes written WPSN 0x%" PRIx32, protection); - return ERROR_OK; + /* apply new option value */ + return stm32x_write_option(bank, FLASH_WPSN_PRG, protection); } static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; /* - * If the size of the data part of the buffer is not a multiple of FLASH_BLOCK_SIZE, we get + * If the size of the data part of the buffer is not a multiple of .block_size, we get * "corrupted fifo read" pointer in target_run_flash_async_algorithm() */ - uint32_t data_size = 512 * FLASH_BLOCK_SIZE; /* 16384 */ + uint32_t data_size = 512 * stm32x_info->part_info->block_size; uint32_t buffer_size = 8 + data_size; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; - struct reg_param reg_params[5]; + struct reg_param reg_params[6]; struct armv7m_algorithm armv7m_info; - struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; int retval = ERROR_OK; static const uint8_t stm32x_flash_write_code[] = { @@ -588,7 +586,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, } } - LOG_DEBUG("target_alloc_working_area_try : buffer_size -> 0x%x", buffer_size); + LOG_DEBUG("target_alloc_working_area_try : buffer_size -> 0x%" PRIx32, buffer_size); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; @@ -596,27 +594,29 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ - init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (word-256 bits) */ - init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash reg base */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count of words (word size = .block_size (bytes) */ + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* word size in bytes */ + init_reg_param(®_params[5], "r5", 32, PARAM_OUT); /* flash reg base */ buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[2].value, 0, 32, address); buf_set_u32(reg_params[3].value, 0, 32, count); - buf_set_u32(reg_params[4].value, 0, 32, stm32x_info->flash_base); + buf_set_u32(reg_params[4].value, 0, 32, stm32x_info->part_info->block_size); + buf_set_u32(reg_params[5].value, 0, 32, stm32x_info->flash_regs_base); retval = target_run_flash_async_algorithm(target, buffer, count, - FLASH_BLOCK_SIZE, + stm32x_info->part_info->block_size, 0, NULL, - 5, reg_params, + ARRAY_SIZE(reg_params), reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { - LOG_INFO("error executing stm32h7x flash write algorithm"); + LOG_ERROR("error executing stm32h7x flash write algorithm"); uint32_t flash_sr = buf_get_u32(reg_params[0].value, 0, 32); @@ -626,7 +626,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, if ((flash_sr & FLASH_ERROR) != 0) { LOG_ERROR("flash write failed, FLASH_SR = %08" PRIx32, flash_sr); /* Clear error + EOP flags but report errors */ - target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CCR), flash_sr); + stm32x_write_flash_reg(bank, FLASH_CCR, flash_sr); retval = ERROR_FAIL; } } @@ -639,6 +639,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); + destroy_reg_param(®_params[5]); return retval; } @@ -646,6 +647,7 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; uint32_t address = bank->base + offset; int retval, retval2; @@ -654,19 +656,19 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, return ERROR_TARGET_NOT_HALTED; } - if (offset % FLASH_BLOCK_SIZE) { - LOG_WARNING("offset 0x%" PRIx32 " breaks required 32-byte alignment", offset); - return ERROR_FLASH_DST_BREAKS_ALIGNMENT; - } + /* should be enforced via bank->write_start_alignment */ + assert(!(offset % stm32x_info->part_info->block_size)); + + /* should be enforced via bank->write_end_alignment */ + assert(!(count % stm32x_info->part_info->block_size)); retval = stm32x_unlock_reg(bank); if (retval != ERROR_OK) - return retval; + goto flash_lock; - uint32_t blocks_remaining = count / FLASH_BLOCK_SIZE; - uint32_t bytes_remaining = count % FLASH_BLOCK_SIZE; + uint32_t blocks_remaining = count / stm32x_info->part_info->block_size; - /* multiple words (32-bytes) to be programmed in block */ + /* multiple words (n * .block_size) to be programmed in block */ if (blocks_remaining) { retval = stm32x_write_block(bank, buffer, offset, blocks_remaining); if (retval != ERROR_OK) { @@ -676,8 +678,8 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); } } else { - buffer += blocks_remaining * FLASH_BLOCK_SIZE; - address += blocks_remaining * FLASH_BLOCK_SIZE; + buffer += blocks_remaining * stm32x_info->part_info->block_size; + address += blocks_remaining * stm32x_info->part_info->block_size; blocks_remaining = 0; } if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)) @@ -694,11 +696,12 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, 4. Wait for flash operations completion */ while (blocks_remaining > 0) { - retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64); + retval = stm32x_write_flash_reg(bank, FLASH_CR, + stm32x_info->part_info->compute_flash_cr(FLASH_PG | FLASH_PSIZE_64, 0)); if (retval != ERROR_OK) goto flash_lock; - retval = target_write_buffer(target, address, FLASH_BLOCK_SIZE, buffer); + retval = target_write_buffer(target, address, stm32x_info->part_info->block_size, buffer); if (retval != ERROR_OK) goto flash_lock; @@ -706,49 +709,17 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, if (retval != ERROR_OK) goto flash_lock; - buffer += FLASH_BLOCK_SIZE; - address += FLASH_BLOCK_SIZE; + buffer += stm32x_info->part_info->block_size; + address += stm32x_info->part_info->block_size; blocks_remaining--; } - if (bytes_remaining) { - retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64); - if (retval != ERROR_OK) - goto flash_lock; - - retval = target_write_buffer(target, address, bytes_remaining, buffer); - if (retval != ERROR_OK) - goto flash_lock; - - /* Force Write buffer of FLASH_BLOCK_SIZE = 32 bytes */ - retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64 | FLASH_FW); - if (retval != ERROR_OK) - goto flash_lock; - - retval = stm32x_wait_flash_op_queue(bank, FLASH_WRITE_TIMEOUT); - if (retval != ERROR_OK) - goto flash_lock; - } - flash_lock: retval2 = stm32x_lock_reg(bank); if (retval2 != ERROR_OK) LOG_ERROR("error during the lock of flash"); - if (retval == ERROR_OK) - retval = retval2; - - return retval; -} - -static void setup_sector(struct flash_bank *bank, int start, int num, int size) -{ - for (int i = start; i < (start + num) ; i++) { - assert(i < bank->num_sectors); - bank->sectors[i].offset = bank->size; - bank->sectors[i].size = size; - bank->size += bank->sectors[i].size; - } + return (retval == ERROR_OK) ? retval2 : retval; } static int stm32x_read_id_code(struct flash_bank *bank, uint32_t *id) @@ -764,13 +735,10 @@ static int stm32x_probe(struct flash_bank *bank) { struct target *target = bank->target; struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; - int i; uint16_t flash_size_in_kb; uint32_t device_id; - uint32_t base_address = FLASH_BANK0_ADDRESS; - uint32_t second_bank_base; - stm32x_info->probed = 0; + stm32x_info->probed = false; stm32x_info->part_info = NULL; int retval = stm32x_read_id_code(bank, &stm32x_info->idcode); @@ -792,44 +760,77 @@ static int stm32x_probe(struct flash_bank *bank) LOG_INFO("Device: %s", stm32x_info->part_info->device_str); } - /* update the address of controller from data base */ - stm32x_info->flash_base = stm32x_info->part_info->flash_base; + /* update the address of controller */ + if (bank->base == FLASH_BANK0_ADDRESS) + stm32x_info->flash_regs_base = FLASH_REG_BASE_B0; + else if (bank->base == FLASH_BANK1_ADDRESS) + stm32x_info->flash_regs_base = FLASH_REG_BASE_B1; + else { + LOG_WARNING("Flash register base not defined for bank %d", bank->bank_number); + return ERROR_FAIL; + } + LOG_DEBUG("flash_regs_base: 0x%" PRIx32, stm32x_info->flash_regs_base); /* get flash size from target */ - retval = target_read_u16(target, stm32x_info->part_info->fsize_base, &flash_size_in_kb); + retval = target_read_u16(target, stm32x_info->part_info->fsize_addr, &flash_size_in_kb); if (retval != ERROR_OK) { /* read error when device has invalid value, set max flash size */ flash_size_in_kb = stm32x_info->part_info->max_flash_size_kb; } else LOG_INFO("flash size probed value %d", flash_size_in_kb); - /* Lower flash size devices are single bank */ - if (stm32x_info->part_info->has_dual_bank && (flash_size_in_kb > stm32x_info->part_info->first_bank_size_kb)) { - /* Use the configured base address to determine if this is the first or second flash bank. - * Verify that the base address is reasonably correct and determine the flash bank size + + + + /* setup bank size */ + const uint32_t bank1_base = FLASH_BANK0_ADDRESS; + const uint32_t bank2_base = bank1_base + stm32x_info->part_info->max_bank_size_kb * 1024; + bool has_dual_bank = stm32x_info->part_info->has_dual_bank; + + switch (device_id) { + case 0x450: + case 0x480: + /* For STM32H74x/75x and STM32H7Ax/Bx + * - STM32H7xxxI devices contains dual bank, 1 Mbyte each + * - STM32H7xxxG devices contains dual bank, 512 Kbyte each + * - STM32H7xxxB devices contains single bank, 128 Kbyte + * - the second bank starts always from 0x08100000 */ - second_bank_base = base_address + stm32x_info->part_info->first_bank_size_kb * 1024; - if (bank->base == second_bank_base) { - /* This is the second bank */ - base_address = second_bank_base; - flash_size_in_kb = flash_size_in_kb - stm32x_info->part_info->first_bank_size_kb; - /* bank1 also uses a register offset */ - stm32x_info->flash_base = FLASH_REG_BASE_B1; - } else if (bank->base == base_address) { - /* This is the first bank */ - flash_size_in_kb = stm32x_info->part_info->first_bank_size_kb; - } else { - LOG_WARNING("STM32H flash bank base address config is incorrect. " - TARGET_ADDR_FMT " but should rather be 0x%" PRIx32 " or 0x%" PRIx32, - bank->base, base_address, second_bank_base); + if (flash_size_in_kb == 128) + has_dual_bank = false; + else + /* flash size is 2M or 1M */ + flash_size_in_kb /= 2; + break; + default: + LOG_ERROR("unsupported device"); + return ERROR_FAIL; + } + + if (has_dual_bank) { + LOG_INFO("STM32H7 flash has dual banks"); + if (bank->base != bank1_base && bank->base != bank2_base) { + LOG_ERROR("STM32H7 flash bank base address config is incorrect. " + TARGET_ADDR_FMT " but should rather be 0x%" PRIx32 " or 0x%" PRIx32, + bank->base, bank1_base, bank2_base); return ERROR_FAIL; } - LOG_INFO("STM32H flash has dual banks. Bank (%d) size is %dkb, base address is 0x%" PRIx32, - bank->bank_number, flash_size_in_kb, base_address); } else { - LOG_INFO("STM32H flash size is %dkb, base address is 0x%" PRIx32, flash_size_in_kb, base_address); + LOG_INFO("STM32H7 flash has a single bank"); + if (bank->base == bank2_base) { + LOG_ERROR("this device has a single bank only"); + return ERROR_FAIL; + } else if (bank->base != bank1_base) { + LOG_ERROR("STM32H7 flash bank base address config is incorrect. " + TARGET_ADDR_FMT " but should be 0x%" PRIx32, + bank->base, bank1_base); + return ERROR_FAIL; + } } + LOG_INFO("Bank (%d) size is %d kb, base address is 0x%" PRIx32, + bank->bank_number, flash_size_in_kb, (uint32_t) bank->base); + /* if the user sets the size manually then ignore the probed value * this allows us to work around devices that have an invalid flash size register value */ if (stm32x_info->user_bank_size) { @@ -842,33 +843,41 @@ static int stm32x_probe(struct flash_bank *bank) /* did we assign flash size? */ assert(flash_size_in_kb != 0xffff); + bank->size = flash_size_in_kb * 1024; + bank->write_start_alignment = stm32x_info->part_info->block_size; + bank->write_end_alignment = stm32x_info->part_info->block_size; - /* calculate numbers of pages */ - int num_pages = flash_size_in_kb / stm32x_info->part_info->page_size; - - /* check that calculation result makes sense */ - assert(num_pages > 0); + /* setup sectors */ + bank->num_sectors = flash_size_in_kb / stm32x_info->part_info->page_size_kb; + assert(bank->num_sectors > 0); - if (bank->sectors) { + if (bank->sectors) free(bank->sectors); - bank->sectors = NULL; - } - bank->base = base_address; - bank->num_sectors = num_pages; - bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); + bank->sectors = alloc_block_array(0, stm32x_info->part_info->page_size_kb * 1024, + bank->num_sectors); + if (bank->sectors == NULL) { LOG_ERROR("failed to allocate bank sectors"); return ERROR_FAIL; } - bank->size = 0; - /* fixed memory */ - setup_sector(bank, 0, num_pages, stm32x_info->part_info->page_size * 1024); + /* setup protection blocks */ + const uint32_t wpsn = stm32x_info->part_info->wps_group_size; + assert(bank->num_sectors % wpsn == 0); - for (i = 0; i < num_pages; i++) { - bank->sectors[i].is_erased = -1; - bank->sectors[i].is_protected = 0; + bank->num_prot_blocks = bank->num_sectors / wpsn; + assert(bank->num_prot_blocks > 0); + + if (bank->prot_blocks) + free(bank->prot_blocks); + + bank->prot_blocks = alloc_block_array(0, stm32x_info->part_info->page_size_kb * wpsn * 1024, + bank->num_prot_blocks); + + if (bank->prot_blocks == NULL) { + LOG_ERROR("failed to allocate bank prot_block"); + return ERROR_FAIL; } stm32x_info->probed = 1; @@ -922,57 +931,52 @@ static int stm32x_get_info(struct flash_bank *bank, char *buf, int buf_size) return ERROR_OK; } -COMMAND_HANDLER(stm32x_handle_lock_command) +static int stm32x_set_rdp(struct flash_bank *bank, enum stm32h7x_opt_rdp new_rdp) { - struct target *target = NULL; - struct stm32h7x_flash_bank *stm32x_info = NULL; - - if (CMD_ARGC < 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - struct flash_bank *bank; - int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) - return retval; - - stm32x_info = bank->driver_priv; - target = bank->target; - - /* if we have a dual flash bank device then - * we need to perform option byte lock on bank0 only */ - if (stm32x_info->flash_base != FLASH_REG_BASE_B0) { - LOG_ERROR("Option Byte Lock Operation must use bank0"); - return ERROR_FLASH_OPERATION_FAILED; - } + struct target *target = bank->target; + uint32_t optsr, cur_rdp; + int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - if (stm32x_read_options(bank) != ERROR_OK) { - command_print(CMD, "%s failed to read options", - bank->driver->name); - return ERROR_OK; + retval = stm32x_read_flash_reg(bank, FLASH_OPTSR_PRG, &optsr); + + if (retval != ERROR_OK) { + LOG_DEBUG("unable to read FLASH_OPTSR_PRG register"); + return retval; } - /* set readout protection */ - stm32x_info->option_bytes.RDP = 0; - if (stm32x_write_options(bank) != ERROR_OK) { - command_print(CMD, "%s failed to lock device", - bank->driver->name); + /* get current RDP, and check if there is a change */ + cur_rdp = (optsr & OPT_RDP_MASK) >> OPT_RDP_POS; + if (new_rdp == cur_rdp) { + LOG_INFO("the requested RDP value is already programmed"); return ERROR_OK; } - command_print(CMD, "%s locked", bank->driver->name); - return ERROR_OK; + switch (new_rdp) { + case OPT_RDP_L0: + LOG_WARNING("unlocking the entire flash device"); + break; + case OPT_RDP_L1: + LOG_WARNING("locking the entire flash device"); + break; + case OPT_RDP_L2: + LOG_WARNING("locking the entire flash device, irreversible"); + break; + } + + /* apply new RDP */ + optsr = (optsr & ~OPT_RDP_MASK) | (new_rdp << OPT_RDP_POS); + + /* apply new option value */ + return stm32x_write_option(bank, FLASH_OPTSR_PRG, optsr); } -COMMAND_HANDLER(stm32x_handle_unlock_command) +COMMAND_HANDLER(stm32x_handle_lock_command) { - struct target *target = NULL; - struct stm32h7x_flash_bank *stm32x_info = NULL; - if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; @@ -981,43 +985,41 @@ COMMAND_HANDLER(stm32x_handle_unlock_command) if (ERROR_OK != retval) return retval; - stm32x_info = bank->driver_priv; - target = bank->target; + retval = stm32x_set_rdp(bank, OPT_RDP_L1); - /* if we have a dual flash bank device then - * we need to perform option byte unlock on bank0 only */ - if (stm32x_info->flash_base != FLASH_REG_BASE_B0) { - LOG_ERROR("Option Byte Unlock Operation must use bank0"); - return ERROR_FLASH_OPERATION_FAILED; - } + if (retval != ERROR_OK) + command_print(CMD, "%s failed to lock device", bank->driver->name); + else + command_print(CMD, "%s locked", bank->driver->name); - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } + return retval; +} - if (stm32x_read_options(bank) != ERROR_OK) { - command_print(CMD, "%s failed to read options", bank->driver->name); - return ERROR_OK; - } +COMMAND_HANDLER(stm32x_handle_unlock_command) +{ + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; - /* clear readout protection option byte - * this will also force a device unlock if set */ - stm32x_info->option_bytes.RDP = 0xAA; + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; - if (stm32x_write_options(bank) != ERROR_OK) { + retval = stm32x_set_rdp(bank, OPT_RDP_L0); + + if (retval != ERROR_OK) command_print(CMD, "%s failed to unlock device", bank->driver->name); - return ERROR_OK; - } - command_print(CMD, "%s unlocked.\n", bank->driver->name); + else + command_print(CMD, "%s unlocked", bank->driver->name); - return ERROR_OK; + return retval; } static int stm32x_mass_erase(struct flash_bank *bank) { - int retval; + int retval, retval2; struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -1026,34 +1028,33 @@ static int stm32x_mass_erase(struct flash_bank *bank) retval = stm32x_unlock_reg(bank); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* mass erase flash memory bank */ - retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_BER | FLASH_PSIZE_64); + retval = stm32x_write_flash_reg(bank, FLASH_CR, + stm32x_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64, 0)); if (retval != ERROR_OK) - return retval; + goto flash_lock; - retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), - FLASH_BER | FLASH_PSIZE_64 | FLASH_START); + retval = stm32x_write_flash_reg(bank, FLASH_CR, + stm32x_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64 | FLASH_START, 0)); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = stm32x_wait_flash_op_queue(bank, 30000); if (retval != ERROR_OK) - return retval; + goto flash_lock; - retval = stm32x_lock_reg(bank); - if (retval != ERROR_OK) { +flash_lock: + retval2 = stm32x_lock_reg(bank); + if (retval2 != ERROR_OK) LOG_ERROR("error during the lock of flash"); - return retval; - } - return ERROR_OK; + + return (retval == ERROR_OK) ? retval2 : retval; } COMMAND_HANDLER(stm32x_handle_mass_erase_command) { - int i; - if (CMD_ARGC < 1) { command_print(CMD, "stm32h7x mass_erase <bank>"); return ERROR_COMMAND_SYNTAX_ERROR; @@ -1067,7 +1068,7 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command) retval = stm32x_mass_erase(bank); if (retval == ERROR_OK) { /* set all sectors as erased */ - for (i = 0; i < bank->num_sectors; i++) + for (int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; command_print(CMD, "stm32h7x mass erase complete"); @@ -1078,6 +1079,53 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command) return retval; } +COMMAND_HANDLER(stm32x_handle_option_read_command) +{ + if (CMD_ARGC < 2) { + command_print(CMD, "stm32h7x option_read <bank> <option_reg offset>"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + uint32_t reg_offset, value; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset); + retval = stm32x_read_flash_reg(bank, reg_offset, &value); + if (ERROR_OK != retval) + return retval; + + command_print(CMD, "Option Register: <0x%" PRIx32 "> = 0x%" PRIx32 "", + stm32x_get_flash_reg(bank, reg_offset), value); + + return retval; +} + +COMMAND_HANDLER(stm32x_handle_option_write_command) +{ + if (CMD_ARGC < 3) { + command_print(CMD, "stm32h7x option_write <bank> <option_reg offset> <value> [mask]"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + uint32_t reg_offset, value, mask = 0xffffffff; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); + if (CMD_ARGC > 3) + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], mask); + + return stm32x_modify_option(bank, reg_offset, value, mask); +} + static const struct command_registration stm32x_exec_command_handlers[] = { { .name = "lock", @@ -1100,6 +1148,20 @@ static const struct command_registration stm32x_exec_command_handlers[] = { .usage = "bank_id", .help = "Erase entire flash device.", }, + { + .name = "option_read", + .handler = stm32x_handle_option_read_command, + .mode = COMMAND_EXEC, + .usage = "bank_id reg_offset", + .help = "Read and display device option bytes.", + }, + { + .name = "option_write", + .handler = stm32x_handle_option_write_command, + .mode = COMMAND_EXEC, + .usage = "bank_id reg_offset value [mask]", + .help = "Write device option bit fields with provided value.", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index f680542..94fcd32 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -1,7 +1,10 @@ /*************************************************************************** * Copyright (C) 2015 by Uwe Bonnes * * bon@elektron.ikp.physik.tu-darmstadt.de * - * + * * + * Copyright (C) 2019 by Tarek Bochkati for STMicroelectronics * + * tarek.bouchkati@gmail.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 * @@ -24,6 +27,8 @@ #include <helper/binarybuffer.h> #include <target/algorithm.h> #include <target/armv7m.h> +#include "bits.h" +#include "stm32l4x.h" /* STM32L4xxx series for reference. * @@ -47,91 +52,294 @@ * RM0394 devices have a single bank only. * * RM0432 devices have single and dual bank operating modes. - * The FLASH size is 1Mbyte or 2Mbyte. + * - for STM32L4R/Sxx the FLASH size is 2Mbyte or 1Mbyte. + * - for STM32L4P/Q5x the FLASH size is 1Mbyte or 512Kbyte. * Bank page (sector) size is 4Kbyte (dual mode) or 8Kbyte (single mode). * * Bank mode is controlled by two different bits in option bytes register. - * In 2M FLASH devices bit 22 (DBANK) controls Dual Bank mode. - * In 1M FLASH devices bit 21 (DB1M) controls Dual Bank mode. + * - for STM32L4R/Sxx + * In 2M FLASH devices bit 22 (DBANK) controls Dual Bank mode. + * In 1M FLASH devices bit 21 (DB1M) controls Dual Bank mode. + * - for STM32L4P5/Q5x + * In 1M FLASH devices bit 22 (DBANK) controls Dual Bank mode. + * In 512K FLASH devices bit 21 (DB512K) controls Dual Bank mode. + * + */ + +/* STM32WBxxx series for reference. + * + * RM0434 (STM32WB55) + * http://www.st.com/resource/en/reference_manual/dm00318631.pdf + * + * RM0471 (STM32WB50) + * http://www.st.com/resource/en/reference_manual/dm00622834.pdf + */ + +/* STM32WLxxx series for reference. + * + * RM0461 (STM32WLEx) + * http://www.st.com/resource/en/reference_manual/dm00530369.pdf + */ + +/* + * STM32G0xxx series for reference. + * + * RM0444 (STM32G0x1) + * http://www.st.com/resource/en/reference_manual/dm00371828.pdf + * + * RM0454 (STM32G0x0) + * http://www.st.com/resource/en/reference_manual/dm00463896.pdf + */ + +/* + * STM32G4xxx series for reference. + * + * RM0440 (STM32G43x/44x/47x/48x) + * http://www.st.com/resource/en/reference_manual/dm00355726.pdf + * + * Cat. 2 devices have single bank only, page size is 2kByte. + * + * Cat. 3 devices have single and dual bank operating modes, + * Page size is 2kByte (dual mode) or 4kByte (single mode). * + * Bank mode is controlled by bit 22 (DBANK) in option bytes register. + * Both banks are treated as a single OpenOCD bank. */ /* Erase time can be as high as 25ms, 10x this and assume it's toast... */ #define FLASH_ERASE_TIMEOUT 250 -#define STM32_FLASH_BASE 0x40022000 -#define STM32_FLASH_ACR 0x40022000 -#define STM32_FLASH_KEYR 0x40022008 -#define STM32_FLASH_OPTKEYR 0x4002200c -#define STM32_FLASH_SR 0x40022010 -#define STM32_FLASH_CR 0x40022014 -#define STM32_FLASH_OPTR 0x40022020 -#define STM32_FLASH_WRP1AR 0x4002202c -#define STM32_FLASH_WRP1BR 0x40022030 -#define STM32_FLASH_WRP2AR 0x4002204c -#define STM32_FLASH_WRP2BR 0x40022050 - -/* FLASH_CR register bits */ - -#define FLASH_PG (1 << 0) -#define FLASH_PER (1 << 1) -#define FLASH_MER1 (1 << 2) -#define FLASH_PAGE_SHIFT 3 -#define FLASH_CR_BKER (1 << 11) -#define FLASH_MER2 (1 << 15) -#define FLASH_STRT (1 << 16) -#define FLASH_OPTSTRT (1 << 17) -#define FLASH_EOPIE (1 << 24) -#define FLASH_ERRIE (1 << 25) -#define FLASH_OBLLAUNCH (1 << 27) -#define FLASH_OPTLOCK (1 << 30) -#define FLASH_LOCK (1 << 31) - -/* FLASH_SR register bits */ - -#define FLASH_BSY (1 << 16) -/* Fast programming not used => related errors not used*/ -#define FLASH_PGSERR (1 << 7) /* Programming sequence error */ -#define FLASH_SIZERR (1 << 6) /* Size error */ -#define FLASH_PGAERR (1 << 5) /* Programming alignment error */ -#define FLASH_WRPERR (1 << 4) /* Write protection error */ -#define FLASH_PROGERR (1 << 3) /* Programming error */ -#define FLASH_OPERR (1 << 1) /* Operation error */ -#define FLASH_EOP (1 << 0) /* End of operation */ - -#define FLASH_ERROR (FLASH_PGSERR | FLASH_PGSERR | FLASH_PGAERR | FLASH_WRPERR | FLASH_OPERR) - -/* STM32_FLASH_OBR bit definitions (reading) */ - -#define OPT_DBANK_LE_1M (1 << 21) /* dual bank for devices up to 1M flash */ -#define OPT_DBANK_GE_2M (1 << 22) /* dual bank for devices with 2M flash */ - -/* register unlock keys */ - -#define KEY1 0x45670123 -#define KEY2 0xCDEF89AB - -/* option register unlock key */ -#define OPTKEY1 0x08192A3B -#define OPTKEY2 0x4C5D6E7F - -#define RDP_LEVEL_0 0xAA -#define RDP_LEVEL_1 0xBB -#define RDP_LEVEL_2 0xCC - - -/* other registers */ -#define DBGMCU_IDCODE 0xE0042000 -#define FLASH_SIZE_REG 0x1FFF75E0 +struct stm32l4_rev { + const uint16_t rev; + const char *str; +}; + +struct stm32l4_part_info { + uint16_t id; + const char *device_str; + const struct stm32l4_rev *revs; + const size_t num_revs; + const uint16_t max_flash_size_kb; + const bool has_dual_bank; + const uint32_t flash_regs_base; + const uint32_t fsize_addr; +}; struct stm32l4_flash_bank { - uint16_t bank2_start; - int probed; + bool probed; + uint32_t idcode; + int bank1_sectors; + bool dual_bank_mode; + int hole_sectors; + uint32_t user_bank_size; + uint32_t wrpxxr_mask; + const struct stm32l4_part_info *part_info; }; -/* flash bank stm32l4x <base> <size> 0 0 <target#> - */ +/* human readable list of families this drivers supports */ +static const char *device_families = "STM32L4/L4+/WB/WL/G4/G0"; + +static const struct stm32l4_rev stm32_415_revs[] = { + { 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" } +}; + +static const struct stm32l4_rev stm32_435_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, +}; + +static const struct stm32l4_rev stm32_460_revs[] = { + { 0x1000, "A/Z" } /* A and Z, no typo in RM! */, { 0x2000, "B" }, +}; + +static const struct stm32l4_rev stm32_461_revs[] = { + { 0x1000, "A" }, { 0x2000, "B" }, +}; + +static const struct stm32l4_rev stm32_462_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, +}; + +static const struct stm32l4_rev stm32_464_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, +}; + +static const struct stm32l4_rev stm32_466_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2000, "B" }, +}; + +static const struct stm32l4_rev stm32_468_revs[] = { + { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, +}; + +static const struct stm32l4_rev stm32_469_revs[] = { + { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, +}; + +static const struct stm32l4_rev stm32_470_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x100F, "W" }, +}; + +static const struct stm32l4_rev stm32_471_revs[] = { + { 0x1001, "Z" }, +}; + +static const struct stm32l4_rev stm32_495_revs[] = { + { 0x2001, "2.1" }, +}; + +static const struct stm32l4_rev stm32_496_revs[] = { + { 0x1000, "A" }, +}; + +static const struct stm32l4_rev stm32_497_revs[] = { + { 0x1000, "1.0" }, +}; + +static const struct stm32l4_part_info stm32l4_parts[] = { + { + .id = 0x415, + .revs = stm32_415_revs, + .num_revs = ARRAY_SIZE(stm32_415_revs), + .device_str = "STM32L47/L48xx", + .max_flash_size_kb = 1024, + .has_dual_bank = true, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x435, + .revs = stm32_435_revs, + .num_revs = ARRAY_SIZE(stm32_435_revs), + .device_str = "STM32L43/L44xx", + .max_flash_size_kb = 256, + .has_dual_bank = false, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x460, + .revs = stm32_460_revs, + .num_revs = ARRAY_SIZE(stm32_460_revs), + .device_str = "STM32G07/G08xx", + .max_flash_size_kb = 128, + .has_dual_bank = false, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x461, + .revs = stm32_461_revs, + .num_revs = ARRAY_SIZE(stm32_461_revs), + .device_str = "STM32L49/L4Axx", + .max_flash_size_kb = 1024, + .has_dual_bank = true, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x462, + .revs = stm32_462_revs, + .num_revs = ARRAY_SIZE(stm32_462_revs), + .device_str = "STM32L45/L46xx", + .max_flash_size_kb = 512, + .has_dual_bank = false, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x464, + .revs = stm32_464_revs, + .num_revs = ARRAY_SIZE(stm32_464_revs), + .device_str = "STM32L41/L42xx", + .max_flash_size_kb = 128, + .has_dual_bank = false, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x466, + .revs = stm32_466_revs, + .num_revs = ARRAY_SIZE(stm32_466_revs), + .device_str = "STM32G03/G04xx", + .max_flash_size_kb = 64, + .has_dual_bank = false, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x468, + .revs = stm32_468_revs, + .num_revs = ARRAY_SIZE(stm32_468_revs), + .device_str = "STM32G43/G44xx", + .max_flash_size_kb = 128, + .has_dual_bank = false, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x469, + .revs = stm32_469_revs, + .num_revs = ARRAY_SIZE(stm32_469_revs), + .device_str = "STM32G47/G48xx", + .max_flash_size_kb = 512, + .has_dual_bank = true, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x470, + .revs = stm32_470_revs, + .num_revs = ARRAY_SIZE(stm32_470_revs), + .device_str = "STM32L4R/L4Sxx", + .max_flash_size_kb = 2048, + .has_dual_bank = true, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x471, + .revs = stm32_471_revs, + .num_revs = ARRAY_SIZE(stm32_471_revs), + .device_str = "STM32L4P5/L4Q5x", + .max_flash_size_kb = 1024, + .has_dual_bank = true, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x495, + .revs = stm32_495_revs, + .num_revs = ARRAY_SIZE(stm32_495_revs), + .device_str = "STM32WB5x", + .max_flash_size_kb = 1024, + .has_dual_bank = false, + .flash_regs_base = 0x58004000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x496, + .revs = stm32_496_revs, + .num_revs = ARRAY_SIZE(stm32_496_revs), + .device_str = "STM32WB3x", + .max_flash_size_kb = 512, + .has_dual_bank = false, + .flash_regs_base = 0x58004000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x497, + .revs = stm32_497_revs, + .num_revs = ARRAY_SIZE(stm32_497_revs), + .device_str = "STM32WLEx", + .max_flash_size_kb = 256, + .has_dual_bank = false, + .flash_regs_base = 0x58004000, + .fsize_addr = 0x1FFF75E0, + }, +}; + +/* flash bank stm32l4x <base> <size> 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command) { struct stm32l4_flash_bank *stm32l4_info; @@ -144,32 +352,40 @@ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command) return ERROR_FAIL; /* Checkme: What better error to use?*/ bank->driver_priv = stm32l4_info; - stm32l4_info->probed = 0; + /* The flash write must be aligned to a double word (8-bytes) boundary. + * Ask the flash infrastructure to ensure required alignment */ + bank->write_start_alignment = bank->write_end_alignment = 8; + + stm32l4_info->probed = false; + stm32l4_info->user_bank_size = bank->size; return ERROR_OK; } -static inline int stm32l4_get_flash_reg(struct flash_bank *bank, uint32_t reg) +static inline uint32_t stm32l4_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset) { - return reg; + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + return stm32l4_info->part_info->flash_regs_base + reg_offset; } -static inline int stm32l4_get_flash_status(struct flash_bank *bank, uint32_t *status) +static inline int stm32l4_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value) { - struct target *target = bank->target; - return target_read_u32( - target, stm32l4_get_flash_reg(bank, STM32_FLASH_SR), status); + return target_read_u32(bank->target, stm32l4_get_flash_reg(bank, reg_offset), value); +} + +static inline int stm32l4_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) +{ + return target_write_u32(bank->target, stm32l4_get_flash_reg(bank, reg_offset), value); } static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout) { - struct target *target = bank->target; uint32_t status; int retval = ERROR_OK; /* wait for busy to clear */ for (;;) { - retval = stm32l4_get_flash_status(bank, &status); + retval = stm32l4_read_flash_reg(bank, STM32_FLASH_SR, &status); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%" PRIx32 "", status); @@ -195,20 +411,20 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout) /* If this operation fails, we ignore it and report the original * retval */ - target_write_u32(target, stm32l4_get_flash_reg(bank, STM32_FLASH_SR), - status & FLASH_ERROR); + stm32l4_write_flash_reg(bank, STM32_FLASH_SR, status & FLASH_ERROR); } + return retval; } -static int stm32l4_unlock_reg(struct target *target) +static int stm32l4_unlock_reg(struct flash_bank *bank) { uint32_t ctrl; /* first check if not already unlocked * otherwise writing on STM32_FLASH_KEYR will fail */ - int retval = target_read_u32(target, STM32_FLASH_CR, &ctrl); + int retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; @@ -216,15 +432,15 @@ static int stm32l4_unlock_reg(struct target *target) return ERROR_OK; /* unlock flash registers */ - retval = target_write_u32(target, STM32_FLASH_KEYR, KEY1); + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_KEYR, KEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_KEYR, KEY2); + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_KEYR, KEY2); if (retval != ERROR_OK) return retval; - retval = target_read_u32(target, STM32_FLASH_CR, &ctrl); + retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; @@ -236,11 +452,11 @@ static int stm32l4_unlock_reg(struct target *target) return ERROR_OK; } -static int stm32l4_unlock_option_reg(struct target *target) +static int stm32l4_unlock_option_reg(struct flash_bank *bank) { uint32_t ctrl; - int retval = target_read_u32(target, STM32_FLASH_CR, &ctrl); + int retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; @@ -248,15 +464,15 @@ static int stm32l4_unlock_option_reg(struct target *target) return ERROR_OK; /* unlock option registers */ - retval = target_write_u32(target, STM32_FLASH_OPTKEYR, OPTKEY1); + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_OPTKEYR, OPTKEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_OPTKEYR, OPTKEY2); + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_OPTKEYR, OPTKEY2); if (retval != ERROR_OK) return retval; - retval = target_read_u32(target, STM32_FLASH_CR, &ctrl); + retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; @@ -268,66 +484,72 @@ static int stm32l4_unlock_option_reg(struct target *target) return ERROR_OK; } -static int stm32l4_read_option(struct flash_bank *bank, uint32_t address, uint32_t* value) -{ - struct target *target = bank->target; - return target_read_u32(target, address, value); -} - -static int stm32l4_write_option(struct flash_bank *bank, uint32_t address, uint32_t value, uint32_t mask) +static int stm32l4_write_option(struct flash_bank *bank, uint32_t reg_offset, + uint32_t value, uint32_t mask) { - struct target *target = bank->target; uint32_t optiondata; + int retval, retval2; - int retval = target_read_u32(target, address, &optiondata); + retval = stm32l4_read_flash_reg(bank, reg_offset, &optiondata); if (retval != ERROR_OK) return retval; - retval = stm32l4_unlock_reg(target); + retval = stm32l4_unlock_reg(bank); if (retval != ERROR_OK) - return retval; + goto err_lock; - retval = stm32l4_unlock_option_reg(target); + retval = stm32l4_unlock_option_reg(bank); if (retval != ERROR_OK) - return retval; + goto err_lock; optiondata = (optiondata & ~mask) | (value & mask); - retval = target_write_u32(target, address, optiondata); + retval = stm32l4_write_flash_reg(bank, reg_offset, optiondata); if (retval != ERROR_OK) - return retval; + goto err_lock; - retval = target_write_u32(target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OPTSTRT); + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_OPTSTRT); if (retval != ERROR_OK) - return retval; + goto err_lock; retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + +err_lock: + retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK | FLASH_OPTLOCK); + if (retval != ERROR_OK) return retval; - return retval; + return retval2; } static int stm32l4_protect_check(struct flash_bank *bank) { struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + uint32_t wrp1ar, wrp1br, wrp2ar, wrp2br; - stm32l4_read_option(bank, STM32_FLASH_WRP1AR, &wrp1ar); - stm32l4_read_option(bank, STM32_FLASH_WRP1BR, &wrp1br); - stm32l4_read_option(bank, STM32_FLASH_WRP2AR, &wrp2ar); - stm32l4_read_option(bank, STM32_FLASH_WRP2BR, &wrp2br); - - const uint8_t wrp1a_start = wrp1ar & 0xFF; - const uint8_t wrp1a_end = (wrp1ar >> 16) & 0xFF; - const uint8_t wrp1b_start = wrp1br & 0xFF; - const uint8_t wrp1b_end = (wrp1br >> 16) & 0xFF; - const uint8_t wrp2a_start = wrp2ar & 0xFF; - const uint8_t wrp2a_end = (wrp2ar >> 16) & 0xFF; - const uint8_t wrp2b_start = wrp2br & 0xFF; - const uint8_t wrp2b_end = (wrp2br >> 16) & 0xFF; + stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1AR, &wrp1ar); + stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1BR, &wrp1br); + if (stm32l4_info->part_info->has_dual_bank) { + stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2AR, &wrp2ar); + stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2BR, &wrp2br); + } else { + /* prevent unintialized errors */ + wrp2ar = 0; + wrp2br = 0; + } + + const uint8_t wrp1a_start = wrp1ar & stm32l4_info->wrpxxr_mask; + const uint8_t wrp1a_end = (wrp1ar >> 16) & stm32l4_info->wrpxxr_mask; + const uint8_t wrp1b_start = wrp1br & stm32l4_info->wrpxxr_mask; + const uint8_t wrp1b_end = (wrp1br >> 16) & stm32l4_info->wrpxxr_mask; + const uint8_t wrp2a_start = wrp2ar & stm32l4_info->wrpxxr_mask; + const uint8_t wrp2a_end = (wrp2ar >> 16) & stm32l4_info->wrpxxr_mask; + const uint8_t wrp2b_start = wrp2br & stm32l4_info->wrpxxr_mask; + const uint8_t wrp2b_end = (wrp2br >> 16) & stm32l4_info->wrpxxr_mask; for (int i = 0; i < bank->num_sectors; i++) { - if (i < stm32l4_info->bank2_start) { + if (i < stm32l4_info->bank1_sectors) { if (((i >= wrp1a_start) && (i <= wrp1a_end)) || ((i >= wrp1b_start) && @@ -336,8 +558,9 @@ static int stm32l4_protect_check(struct flash_bank *bank) else bank->sectors[i].is_protected = 0; } else { + assert(stm32l4_info->part_info->has_dual_bank == true); uint8_t snb; - snb = i - stm32l4_info->bank2_start; + snb = i - stm32l4_info->bank1_sectors; if (((snb >= wrp2a_start) && (snb <= wrp2a_end)) || ((snb >= wrp2b_start) && @@ -352,62 +575,60 @@ static int stm32l4_protect_check(struct flash_bank *bank) static int stm32l4_erase(struct flash_bank *bank, int first, int last) { - struct target *target = bank->target; + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; int i; + int retval, retval2; - assert(first < bank->num_sectors); - assert(last < bank->num_sectors); + assert((0 <= first) && (first <= last) && (last < bank->num_sectors)); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - int retval; - retval = stm32l4_unlock_reg(target); + retval = stm32l4_unlock_reg(bank); if (retval != ERROR_OK) - return retval; + goto err_lock; /* Sector Erase To erase a sector, follow the procedure below: 1. Check that no Flash memory operation is ongoing by - checking the BSY bit in the FLASH_SR register + checking the BSY bit in the FLASH_SR register 2. Set the PER bit and select the page and bank you wish to erase in the FLASH_CR register 3. Set the STRT bit in the FLASH_CR register 4. Wait for the BSY bit to be cleared */ - struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; for (i = first; i <= last; i++) { uint32_t erase_flags; erase_flags = FLASH_PER | FLASH_STRT; - if (i >= stm32l4_info->bank2_start) { + if (i >= stm32l4_info->bank1_sectors) { uint8_t snb; - snb = i - stm32l4_info->bank2_start; + snb = i - stm32l4_info->bank1_sectors; erase_flags |= snb << FLASH_PAGE_SHIFT | FLASH_CR_BKER; } else erase_flags |= i << FLASH_PAGE_SHIFT; - retval = target_write_u32(target, - stm32l4_get_flash_reg(bank, STM32_FLASH_CR), erase_flags); + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, erase_flags); if (retval != ERROR_OK) - return retval; + break; retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) - return retval; + break; bank->sectors[i].is_erased = 1; } - retval = target_write_u32( - target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); +err_lock: + retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK); + if (retval != ERROR_OK) return retval; - return ERROR_OK; + return retval2; } static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last) @@ -423,9 +644,9 @@ static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last int ret = ERROR_OK; /* Bank 2 */ uint32_t reg_value = 0xFF; /* Default to bank un-protected */ - if (last >= stm32l4_info->bank2_start) { + if (last >= stm32l4_info->bank1_sectors) { if (set == 1) { - uint8_t begin = first > stm32l4_info->bank2_start ? first : 0x00; + uint8_t begin = first > stm32l4_info->bank1_sectors ? first : 0x00; reg_value = ((last & 0xFF) << 16) | begin; } @@ -433,9 +654,9 @@ static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last } /* Bank 1 */ reg_value = 0xFF; /* Default to bank un-protected */ - if (first < stm32l4_info->bank2_start) { + if (first < stm32l4_info->bank1_sectors) { if (set == 1) { - uint8_t end = last >= stm32l4_info->bank2_start ? 0xFF : last; + uint8_t end = last >= stm32l4_info->bank1_sectors ? 0xFF : last; reg_value = (end << 16) | (first & 0xFF); } @@ -445,16 +666,16 @@ static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last return ret; } -/* Count is in halfwords */ +/* Count is in double-words */ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) + uint32_t offset, uint32_t count) { struct target *target = bank->target; - uint32_t buffer_size = 16384; + uint32_t buffer_size; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; - struct reg_param reg_params[5]; + struct reg_param reg_params[6]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; @@ -476,18 +697,19 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, return retval; } - /* memory buffer */ - while (target_alloc_working_area_try(target, buffer_size, &source) != - ERROR_OK) { - buffer_size /= 2; - if (buffer_size <= 256) { - /* we already allocated the writing code, but failed to get a - * buffer, free the algorithm */ - target_free_working_area(target, write_algorithm); - - LOG_WARNING("large enough working area not available, can't do block memory writes"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } + /* memory buffer, size *must* be multiple of dword plus one dword for rp and one for wp */ + buffer_size = target_get_working_area_avail(target) & ~(2 * sizeof(uint32_t) - 1); + if (buffer_size < 256) { + LOG_WARNING("large enough working area not available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } else if (buffer_size > 16384) { + /* probably won't benefit from more than 16k ... */ + buffer_size = 16384; + } + + if (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { + LOG_ERROR("allocating working area failed"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; @@ -497,17 +719,19 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (double word-64bit) */ - init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash base */ + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash status register */ + init_reg_param(®_params[5], "r5", 32, PARAM_OUT); /* flash control register */ buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[2].value, 0, 32, address); - buf_set_u32(reg_params[3].value, 0, 32, count / 4); - buf_set_u32(reg_params[4].value, 0, 32, STM32_FLASH_BASE); + buf_set_u32(reg_params[3].value, 0, 32, count); + buf_set_u32(reg_params[4].value, 0, 32, stm32l4_get_flash_reg(bank, STM32_FLASH_SR)); + buf_set_u32(reg_params[5].value, 0, 32, stm32l4_get_flash_reg(bank, STM32_FLASH_CR)); - retval = target_run_flash_async_algorithm(target, buffer, count, 2, + retval = target_run_flash_async_algorithm(target, buffer, count, 8, 0, NULL, - 5, reg_params, + ARRAY_SIZE(reg_params), reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); @@ -523,7 +747,7 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, if (error != 0) { LOG_ERROR("flash write failed = %08" PRIx32, error); /* Clear but report errors */ - target_write_u32(target, STM32_FLASH_SR, error); + stm32l4_write_flash_reg(bank, STM32_FLASH_SR, error); retval = ERROR_FAIL; } } @@ -536,195 +760,311 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); + destroy_reg_param(®_params[5]); return retval; } static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) + uint32_t offset, uint32_t count) { - struct target *target = bank->target; - int retval; + int retval = ERROR_OK, retval2; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - if (offset & 0x7) { - LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment", - offset); - return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + /* The flash write must be aligned to a double word (8-bytes) boundary. + * The flash infrastructure ensures it, do just a security check */ + assert(offset % 8 == 0); + assert(count % 8 == 0); + + /* STM32G4xxx Cat. 3 devices may have gaps between banks, check whether + * data to be written does not go into a gap: + * suppose buffer is fully contained in bank from sector 0 to sector + * num->sectors - 1 and sectors are ordered according to offset + */ + struct flash_sector *head = &bank->sectors[0]; + struct flash_sector *tail = &bank->sectors[bank->num_sectors - 1]; + + while ((head < tail) && (offset >= (head + 1)->offset)) { + /* buffer does not intersect head nor gap behind head */ + head++; + } + + while ((head < tail) && (offset + count <= (tail - 1)->offset + (tail - 1)->size)) { + /* buffer does not intersect tail nor gap before tail */ + --tail; } - if (count & 0x7) { - LOG_WARNING("Padding %d bytes to keep 8-byte write size", - count & 7); - count = (count + 7) & ~7; - /* This pads the write chunk with random bytes by overrunning the - * write buffer. Padding with the erased pattern 0xff is purely - * cosmetical, as 8-byte flash words are ECC secured and the first - * write will program the ECC bits. A second write would need - * to reprogramm these ECC bits. - * But this can only be done after erase! - */ + LOG_DEBUG("data: 0x%08" PRIx32 " - 0x%08" PRIx32 ", sectors: 0x%08" PRIx32 " - 0x%08" PRIx32, + offset, offset + count - 1, head->offset, tail->offset + tail->size - 1); + + /* Now check that there is no gap from head to tail, this should work + * even for multiple or non-symmetric gaps + */ + while (head < tail) { + if (head->offset + head->size != (head + 1)->offset) { + LOG_ERROR("write into gap from " TARGET_ADDR_FMT " to " TARGET_ADDR_FMT, + bank->base + head->offset + head->size, + bank->base + (head + 1)->offset - 1); + retval = ERROR_FLASH_DST_OUT_OF_BANK; + } + head++; } - retval = stm32l4_unlock_reg(target); if (retval != ERROR_OK) return retval; - /* Only full double words (8-byte) can be programmed*/ - retval = stm32l4_write_block(bank, buffer, offset, count / 2); + retval = stm32l4_unlock_reg(bank); + if (retval != ERROR_OK) + goto err_lock; + + retval = stm32l4_write_block(bank, buffer, offset, count / 8); + +err_lock: + retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK); + if (retval != ERROR_OK) { - LOG_WARNING("block write failed"); + LOG_ERROR("block write failed"); return retval; + } + return retval2; +} + +static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) +{ + int retval; + + /* try stm32l4/l4+/wb/g4 id register first, then stm32g0 id register */ + retval = target_read_u32(bank->target, DBGMCU_IDCODE_L4_G4, id); + if ((retval != ERROR_OK) || ((*id & 0xfff) == 0) || ((*id & 0xfff) == 0xfff)) { + retval = target_read_u32(bank->target, DBGMCU_IDCODE_G0, id); + if ((retval != ERROR_OK) || ((*id & 0xfff) == 0) || ((*id & 0xfff) == 0xfff)) { + LOG_ERROR("can't get device id"); + return (retval == ERROR_OK) ? ERROR_FAIL : retval; } + } - LOG_WARNING("block write succeeded"); - return target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK); + return retval; } static int stm32l4_probe(struct flash_bank *bank) { struct target *target = bank->target; struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; - int i; - uint16_t flash_size_in_kb = 0xffff; - uint16_t max_flash_size_in_kb; + const struct stm32l4_part_info *part_info; + uint16_t flash_size_kb = 0xffff; uint32_t device_id; uint32_t options; - uint32_t base_address = 0x08000000; - stm32l4_info->probed = 0; + stm32l4_info->probed = false; - /* read stm32 device id register */ - int retval = target_read_u32(target, DBGMCU_IDCODE, &device_id); + /* read stm32 device id registers */ + int retval = stm32l4_read_idcode(bank, &stm32l4_info->idcode); if (retval != ERROR_OK) return retval; - LOG_INFO("device id = 0x%08" PRIx32 "", device_id); - /* set max flash size depending on family */ - switch (device_id & 0xfff) { - case 0x470: - max_flash_size_in_kb = 2048; - break; - case 0x461: - case 0x415: - max_flash_size_in_kb = 1024; - break; - case 0x462: - max_flash_size_in_kb = 512; - break; - case 0x435: - max_flash_size_in_kb = 256; - break; - default: - LOG_WARNING("Cannot identify target as an STM32L4 family device."); + device_id = stm32l4_info->idcode & 0xFFF; + + for (unsigned int n = 0; n < ARRAY_SIZE(stm32l4_parts); n++) { + if (device_id == stm32l4_parts[n].id) + stm32l4_info->part_info = &stm32l4_parts[n]; + } + + if (!stm32l4_info->part_info) { + LOG_WARNING("Cannot identify target as an %s family device.", device_families); return ERROR_FAIL; } + part_info = stm32l4_info->part_info; + + char device_info[1024]; + retval = bank->driver->info(bank, device_info, sizeof(device_info)); + if (retval != ERROR_OK) + return retval; + + LOG_INFO("device idcode = 0x%08" PRIx32 " (%s)", stm32l4_info->idcode, device_info); + /* get flash size from target. */ - retval = target_read_u16(target, FLASH_SIZE_REG, &flash_size_in_kb); + retval = target_read_u16(target, part_info->fsize_addr, &flash_size_kb); /* failed reading flash size or flash size invalid (early silicon), * default to max target family */ - if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) { + if (retval != ERROR_OK || flash_size_kb == 0xffff || flash_size_kb == 0 + || flash_size_kb > part_info->max_flash_size_kb) { LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming %dk flash", - max_flash_size_in_kb); - flash_size_in_kb = max_flash_size_in_kb; + part_info->max_flash_size_kb); + flash_size_kb = part_info->max_flash_size_kb; + } + + /* if the user sets the size manually then ignore the probed value + * this allows us to work around devices that have a invalid flash size register value */ + if (stm32l4_info->user_bank_size) { + LOG_WARNING("overriding size register by configured bank size - MAY CAUSE TROUBLE"); + flash_size_kb = stm32l4_info->user_bank_size / 1024; } - LOG_INFO("flash size = %dkbytes", flash_size_in_kb); + LOG_INFO("flash size = %dkbytes", flash_size_kb); /* did we assign a flash size? */ - assert((flash_size_in_kb != 0xffff) && flash_size_in_kb); - - /* get options for DUAL BANK. */ - retval = target_read_u32(target, STM32_FLASH_OPTR, &options); + assert((flash_size_kb != 0xffff) && flash_size_kb); + /* read flash option register */ + retval = stm32l4_read_flash_reg(bank, STM32_FLASH_OPTR, &options); if (retval != ERROR_OK) return retval; + stm32l4_info->bank1_sectors = 0; + stm32l4_info->hole_sectors = 0; + int num_pages = 0; - int page_size = 0; - - switch (device_id & 0xfff) { - case 0x470: - /* L4R/S have 1M or 2M FLASH and dual/single bank mode. - * Page size is 4K or 8K.*/ - if (flash_size_in_kb == 2048) { - stm32l4_info->bank2_start = 256; - if (options & OPT_DBANK_GE_2M) { - page_size = 4096; - num_pages = 512; - } else { - page_size = 8192; - num_pages = 256; - } - break; - } - if (flash_size_in_kb == 1024) { - stm32l4_info->bank2_start = 128; - if (options & OPT_DBANK_LE_1M) { - page_size = 4096; - num_pages = 256; - } else { - page_size = 8192; - num_pages = 128; - } - break; - } - /* Invalid FLASH size for this device. */ - LOG_WARNING("Invalid flash size for STM32L4+ family device."); - return ERROR_FAIL; - case 0x461: - case 0x415: - /* These are dual-bank devices, we need to check the OPT_DBANK_LE_1M bit here */ - page_size = 2048; - num_pages = flash_size_in_kb / 2; - /* check that calculation result makes sense */ - assert(num_pages > 0); - if ((flash_size_in_kb == 1024) || !(options & OPT_DBANK_LE_1M)) - stm32l4_info->bank2_start = 256; - else - stm32l4_info->bank2_start = num_pages / 2; - break; - case 0x462: - case 0x435: - default: - /* These are single-bank devices */ - page_size = 2048; - num_pages = flash_size_in_kb / 2; - /* check that calculation result makes sense */ - assert(num_pages > 0); - stm32l4_info->bank2_start = UINT16_MAX; - break; + int page_size_kb = 0; + + stm32l4_info->dual_bank_mode = false; + + switch (device_id) { + case 0x415: /* STM32L47/L48xx */ + case 0x461: /* STM32L49/L4Axx */ + /* if flash size is max (1M) the device is always dual bank + * 0x415: has variants with 512K + * 0x461: has variants with 512 and 256 + * for these variants: + * if DUAL_BANK = 0 -> single bank + * else -> dual bank without gap + * note: the page size is invariant + */ + page_size_kb = 2; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + + /* check DUAL_BANK bit[21] if the flash is less than 1M */ + if (flash_size_kb == 1024 || (options & BIT(21))) { + stm32l4_info->dual_bank_mode = true; + stm32l4_info->bank1_sectors = num_pages / 2; + } + break; + case 0x435: /* STM32L43/L44xx */ + case 0x460: /* STM32G07/G08xx */ + case 0x462: /* STM32L45/L46xx */ + case 0x464: /* STM32L41/L42xx */ + case 0x466: /* STM32G03/G04xx */ + case 0x468: /* STM32G43/G44xx */ + case 0x497: /* STM32WLEx */ + /* single bank flash */ + page_size_kb = 2; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + break; + case 0x469: /* STM32G47/G48xx */ + /* STM32G47/8 can be single/dual bank: + * if DUAL_BANK = 0 -> single bank + * else -> dual bank WITH gap + */ + page_size_kb = 4; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + if (options & BIT(22)) { + stm32l4_info->dual_bank_mode = true; + page_size_kb = 2; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages / 2; + + /* for devices with trimmed flash, there is a gap between both banks */ + stm32l4_info->hole_sectors = + (part_info->max_flash_size_kb - flash_size_kb) / (2 * page_size_kb); + } + break; + case 0x470: /* STM32L4R/L4Sxx */ + case 0x471: /* STM32L4P5/L4Q5x */ + /* STM32L4R/S can be single/dual bank: + * if size = 2M check DBANK bit(22) + * if size = 1M check DB1M bit(21) + * STM32L4P/Q can be single/dual bank + * if size = 1M check DBANK bit(22) + * if size = 512K check DB512K bit(21) + */ + page_size_kb = 8; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + const bool use_dbank_bit = flash_size_kb == part_info->max_flash_size_kb; + if ((use_dbank_bit && (options & BIT(22))) || + (!use_dbank_bit && (options & BIT(21)))) { + stm32l4_info->dual_bank_mode = true; + page_size_kb = 4; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages / 2; + } + break; + case 0x495: /* STM32WB5x */ + case 0x496: /* STM32WB3x */ + /* single bank flash */ + page_size_kb = 4; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + break; + default: + LOG_ERROR("unsupported device"); + return ERROR_FAIL; + } + + LOG_INFO("flash mode : %s-bank", stm32l4_info->dual_bank_mode ? "dual" : "single"); + + const int gap_size_kb = stm32l4_info->hole_sectors * page_size_kb; + + if (gap_size_kb != 0) { + LOG_INFO("gap detected from 0x%08" PRIx32 " to 0x%08" PRIx32, + STM32_FLASH_BANK_BASE + stm32l4_info->bank1_sectors + * page_size_kb * 1024, + STM32_FLASH_BANK_BASE + (stm32l4_info->bank1_sectors + * page_size_kb + gap_size_kb) * 1024 - 1); } - /* Release sector table if allocated. */ + /* number of significant bits in WRPxxR differs per device, + * always right adjusted, on some devices non-implemented + * bits read as '0', on others as '1' ... + * notably G4 Cat. 2 implement only 6 bits, contradicting the RM + */ + + /* use *max_flash_size* instead of actual size as the trimmed versions + * certainly use the same number of bits + * max_flash_size is always power of two, so max_pages too + */ + uint32_t max_pages = stm32l4_info->part_info->max_flash_size_kb / page_size_kb; + assert((max_pages & (max_pages - 1)) == 0); + + /* in dual bank mode number of pages is doubled, but extra bit is bank selection */ + stm32l4_info->wrpxxr_mask = ((max_pages >> (stm32l4_info->dual_bank_mode ? 1 : 0)) - 1); + assert((stm32l4_info->wrpxxr_mask & 0xFFFF0000) == 0); + LOG_DEBUG("WRPxxR mask 0x%04" PRIx16, (uint16_t)stm32l4_info->wrpxxr_mask); + if (bank->sectors) { free(bank->sectors); bank->sectors = NULL; } - /* Set bank configuration and construct sector table. */ - bank->base = base_address; - bank->size = num_pages * page_size; + bank->size = (flash_size_kb + gap_size_kb) * 1024; + bank->base = STM32_FLASH_BANK_BASE; bank->num_sectors = num_pages; - bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); - if (!bank->sectors) - return ERROR_FAIL; /* Checkme: What better error to use?*/ + bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + if (bank->sectors == NULL) { + LOG_ERROR("failed to allocate bank sectors"); + return ERROR_FAIL; + } - for (i = 0; i < num_pages; i++) { - bank->sectors[i].offset = i * page_size; - bank->sectors[i].size = page_size; + for (int i = 0; i < bank->num_sectors; i++) { + bank->sectors[i].offset = i * page_size_kb * 1024; + /* in dual bank configuration, if there is a gap between banks + * we fix up the sector offset to consider this gap */ + if (i >= stm32l4_info->bank1_sectors && stm32l4_info->hole_sectors) + bank->sectors[i].offset += gap_size_kb * 1024; + bank->sectors[i].size = page_size_kb * 1024; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } - stm32l4_info->probed = 1; - + stm32l4_info->probed = true; return ERROR_OK; } @@ -733,107 +1073,89 @@ static int stm32l4_auto_probe(struct flash_bank *bank) struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; if (stm32l4_info->probed) return ERROR_OK; + return stm32l4_probe(bank); } static int get_stm32l4_info(struct flash_bank *bank, char *buf, int buf_size) { - struct target *target = bank->target; - uint32_t dbgmcu_idcode; - - /* read stm32 device id register */ - int retval = target_read_u32(target, DBGMCU_IDCODE, &dbgmcu_idcode); - if (retval != ERROR_OK) - return retval; - - uint16_t device_id = dbgmcu_idcode & 0xfff; - uint8_t rev_id = dbgmcu_idcode >> 28; - uint8_t rev_minor = 0; - int i; - - for (i = 16; i < 28; i++) { - if (dbgmcu_idcode & (1 << i)) - rev_minor++; - else - break; - } - - const char *device_str; - - switch (device_id) { - case 0x470: - device_str = "STM32L4R/4Sxx"; - break; - - case 0x461: - device_str = "STM32L496/4A6"; - break; - - case 0x415: - device_str = "STM32L475/476/486"; - break; - - case 0x462: - device_str = "STM32L45x/46x"; - break; - - case 0x435: - device_str = "STM32L43x/44x"; - break; + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + const struct stm32l4_part_info *part_info = stm32l4_info->part_info; + + if (part_info) { + const char *rev_str = NULL; + uint16_t rev_id = stm32l4_info->idcode >> 16; + for (unsigned int i = 0; i < part_info->num_revs; i++) { + if (rev_id == part_info->revs[i].rev) { + rev_str = part_info->revs[i].str; + + if (rev_str != NULL) { + snprintf(buf, buf_size, "%s - Rev: %s%s", + part_info->device_str, rev_str, stm32l4_info->probed ? + (stm32l4_info->dual_bank_mode ? " dual-bank" : " single-bank") : ""); + return ERROR_OK; + } + } + } - default: - snprintf(buf, buf_size, "Cannot identify target as a STM32L4\n"); + snprintf(buf, buf_size, "%s - Rev: unknown (0x%04x)%s", + part_info->device_str, rev_id, stm32l4_info->probed ? + (stm32l4_info->dual_bank_mode ? " dual-bank" : " single-bank") : ""); + return ERROR_OK; + } else { + snprintf(buf, buf_size, "Cannot identify target as an %s device", device_families); return ERROR_FAIL; } - snprintf(buf, buf_size, "%s - Rev: %1d.%02d", - device_str, rev_id, rev_minor); - return ERROR_OK; } -static int stm32l4_mass_erase(struct flash_bank *bank, uint32_t action) +static int stm32l4_mass_erase(struct flash_bank *bank) { - int retval; + int retval, retval2; struct target *target = bank->target; + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + + uint32_t action = FLASH_MER1; + + if (stm32l4_info->part_info->has_dual_bank) + action |= FLASH_MER2; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - retval = stm32l4_unlock_reg(target); + retval = stm32l4_unlock_reg(bank); if (retval != ERROR_OK) - return retval; + goto err_lock; /* mass erase flash memory */ - retval = target_write_u32( - target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), action); + retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT / 10); if (retval != ERROR_OK) - return retval; - retval = target_write_u32( - target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), - action | FLASH_STRT); + goto err_lock; + + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, action); if (retval != ERROR_OK) - return retval; + goto err_lock; - retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, action | FLASH_STRT); if (retval != ERROR_OK) - return retval; + goto err_lock; + + retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + +err_lock: + retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK); - retval = target_write_u32( - target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); if (retval != ERROR_OK) return retval; - return ERROR_OK; + return retval2; } COMMAND_HANDLER(stm32l4_handle_mass_erase_command) { - int i; - uint32_t action; - if (CMD_ARGC < 1) { command_print(CMD, "stm32l4x mass_erase <STM32L4 bank>"); return ERROR_COMMAND_SYNTAX_ERROR; @@ -844,11 +1166,10 @@ COMMAND_HANDLER(stm32l4_handle_mass_erase_command) if (ERROR_OK != retval) return retval; - action = FLASH_MER1 | FLASH_MER2; - retval = stm32l4_mass_erase(bank, action); + retval = stm32l4_mass_erase(bank); if (retval == ERROR_OK) { /* set all sectors as erased */ - for (i = 0; i < bank->num_sectors; i++) + for (int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; command_print(CMD, "stm32l4x mass erase complete"); @@ -871,12 +1192,13 @@ COMMAND_HANDLER(stm32l4_handle_option_read_command) if (ERROR_OK != retval) return retval; - uint32_t reg_addr = STM32_FLASH_BASE; + uint32_t reg_offset, reg_addr; uint32_t value = 0; - reg_addr += strtoul(CMD_ARGV[1], NULL, 16); + reg_offset = strtoul(CMD_ARGV[1], NULL, 16); + reg_addr = stm32l4_get_flash_reg(bank, reg_offset); - retval = stm32l4_read_option(bank, reg_addr, &value); + retval = stm32l4_read_flash_reg(bank, reg_offset, &value); if (ERROR_OK != retval) return retval; @@ -897,11 +1219,11 @@ COMMAND_HANDLER(stm32l4_handle_option_write_command) if (ERROR_OK != retval) return retval; - uint32_t reg_addr = STM32_FLASH_BASE; + uint32_t reg_offset; uint32_t value = 0; uint32_t mask = 0xFFFFFFFF; - reg_addr += strtoul(CMD_ARGV[1], NULL, 16); + reg_offset = strtoul(CMD_ARGV[1], NULL, 16); value = strtoul(CMD_ARGV[2], NULL, 16); if (CMD_ARGC > 3) mask = strtoul(CMD_ARGV[3], NULL, 16); @@ -910,13 +1232,13 @@ COMMAND_HANDLER(stm32l4_handle_option_write_command) "INFO: a reset or power cycle is required " "for the new settings to take effect.", bank->driver->name); - retval = stm32l4_write_option(bank, reg_addr, value, mask); + retval = stm32l4_write_option(bank, reg_offset, value, mask); return retval; } COMMAND_HANDLER(stm32l4_handle_option_load_command) { - if (CMD_ARGC < 1) + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; @@ -924,20 +1246,27 @@ COMMAND_HANDLER(stm32l4_handle_option_load_command) if (ERROR_OK != retval) return retval; - struct target *target = bank->target; - - retval = stm32l4_unlock_reg(target); + retval = stm32l4_unlock_reg(bank); if (ERROR_OK != retval) return retval; - retval = stm32l4_unlock_option_reg(target); + retval = stm32l4_unlock_option_reg(bank); if (ERROR_OK != retval) return retval; - /* Write the OBLLAUNCH bit in CR -> Cause device "POR" and option bytes reload */ - retval = target_write_u32(target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OBLLAUNCH); + /* Set OBL_LAUNCH bit in CR -> system reset and option bytes reload, + * but the RMs explicitly do *NOT* list this as power-on reset cause, and: + * "Note: If the read protection is set while the debugger is still + * connected through JTAG/SWD, apply a POR (power-on reset) instead of a system reset." + */ + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_OBL_LAUNCH); + + command_print(CMD, "stm32l4x option load completed. Power-on reset might be required"); + + /* Need to re-probe after change */ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + stm32l4_info->probed = false; - command_print(CMD, "stm32l4x option load (POR) completed."); return retval; } diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h new file mode 100644 index 0000000..abd8010 --- /dev/null +++ b/src/flash/nor/stm32l4x.h @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (C) 2015 by Uwe Bonnes * + * bon@elektron.ikp.physik.tu-darmstadt.de * + * + * 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_STM32L4X +#define OPENOCD_FLASH_NOR_STM32L4X + +/* Flash registers offsets */ +#define STM32_FLASH_ACR 0x00 +#define STM32_FLASH_KEYR 0x08 +#define STM32_FLASH_OPTKEYR 0x0c +#define STM32_FLASH_SR 0x10 +#define STM32_FLASH_CR 0x14 +#define STM32_FLASH_OPTR 0x20 +#define STM32_FLASH_WRP1AR 0x2c +#define STM32_FLASH_WRP1BR 0x30 +#define STM32_FLASH_WRP2AR 0x4c +#define STM32_FLASH_WRP2BR 0x50 + +/* FLASH_CR register bits */ +#define FLASH_PG (1 << 0) +#define FLASH_PER (1 << 1) +#define FLASH_MER1 (1 << 2) +#define FLASH_PAGE_SHIFT 3 +#define FLASH_CR_BKER (1 << 11) +#define FLASH_MER2 (1 << 15) +#define FLASH_STRT (1 << 16) +#define FLASH_OPTSTRT (1 << 17) +#define FLASH_EOPIE (1 << 24) +#define FLASH_ERRIE (1 << 25) +#define FLASH_OBL_LAUNCH (1 << 27) +#define FLASH_OPTLOCK (1 << 30) +#define FLASH_LOCK (1 << 31) + +/* FLASH_SR register bits */ +#define FLASH_BSY (1 << 16) + +/* Fast programming not used => related errors not used*/ +#define FLASH_PGSERR (1 << 7) /* Programming sequence error */ +#define FLASH_SIZERR (1 << 6) /* Size error */ +#define FLASH_PGAERR (1 << 5) /* Programming alignment error */ +#define FLASH_WRPERR (1 << 4) /* Write protection error */ +#define FLASH_PROGERR (1 << 3) /* Programming error */ +#define FLASH_OPERR (1 << 1) /* Operation error */ +#define FLASH_EOP (1 << 0) /* End of operation */ +#define FLASH_ERROR (FLASH_PGSERR | FLASH_SIZERR | FLASH_PGAERR | \ + FLASH_WRPERR | FLASH_PROGERR | FLASH_OPERR) + +/* register unlock keys */ +#define KEY1 0x45670123 +#define KEY2 0xCDEF89AB + +/* option register unlock key */ +#define OPTKEY1 0x08192A3B +#define OPTKEY2 0x4C5D6E7F + +#define RDP_LEVEL_0 0xAA +#define RDP_LEVEL_1 0xBB +#define RDP_LEVEL_2 0xCC + +/* other registers */ +#define DBGMCU_IDCODE_G0 0x40015800 +#define DBGMCU_IDCODE_L4_G4 0xE0042000 +#define DBGMCU_IDCODE_L5 0xE0044000 + +#define STM32_FLASH_BANK_BASE 0x08000000 + +#endif diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index e6473f8..c3f9c72 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -128,7 +128,7 @@ struct stm32lx_part_info { }; struct stm32lx_flash_bank { - int probed; + bool probed; uint32_t idcode; uint32_t user_bank_size; uint32_t flash_base; @@ -297,7 +297,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command) bank->driver_priv = stm32lx_info; - stm32lx_info->probed = 0; + stm32lx_info->probed = false; stm32lx_info->user_bank_size = bank->size; /* the stm32l erased value is 0x00 */ @@ -308,8 +308,6 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command) COMMAND_HANDLER(stm32lx_handle_mass_erase_command) { - int i; - if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; @@ -321,7 +319,7 @@ COMMAND_HANDLER(stm32lx_handle_mass_erase_command) retval = stm32lx_mass_erase(bank); if (retval == ERROR_OK) { /* set all sectors as erased */ - for (i = 0; i < bank->num_sectors; i++) + for (int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; command_print(CMD, "stm32lx mass erase complete"); @@ -731,14 +729,13 @@ static int stm32lx_probe(struct flash_bank *bank) { struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; - int i; uint16_t flash_size_in_kb; uint32_t device_id; uint32_t base_address = FLASH_BANK0_ADDRESS; uint32_t second_bank_base; unsigned int n; - stm32lx_info->probed = 0; + stm32lx_info->probed = false; int retval = stm32lx_read_id_code(bank->target, &device_id); if (retval != ERROR_OK) @@ -756,7 +753,7 @@ static int stm32lx_probe(struct flash_bank *bank) } if (n == ARRAY_SIZE(stm32lx_parts)) { - LOG_WARNING("Cannot identify target as a STM32L family."); + LOG_ERROR("Cannot identify target as an STM32 L0 or L1 family device."); return ERROR_FAIL; } else { LOG_INFO("Device: %s", stm32lx_info->part_info.device_str); @@ -852,14 +849,14 @@ static int stm32lx_probe(struct flash_bank *bank) return ERROR_FAIL; } - for (i = 0; i < num_sectors; i++) { + for (int i = 0; i < num_sectors; i++) { bank->sectors[i].offset = i * FLASH_SECTOR_SIZE; bank->sectors[i].size = FLASH_SECTOR_SIZE; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } - stm32lx_info->probed = 1; + stm32lx_info->probed = true; return ERROR_OK; } diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index bd313a0..fb2053b 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -109,7 +109,7 @@ COMMAND_HANDLER(handle_flash_info_command) return retval; } if (retval == ERROR_FLASH_OPER_UNSUPPORTED) - LOG_WARNING("Flash protection check is not implemented."); + LOG_INFO("Flash protection check is not implemented."); command_print(CMD, "#%d : %s at " TARGET_ADDR_FMT ", size 0x%8.8" PRIx32 @@ -476,7 +476,7 @@ COMMAND_HANDLER(handle_flash_write_image_command) COMMAND_HANDLER(handle_flash_fill_command) { target_addr_t address; - uint32_t pattern; + uint64_t pattern; uint32_t count; struct target *target = get_current_target(CMD_CTX); unsigned i; @@ -487,7 +487,7 @@ COMMAND_HANDLER(handle_flash_fill_command) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], pattern); + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], pattern); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], count); struct flash_bank *bank; @@ -496,6 +496,9 @@ COMMAND_HANDLER(handle_flash_fill_command) return retval; switch (CMD_NAME[4]) { + case 'd': + wordsize = 8; + break; case 'w': wordsize = 4; break; @@ -509,6 +512,11 @@ COMMAND_HANDLER(handle_flash_fill_command) return ERROR_COMMAND_SYNTAX_ERROR; } + if ((wordsize < sizeof(pattern)) && (pattern >> (8 * wordsize) != 0)) { + command_print(CMD, "Fill pattern 0x%" PRIx64 " does not fit within %" PRIu32 "-byte word", pattern, wordsize); + return ERROR_FAIL; + } + if (count == 0) return ERROR_OK; @@ -541,6 +549,10 @@ COMMAND_HANDLER(handle_flash_fill_command) uint8_t *ptr = buffer + padding_at_start; switch (wordsize) { + case 8: + for (i = 0; i < count; i++, ptr += wordsize) + target_buffer_set_u64(target, ptr, pattern); + break; case 4: for (i = 0; i < count; i++, ptr += wordsize) target_buffer_set_u32(target, ptr, pattern); @@ -577,9 +589,12 @@ COMMAND_HANDLER(handle_flash_fill_command) goto done; for (i = 0, ptr = buffer; i < count; i++) { - uint32_t readback = 0; + uint64_t readback = 0; switch (wordsize) { + case 8: + readback = target_buffer_get_u64(target, ptr); + break; case 4: readback = target_buffer_get_u32(target, ptr); break; @@ -593,7 +608,7 @@ COMMAND_HANDLER(handle_flash_fill_command) if (readback != pattern) { LOG_ERROR( "Verification error address " TARGET_ADDR_FMT - ", read back 0x%02" PRIx32 ", expected 0x%02" PRIx32, + ", read back 0x%02" PRIx64 ", expected 0x%02" PRIx64, address + i * wordsize, readback, pattern); retval = ERROR_FAIL; goto done; @@ -613,6 +628,67 @@ done: return retval; } +COMMAND_HANDLER(handle_flash_md_command) +{ + int retval; + + if (CMD_ARGC < 1 || CMD_ARGC > 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + target_addr_t address; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); + + uint32_t count = 1; + if (CMD_ARGC == 2) + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], count); + + unsigned int wordsize; + switch (CMD_NAME[2]) { + case 'w': + wordsize = 4; + break; + case 'h': + wordsize = 2; + break; + case 'b': + wordsize = 1; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (count == 0) + return ERROR_OK; + + struct target *target = get_current_target(CMD_CTX); + struct flash_bank *bank; + retval = get_flash_bank_by_addr(target, address, true, &bank); + if (retval != ERROR_OK) + return retval; + + uint32_t offset = address - bank->base; + uint32_t sizebytes = count * wordsize; + if (offset + sizebytes > bank->size) { + command_print(CMD, "Cannot cross flash bank borders"); + return ERROR_FAIL; + } + + uint8_t *buffer = calloc(count, wordsize); + if (buffer == NULL) { + command_print(CMD, "No memory for flash read buffer"); + return ERROR_FAIL; + } + + retval = flash_driver_read(bank, buffer, offset, sizebytes); + if (retval == ERROR_OK) + target_handle_md_output(CMD, target, address, wordsize, count, buffer); + + free(buffer); + + return retval; +} + + COMMAND_HANDLER(handle_flash_write_bank_command) { uint32_t offset; @@ -952,7 +1028,7 @@ COMMAND_HANDLER(handle_flash_padded_value_command) COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], p->default_padded_value); - command_print(CMD, "Default padded value set to 0x%" PRIx8 " for flash bank %u", \ + command_print(CMD, "Default padded value set to 0x%" PRIx8 " for flash bank %u", p->default_padded_value, p->bank_number); return retval; @@ -1003,6 +1079,14 @@ static const struct command_registration flash_exec_command_handlers[] = { }, { + .name = "filld", + .handler = handle_flash_fill_command, + .mode = COMMAND_EXEC, + .usage = "address value n", + .help = "Fill n double-words with 64-bit value, starting at " + "word address. (No autoerase.)", + }, + { .name = "fillw", .handler = handle_flash_fill_command, .mode = COMMAND_EXEC, @@ -1027,6 +1111,27 @@ static const struct command_registration flash_exec_command_handlers[] = { "word address. (No autoerase.)", }, { + .name = "mdb", + .handler = handle_flash_md_command, + .mode = COMMAND_EXEC, + .usage = "address [count]", + .help = "Display bytes from flash.", + }, + { + .name = "mdh", + .handler = handle_flash_md_command, + .mode = COMMAND_EXEC, + .usage = "address [count]", + .help = "Display half-words from flash.", + }, + { + .name = "mdw", + .handler = handle_flash_md_command, + .mode = COMMAND_EXEC, + .usage = "address [count]", + .help = "Display words from flash.", + }, + { .name = "write_bank", .handler = handle_flash_write_bank_command, .mode = COMMAND_EXEC, diff --git a/src/flash/nor/tms470.c b/src/flash/nor/tms470.c index 90557b8..bc16aca 100644 --- a/src/flash/nor/tms470.c +++ b/src/flash/nor/tms470.c @@ -709,6 +709,7 @@ static int tms470_erase_sector(struct flash_bank *bank, int sector) * Select one or more bits in FMBSEA or FMBSEB to disable Level 1 * protection for the particular sector to be erased/written. */ + assert(sector >= 0); if (sector < 16) { target_read_u32(target, 0xFFE88008, &fmbsea); target_write_u32(target, 0xFFE88008, fmbsea | (1 << sector)); diff --git a/src/flash/nor/xcf.c b/src/flash/nor/xcf.c index a0c35c5..ba35c2c 100644 --- a/src/flash/nor/xcf.c +++ b/src/flash/nor/xcf.c @@ -625,7 +625,6 @@ static int xcf_probe(struct flash_bank *bank) default: LOG_ERROR("Unknown flash device ID 0x%X", id); return ERROR_FAIL; - break; } bank->sectors = malloc(bank->num_sectors * sizeof(struct flash_sector)); diff --git a/src/flash/startup.tcl b/src/flash/startup.tcl index ff053ae..aafb939 100644 --- a/src/flash/startup.tcl +++ b/src/flash/startup.tcl @@ -17,9 +17,12 @@ proc program_error {description exit} { proc program {filename args} { set exit 0 + set needsflash 1 foreach arg $args { - if {[string equal $arg "verify"]} { + if {[string equal $arg "preverify"]} { + set preverify 1 + } elseif {[string equal $arg "verify"]} { set verify 1 } elseif {[string equal $arg "reset"]} { set reset 1 @@ -30,6 +33,15 @@ proc program {filename args} { } } + # Set variables + set filename \{$filename\} + if {[info exists address]} { + set flash_args "$filename $address" + } else { + set flash_args "$filename" + } + + # make sure init is called if {[catch {init}] != 0} { program_error "** OpenOCD init failed **" 1 @@ -40,40 +52,46 @@ proc program {filename args} { program_error "** Unable to reset target **" $exit } - # start programming phase - echo "** Programming Started **" - set filename \{$filename\} - if {[info exists address]} { - set flash_args "$filename $address" - } else { - set flash_args "$filename" + # Check whether programming is needed + if {[info exists preverify]} { + echo "**pre-verifying**" + if {[catch {eval verify_image $flash_args}] == 0} { + echo "**Verified OK - No flashing**" + set needsflash 0 + } } - if {[catch {eval flash write_image erase $flash_args}] == 0} { - echo "** Programming Finished **" - if {[info exists verify]} { - # verify phase - echo "** Verify Started **" - if {[catch {eval verify_image $flash_args}] == 0} { - echo "** Verified OK **" - } else { - program_error "** Verify Failed **" $exit + # start programming phase + if {$needsflash == 1} { + echo "** Programming Started **" + + if {[catch {eval flash write_image erase $flash_args}] == 0} { + echo "** Programming Finished **" + if {[info exists verify]} { + # verify phase + echo "** Verify Started **" + if {[catch {eval verify_image $flash_args}] == 0} { + echo "** Verified OK **" + } else { + program_error "** Verify Failed **" $exit + } } + } else { + program_error "** Programming Failed **" $exit } + } - if {[info exists reset]} { - # reset target if requested - if {$exit == 1} { - # also disable target polling, we are shutting down anyway - poll off - } - echo "** Resetting Target **" - reset run + if {[info exists reset]} { + # reset target if requested + if {$exit == 1} { + # also disable target polling, we are shutting down anyway + poll off } - } else { - program_error "** Programming Failed **" $exit + echo "** Resetting Target **" + reset run } + if {$exit == 1} { shutdown } @@ -81,25 +99,25 @@ proc program {filename args} { } add_help_text program "write an image to flash, address is only required for binary images. verify, reset, exit are optional" -add_usage_text program "<filename> \[address\] \[verify\] \[reset\] \[exit\]" +add_usage_text program "<filename> \[address\] \[pre-verify\] \[verify\] \[reset\] \[exit\]" -# stm32f0x uses the same flash driver as the stm32f1x -# this alias enables the use of either name. -proc stm32f0x args { - eval stm32f1x $args -} +# stm32[f0x|f3x] uses the same flash driver as the stm32f1x +proc stm32f0x args { eval stm32f1x $args } +proc stm32f3x args { eval stm32f1x $args } -# stm32f3x uses the same flash driver as the stm32f1x -# this alias enables the use of either name. -proc stm32f3x args { - eval stm32f1x $args -} +# stm32[f4x|f7x] uses the same flash driver as the stm32f2x +proc stm32f4x args { eval stm32f2x $args } +proc stm32f7x args { eval stm32f2x $args } -# stm32f4x uses the same flash driver as the stm32f2x -# this alias enables the use of either name. -proc stm32f4x args { - eval stm32f2x $args -} +# stm32lx driver supports both STM32 L0 and L1 devices +proc stm32l0x args { eval stm32lx $args } +proc stm32l1x args { eval stm32lx $args } + +# stm32[g0|g4|wb|wl] uses the same flash driver as the stm32l4x +proc stm32g0x args { eval stm32l4x $args } +proc stm32g4x args { eval stm32l4x $args } +proc stm32wbx args { eval stm32l4x $args } +proc stm32wlx args { eval stm32l4x $args } # ease migration to updated flash driver proc stm32x args { diff --git a/src/helper/binarybuffer.h b/src/helper/binarybuffer.h index 7ac221e..3f2481d 100644 --- a/src/helper/binarybuffer.h +++ b/src/helper/binarybuffer.h @@ -33,6 +33,7 @@ * using the bits in @c value. This routine fast-paths writes * of little-endian, byte-aligned, 32-bit words. * @param _buffer The buffer whose bits will be set. + * Do not use uninitialized buffer or clang static analyzer emits a warning. * @param first The bit offset in @c _buffer to start writing (0-31). * @param num The number of bits from @c value to copy (1-32). * @param value Up to 32 bits that will be copied to _buffer. @@ -62,6 +63,7 @@ static inline void buf_set_u32(uint8_t *_buffer, * using the bits in @c value. This routine fast-paths writes * of little-endian, byte-aligned, 64-bit words. * @param _buffer The buffer whose bits will be set. + * Do not use uninitialized buffer or clang static analyzer emits a warning. * @param first The bit offset in @c _buffer to start writing (0-63). * @param num The number of bits from @c value to copy (1-64). * @param value Up to 64 bits that will be copied to _buffer. diff --git a/src/helper/command.c b/src/helper/command.c index d969933..271e7b9 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -52,6 +52,10 @@ struct log_capture_state { Jim_Obj *output; }; +static int unregister_command(struct command_context *context, + struct command *parent, const char *name); +static char *command_name(struct command *c, char delim); + static void tcl_output(void *privData, const char *file, unsigned line, const char *function, const char *string) { @@ -126,13 +130,12 @@ extern struct command_context *global_cmd_ctx; /* dump a single line to the log for the command. * Do nothing in case we are not at debug level 3 */ -void script_debug(Jim_Interp *interp, const char *name, - unsigned argc, Jim_Obj * const *argv) +void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const *argv) { if (debug_level < LOG_LVL_DEBUG) return; - char *dbg = alloc_printf("command - %s", name); + char *dbg = alloc_printf("command -"); for (unsigned i = 0; i < argc; i++) { int len; const char *w = Jim_GetString(argv[i], &len); @@ -213,7 +216,7 @@ static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv) struct command *c = interp->cmdPrivData; assert(c); - script_debug(interp, c->name, argc, argv); + script_debug(interp, argc, argv); return script_command_run(interp, argc, argv, c); } @@ -243,11 +246,6 @@ struct command *command_find_in_context(struct command_context *cmd_ctx, { return command_find(cmd_ctx->commands, name); } -struct command *command_find_in_parent(struct command *parent, - const char *name) -{ - return command_find(parent->children, name); -} /** * Add the command into the linked list, sorted by name. @@ -333,7 +331,6 @@ static struct command *command_new(struct command_context *cmd_ctx, c->parent = parent; c->handler = cr->handler; c->jim_handler = cr->jim_handler; - c->jim_handler_data = cr->jim_handler_data; c->mode = cr->mode; command_add_child(command_list_for_parent(cmd_ctx, parent), c); @@ -360,7 +357,7 @@ static int register_command_handler(struct command_context *cmd_ctx, return retval; } -struct command *register_command(struct command_context *context, +static struct command *register_command(struct command_context *context, struct command *parent, const struct command_registration *cr) { if (!context || !cr->name) @@ -382,14 +379,14 @@ struct command *register_command(struct command_context *context, if (NULL == c) return NULL; - int retval = ERROR_OK; + int retval = JIM_OK; if (NULL != cr->jim_handler && NULL == parent) { retval = Jim_CreateCommand(context->interp, cr->name, - cr->jim_handler, cr->jim_handler_data, NULL); + cr->jim_handler, NULL, NULL); } else if (NULL != cr->handler || NULL != parent) retval = register_command_handler(context, command_root(c)); - if (ERROR_OK != retval) { + if (retval != JIM_OK) { unregister_command(context, parent, name); c = NULL; } @@ -442,7 +439,7 @@ int unregister_all_commands(struct command_context *context, return ERROR_OK; } -int unregister_command(struct command_context *context, +static int unregister_command(struct command_context *context, struct command *parent, const char *name) { if ((!context) || (!name)) @@ -550,7 +547,7 @@ static char *__command_name(struct command *c, char delim, unsigned extra) return name; } -char *command_name(struct command *c, char delim) +static char *command_name(struct command *c, char delim) { return __command_name(c, delim, 0); } @@ -1033,8 +1030,7 @@ static int run_usage(Jim_Interp *interp, int argc_valid, int argc, Jim_Obj * con static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - const char *cmd_name = Jim_GetString(argv[0], NULL); - script_debug(interp, cmd_name, argc, argv); + script_debug(interp, argc, argv); struct command_context *cmd_ctx = current_command_context(interp); struct command *c = cmd_ctx->commands; @@ -1220,9 +1216,9 @@ static const struct command_registration command_subcommand_handlers[] = { .mode = COMMAND_ANY, .jim_handler = jim_command_mode, .usage = "[command_name ...]", - .help = "Returns the command modes allowed by a command:" - "'any', 'config', or 'exec'. If no command is" - "specified, returns the current command mode. " + .help = "Returns the command modes allowed by a command: " + "'any', 'config', or 'exec'. If no command is " + "specified, returns the current command mode. " "Returns 'unknown' if an unknown command is given. " "Command can be multiple tokens.", }, @@ -1231,6 +1227,21 @@ static const struct command_registration command_subcommand_handlers[] = { static const struct command_registration command_builtin_handlers[] = { { + .name = "ocd_find", + .mode = COMMAND_ANY, + .jim_handler = jim_find, + .help = "find full path to file", + .usage = "file", + }, + { + .name = "capture", + .mode = COMMAND_ANY, + .jim_handler = jim_capture, + .help = "Capture progress output and return as tcl return value. If the " + "progress output was empty, return tcl return value.", + .usage = "command", + }, + { .name = "echo", .handler = jim_echo, .mode = COMMAND_ANY, @@ -1340,9 +1351,6 @@ struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp Jim_SetGlobalVariableStr(interp, "ocd_HOSTOS", Jim_NewStringObj(interp, HostOs, strlen(HostOs))); - Jim_CreateCommand(interp, "ocd_find", jim_find, NULL, NULL); - Jim_CreateCommand(interp, "capture", jim_capture, NULL, NULL); - register_commands(context, NULL, command_builtin_handlers); Jim_SetAssocData(interp, "context", NULL, context); diff --git a/src/helper/command.h b/src/helper/command.h index 733ba42..886bde8 100644 --- a/src/helper/command.h +++ b/src/helper/command.h @@ -195,19 +195,9 @@ struct command { struct command *next; }; -/** - * @param c The command to be named. - * @param delim The character to place between command names. - * @returns A malloc'd string containing the full command name, - * which may include one or more ancestor components. Multiple names - * are separated by single spaces. The caller must free() the string - * when done with it. - */ -char *command_name(struct command *c, char delim); - /* * Commands should be registered by filling in one or more of these - * structures and passing them to register_command(). + * structures and passing them to [un]register_commands(). * * A conventioal format should be used for help strings, to provide both * usage and basic information: @@ -226,7 +216,6 @@ struct command_registration { const char *name; command_handler_t handler; Jim_CmdProc *jim_handler; - void *jim_handler_data; enum command_mode mode; const char *help; /** a string listing the options and arguments, required or optional */ @@ -245,24 +234,6 @@ struct command_registration { #define COMMAND_REGISTRATION_DONE { .name = NULL, .chain = NULL } /** - * Register a command @c handler that can be called from scripts during - * the execution @c mode specified. - * - * If @c parent is non-NULL, the new command will be registered as a - * sub-command under it; otherwise, it will be available as a top-level - * command. - * - * @param cmd_ctx The command_context in which to register the command. - * @param parent Register this command as a child of this, or NULL to - * register a top-level command. - * @param rec A command_registration record that contains the desired - * command parameters. - * @returns The new command, if successful; otherwise, NULL. - */ -struct command *register_command(struct command_context *cmd_ctx, - struct command *parent, const struct command_registration *rec); - -/** * Register one or more commands in the specified context, as children * of @c parent (or top-level commends, if NULL). In a registration's * record contains a non-NULL @c chain member and name is NULL, the @@ -280,16 +251,6 @@ struct command *register_command(struct command_context *cmd_ctx, int register_commands(struct command_context *cmd_ctx, struct command *parent, const struct command_registration *cmds); - -/** - * Unregisters command @c name from the given context, @c cmd_ctx. - * @param cmd_ctx The context of the registered command. - * @param parent The parent of the given command, or NULL. - * @param name The name of the command to unregister. - * @returns ERROR_OK on success, or an error code. - */ -int unregister_command(struct command_context *cmd_ctx, - struct command *parent, const char *name); /** * Unregisters all commands from the specfied context. * @param cmd_ctx The context that will be cleared of registered commands. @@ -301,8 +262,6 @@ int unregister_all_commands(struct command_context *cmd_ctx, struct command *command_find_in_context(struct command_context *cmd_ctx, const char *name); -struct command *command_find_in_parent(struct command *parent, - const char *name); /** * Update the private command data field for a command and all descendents. @@ -449,7 +408,6 @@ COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label); #define COMMAND_PARSE_ENABLE(in, out) \ COMMAND_PARSE_BOOL(in, out, "enable", "disable") -void script_debug(Jim_Interp *interp, const char *cmd, - unsigned argc, Jim_Obj * const *argv); +void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const *argv); #endif /* OPENOCD_HELPER_COMMAND_H */ diff --git a/src/helper/ioutil.c b/src/helper/ioutil.c index d4f39e2..c103ce1 100644 --- a/src/helper/ioutil.c +++ b/src/helper/ioutil.c @@ -403,7 +403,7 @@ static int ioutil_Jim_Command_mac(Jim_Interp *interp, int argc, { if (strcmp("eth0", ifr->ifr_name) != 0) continue; - strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); + strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name) - 1); if (ioctl(SockFD, SIOCGIFHWADDR, &ifreq) < 0) { close(SockFD); return JIM_ERR; diff --git a/src/helper/log.c b/src/helper/log.c index d65430c..3112255 100644 --- a/src/helper/log.c +++ b/src/helper/log.c @@ -220,6 +220,15 @@ COMMAND_HANDLER(handle_debug_level_command) COMMAND_HANDLER(handle_log_output_command) { + if (CMD_ARGC == 0 || (CMD_ARGC == 1 && strcmp(CMD_ARGV[0], "default") == 0)) { + if (log_output != stderr && log_output != NULL) { + /* Close previous log file, if it was open and wasn't stderr. */ + fclose(log_output); + } + log_output = stderr; + LOG_DEBUG("set log_output to default"); + return ERROR_OK; + } if (CMD_ARGC == 1) { FILE *file = fopen(CMD_ARGV[0], "w"); if (file == NULL) { @@ -231,9 +240,11 @@ COMMAND_HANDLER(handle_log_output_command) fclose(log_output); } log_output = file; + LOG_DEBUG("set log_output to \"%s\"", CMD_ARGV[0]); + return ERROR_OK; } - return ERROR_OK; + return ERROR_COMMAND_SYNTAX_ERROR; } static const struct command_registration log_command_handlers[] = { @@ -242,7 +253,7 @@ static const struct command_registration log_command_handlers[] = { .handler = handle_log_output_command, .mode = COMMAND_ANY, .help = "redirect logging to a file (default: stderr)", - .usage = "file_name", + .usage = "[file_name | \"default\"]", }, { .name = "debug_level", @@ -390,25 +401,43 @@ char *alloc_printf(const char *format, ...) * fast when invoked more often than every 500ms. * */ -void keep_alive() +#define KEEP_ALIVE_KICK_TIME_MS 500 +#define KEEP_ALIVE_TIMEOUT_MS 1000 + +static void gdb_timeout_warning(int64_t delta_time) +{ + extern int gdb_actual_connections; + + if (gdb_actual_connections) + LOG_WARNING("keep_alive() was not invoked in the " + "%d ms timelimit. GDB alive packet not " + "sent! (%" PRId64 " ms). Workaround: increase " + "\"set remotetimeout\" in GDB", + KEEP_ALIVE_TIMEOUT_MS, + delta_time); + else + LOG_DEBUG("keep_alive() was not invoked in the " + "%d ms timelimit (%" PRId64 " ms). This may cause " + "trouble with GDB connections.", + KEEP_ALIVE_TIMEOUT_MS, + delta_time); +} + +void keep_alive(void) { current_time = timeval_ms(); - if (current_time-last_time > 1000) { - extern int gdb_actual_connections; - - if (gdb_actual_connections) - LOG_WARNING("keep_alive() was not invoked in the " - "1000ms timelimit. GDB alive packet not " - "sent! (%" PRId64 "). Workaround: increase " - "\"set remotetimeout\" in GDB", - current_time-last_time); - else - LOG_DEBUG("keep_alive() was not invoked in the " - "1000ms timelimit (%" PRId64 "). This may cause " - "trouble with GDB connections.", - current_time-last_time); + + int64_t delta_time = current_time - last_time; + + if (delta_time > KEEP_ALIVE_TIMEOUT_MS) { + last_time = current_time; + + gdb_timeout_warning(delta_time); } - if (current_time-last_time > 500) { + + if (delta_time > KEEP_ALIVE_KICK_TIME_MS) { + last_time = current_time; + /* this will keep the GDB connection alive */ LOG_USER_N("%s", ""); @@ -419,16 +448,20 @@ void keep_alive() * * These functions should be invoked at a well defined spot in server.c */ - - last_time = current_time; } } /* reset keep alive timer without sending message */ -void kept_alive() +void kept_alive(void) { current_time = timeval_ms(); + + int64_t delta_time = current_time - last_time; + last_time = current_time; + + if (delta_time > KEEP_ALIVE_TIMEOUT_MS) + gdb_timeout_warning(delta_time); } /* if we sleep for extended periods of time, we must invoke keep_alive() intermittantly */ @@ -454,3 +487,28 @@ void busy_sleep(uint64_t ms) */ } } + +/* Maximum size of socket error message retreived from operation system */ +#define MAX_SOCKET_ERR_MSG_LENGTH 256 + +/* Provide log message for the last socket error. + Uses errno on *nix and WSAGetLastError() on Windows */ +void log_socket_error(const char *socket_desc) +{ + int error_code; +#ifdef _WIN32 + error_code = WSAGetLastError(); + char error_message[MAX_SOCKET_ERR_MSG_LENGTH]; + error_message[0] = '\0'; + DWORD retval = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, 0, + error_message, MAX_SOCKET_ERR_MSG_LENGTH, NULL); + error_message[MAX_SOCKET_ERR_MSG_LENGTH - 1] = '\0'; + const bool have_message = (retval != 0) && (error_message[0] != '\0'); + LOG_ERROR("Error on socket '%s': WSAGetLastError==%d%s%s.", socket_desc, error_code, + (have_message ? ", message: " : ""), + (have_message ? error_message : "")); +#else + error_code = errno; + LOG_ERROR("Error on socket '%s': errno==%d, message: %s.", socket_desc, error_code, strerror(error_code)); +#endif +} diff --git a/src/helper/log.h b/src/helper/log.h index 43f6751..c165432 100644 --- a/src/helper/log.h +++ b/src/helper/log.h @@ -82,6 +82,8 @@ void kept_alive(void); void alive_sleep(uint64_t ms); void busy_sleep(uint64_t ms); +void log_socket_error(const char *socket_desc); + typedef void (*log_callback_fn)(void *priv, const char *file, unsigned line, const char *function, const char *string); @@ -95,7 +97,8 @@ int log_add_callback(log_callback_fn fn, void *priv); int log_remove_callback(log_callback_fn fn, void *priv); char *alloc_vprintf(const char *fmt, va_list ap); -char *alloc_printf(const char *fmt, ...); +char *alloc_printf(const char *fmt, ...) + __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 1, 2))); extern int debug_level; diff --git a/src/helper/startup.tcl b/src/helper/startup.tcl index 691e382..71f489d 100644 --- a/src/helper/startup.tcl +++ b/src/helper/startup.tcl @@ -29,4 +29,3 @@ add_help_text script "filename of OpenOCD script (tcl) to run" add_usage_text script "<file>" ######### - diff --git a/src/helper/types.h b/src/helper/types.h index 5e35c13..f3d5e04 100644 --- a/src/helper/types.h +++ b/src/helper/types.h @@ -126,17 +126,17 @@ static inline uint64_t le_to_h_u64(const uint8_t *buf) (uint64_t)buf[7] << 56); } -static inline uint32_t le_to_h_u32(const uint8_t* buf) +static inline uint32_t le_to_h_u32(const uint8_t *buf) { return (uint32_t)((uint32_t)buf[0] | (uint32_t)buf[1] << 8 | (uint32_t)buf[2] << 16 | (uint32_t)buf[3] << 24); } -static inline uint32_t le_to_h_u24(const uint8_t* buf) +static inline uint32_t le_to_h_u24(const uint8_t *buf) { return (uint32_t)((uint32_t)buf[0] | (uint32_t)buf[1] << 8 | (uint32_t)buf[2] << 16); } -static inline uint16_t le_to_h_u16(const uint8_t* buf) +static inline uint16_t le_to_h_u16(const uint8_t *buf) { return (uint16_t)((uint16_t)buf[0] | (uint16_t)buf[1] << 8); } @@ -153,17 +153,17 @@ static inline uint64_t be_to_h_u64(const uint8_t *buf) (uint64_t)buf[0] << 56); } -static inline uint32_t be_to_h_u32(const uint8_t* buf) +static inline uint32_t be_to_h_u32(const uint8_t *buf) { return (uint32_t)((uint32_t)buf[3] | (uint32_t)buf[2] << 8 | (uint32_t)buf[1] << 16 | (uint32_t)buf[0] << 24); } -static inline uint32_t be_to_h_u24(const uint8_t* buf) +static inline uint32_t be_to_h_u24(const uint8_t *buf) { return (uint32_t)((uint32_t)buf[2] | (uint32_t)buf[1] << 8 | (uint32_t)buf[0] << 16); } -static inline uint16_t be_to_h_u16(const uint8_t* buf) +static inline uint16_t be_to_h_u16(const uint8_t *buf) { return (uint16_t)((uint16_t)buf[1] | (uint16_t)buf[0] << 8); } @@ -192,7 +192,7 @@ static inline void h_u64_to_be(uint8_t *buf, int64_t val) buf[7] = (uint8_t) (val >> 0); } -static inline void h_u32_to_le(uint8_t* buf, int val) +static inline void h_u32_to_le(uint8_t *buf, int val) { buf[3] = (uint8_t) (val >> 24); buf[2] = (uint8_t) (val >> 16); @@ -200,7 +200,7 @@ static inline void h_u32_to_le(uint8_t* buf, int val) buf[0] = (uint8_t) (val >> 0); } -static inline void h_u32_to_be(uint8_t* buf, int val) +static inline void h_u32_to_be(uint8_t *buf, int val) { buf[0] = (uint8_t) (val >> 24); buf[1] = (uint8_t) (val >> 16); @@ -208,27 +208,27 @@ static inline void h_u32_to_be(uint8_t* buf, int val) buf[3] = (uint8_t) (val >> 0); } -static inline void h_u24_to_le(uint8_t* buf, int val) +static inline void h_u24_to_le(uint8_t *buf, int val) { buf[2] = (uint8_t) (val >> 16); buf[1] = (uint8_t) (val >> 8); buf[0] = (uint8_t) (val >> 0); } -static inline void h_u24_to_be(uint8_t* buf, int val) +static inline void h_u24_to_be(uint8_t *buf, int val) { buf[0] = (uint8_t) (val >> 16); buf[1] = (uint8_t) (val >> 8); buf[2] = (uint8_t) (val >> 0); } -static inline void h_u16_to_le(uint8_t* buf, int val) +static inline void h_u16_to_le(uint8_t *buf, int val) { buf[1] = (uint8_t) (val >> 8); buf[0] = (uint8_t) (val >> 0); } -static inline void h_u16_to_be(uint8_t* buf, int val) +static inline void h_u16_to_be(uint8_t *buf, int val) { buf[0] = (uint8_t) (val >> 8); buf[1] = (uint8_t) (val >> 0); @@ -349,7 +349,6 @@ typedef uint64_t uintmax_t; #endif -#if BUILD_TARGET64 typedef uint64_t target_addr_t; #define TARGET_ADDR_MAX UINT64_MAX #define TARGET_PRIdADDR PRId64 @@ -357,15 +356,6 @@ typedef uint64_t target_addr_t; #define TARGET_PRIoADDR PRIo64 #define TARGET_PRIxADDR PRIx64 #define TARGET_PRIXADDR PRIX64 -#else -typedef uint32_t target_addr_t; -#define TARGET_ADDR_MAX UINT32_MAX -#define TARGET_PRIdADDR PRId32 -#define TARGET_PRIuADDR PRIu32 -#define TARGET_PRIoADDR PRIo32 -#define TARGET_PRIxADDR PRIx32 -#define TARGET_PRIXADDR PRIX32 -#endif #define TARGET_ADDR_FMT "0x%8.8" TARGET_PRIxADDR #endif /* OPENOCD_HELPER_TYPES_H */ diff --git a/src/jtag/Makefile.am b/src/jtag/Makefile.am index a764863..b82914b 100644 --- a/src/jtag/Makefile.am +++ b/src/jtag/Makefile.am @@ -56,6 +56,7 @@ endif %D%/interface.c \ %D%/interfaces.c \ %D%/tcl.c \ + %D%/swim.c \ %D%/commands.h \ %D%/driver.h \ %D%/interface.h \ @@ -65,6 +66,7 @@ endif %D%/minidriver/minidriver_imp.h \ %D%/minidummy/jtag_minidriver.h \ %D%/swd.h \ + %D%/swim.h \ %D%/tcl.h \ $(JTAG_SRCS) diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c index 29a9613..af75917 100644 --- a/src/jtag/adapter.c +++ b/src/jtag/adapter.c @@ -46,7 +46,7 @@ * Holds support for configuring debug adapters from TCl scripts. */ -extern struct jtag_interface *jtag_interface; +struct adapter_driver *adapter_driver; const char * const jtag_only[] = { "jtag", NULL }; static int jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj * const *argv) @@ -61,12 +61,12 @@ static int jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj * const *argv) Jim_WrongNumArgs(goi.interp, 1, goi.argv-1, "(no params)"); return JIM_ERR; } - const char *name = jtag_interface ? jtag_interface->name : NULL; + const char *name = adapter_driver ? adapter_driver->name : NULL; Jim_SetResultString(goi.interp, name ? : "undefined", -1); return JIM_OK; } -COMMAND_HANDLER(interface_transport_command) +COMMAND_HANDLER(adapter_transports_command) { char **transports; int retval; @@ -85,26 +85,26 @@ COMMAND_HANDLER(interface_transport_command) return retval; } -COMMAND_HANDLER(handle_interface_list_command) +COMMAND_HANDLER(handle_adapter_list_command) { - if (strcmp(CMD_NAME, "interface_list") == 0 && CMD_ARGC > 0) + if (strcmp(CMD_NAME, "list") == 0 && CMD_ARGC > 0) return ERROR_COMMAND_SYNTAX_ERROR; - command_print(CMD, "The following debug interfaces are available:"); - for (unsigned i = 0; NULL != jtag_interfaces[i]; i++) { - const char *name = jtag_interfaces[i]->name; + command_print(CMD, "The following debug adapters are available:"); + for (unsigned i = 0; NULL != adapter_drivers[i]; i++) { + const char *name = adapter_drivers[i]->name; command_print(CMD, "%u: %s", i + 1, name); } return ERROR_OK; } -COMMAND_HANDLER(handle_interface_command) +COMMAND_HANDLER(handle_adapter_driver_command) { int retval; /* check whether the interface is already configured */ - if (jtag_interface) { + if (adapter_driver) { LOG_WARNING("Interface already configured, ignoring"); return ERROR_OK; } @@ -113,20 +113,20 @@ COMMAND_HANDLER(handle_interface_command) if (CMD_ARGC != 1 || CMD_ARGV[0][0] == '\0') return ERROR_COMMAND_SYNTAX_ERROR; - for (unsigned i = 0; NULL != jtag_interfaces[i]; i++) { - if (strcmp(CMD_ARGV[0], jtag_interfaces[i]->name) != 0) + for (unsigned i = 0; NULL != adapter_drivers[i]; i++) { + if (strcmp(CMD_ARGV[0], adapter_drivers[i]->name) != 0) continue; - if (NULL != jtag_interfaces[i]->commands) { + if (NULL != adapter_drivers[i]->commands) { retval = register_commands(CMD_CTX, NULL, - jtag_interfaces[i]->commands); + adapter_drivers[i]->commands); if (ERROR_OK != retval) return retval; } - jtag_interface = jtag_interfaces[i]; + adapter_driver = adapter_drivers[i]; - return allow_transports(CMD_CTX, jtag_interface->transports); + return allow_transports(CMD_CTX, adapter_driver->transports); } /* no valid interface was found (i.e. the configuration option, @@ -134,7 +134,7 @@ COMMAND_HANDLER(handle_interface_command) */ LOG_ERROR("The specified debug interface was not found (%s)", CMD_ARGV[0]); - CALL_COMMAND_HANDLER(handle_interface_list_command); + CALL_COMMAND_HANDLER(handle_adapter_list_command); return ERROR_JTAG_INVALID_INTERFACE; } @@ -355,7 +355,7 @@ next: return ERROR_OK; } -COMMAND_HANDLER(handle_adapter_nsrst_delay_command) +COMMAND_HANDLER(handle_adapter_srst_delay_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; @@ -365,11 +365,11 @@ COMMAND_HANDLER(handle_adapter_nsrst_delay_command) jtag_set_nsrst_delay(delay); } - command_print(CMD, "adapter_nsrst_delay: %u", jtag_get_nsrst_delay()); + command_print(CMD, "adapter srst delay: %u", jtag_get_nsrst_delay()); return ERROR_OK; } -COMMAND_HANDLER(handle_adapter_nsrst_assert_width_command) +COMMAND_HANDLER(handle_adapter_srst_pulse_width_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; @@ -379,11 +379,11 @@ COMMAND_HANDLER(handle_adapter_nsrst_assert_width_command) jtag_set_nsrst_assert_width(width); } - command_print(CMD, "adapter_nsrst_assert_width: %u", jtag_get_nsrst_assert_width()); + command_print(CMD, "adapter srst pulse_width: %u", jtag_get_nsrst_assert_width()); return ERROR_OK; } -COMMAND_HANDLER(handle_adapter_khz_command) +COMMAND_HANDLER(handle_adapter_speed_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; @@ -411,6 +411,92 @@ COMMAND_HANDLER(handle_adapter_khz_command) return retval; } +COMMAND_HANDLER(handle_adapter_reset_de_assert) +{ + enum values { + VALUE_UNDEFINED = -1, + VALUE_DEASSERT = 0, + VALUE_ASSERT = 1, + }; + enum values value; + enum values srst = VALUE_UNDEFINED; + enum values trst = VALUE_UNDEFINED; + enum reset_types jtag_reset_config = jtag_get_reset_config(); + char *signal; + + if (CMD_ARGC == 0) { + if (transport_is_jtag()) { + if (jtag_reset_config & RESET_HAS_TRST) + signal = jtag_get_trst() ? "asserted" : "deasserted"; + else + signal = "not present"; + command_print(CMD, "trst %s", signal); + } + + if (jtag_reset_config & RESET_HAS_SRST) + signal = jtag_get_srst() ? "asserted" : "deasserted"; + else + signal = "not present"; + command_print(CMD, "srst %s", signal); + + return ERROR_OK; + } + + if (CMD_ARGC != 1 && CMD_ARGC != 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + value = (strcmp(CMD_NAME, "assert") == 0) ? VALUE_ASSERT : VALUE_DEASSERT; + if (strcmp(CMD_ARGV[0], "srst") == 0) + srst = value; + else if (strcmp(CMD_ARGV[0], "trst") == 0) + trst = value; + else + return ERROR_COMMAND_SYNTAX_ERROR; + + if (CMD_ARGC == 3) { + if (strcmp(CMD_ARGV[1], "assert") == 0) + value = VALUE_ASSERT; + else if (strcmp(CMD_ARGV[1], "deassert") == 0) + value = VALUE_DEASSERT; + else + return ERROR_COMMAND_SYNTAX_ERROR; + + if (strcmp(CMD_ARGV[2], "srst") == 0 && srst == VALUE_UNDEFINED) + srst = value; + else if (strcmp(CMD_ARGV[2], "trst") == 0 && trst == VALUE_UNDEFINED) + trst = value; + else + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (trst == VALUE_UNDEFINED) { + if (transport_is_jtag()) + trst = jtag_get_trst() ? VALUE_ASSERT : VALUE_DEASSERT; + else + trst = VALUE_DEASSERT; /* unused, safe value */ + } + + if (srst == VALUE_UNDEFINED) { + if (jtag_reset_config & RESET_HAS_SRST) + srst = jtag_get_srst() ? VALUE_ASSERT : VALUE_DEASSERT; + else + srst = VALUE_DEASSERT; /* unused, safe value */ + } + + if (trst == VALUE_ASSERT && !transport_is_jtag()) { + LOG_ERROR("transport has no trst signal"); + return ERROR_FAIL; + } + + if (srst == VALUE_ASSERT && !(jtag_reset_config & RESET_HAS_SRST)) { + LOG_ERROR("adapter has no srst signal"); + return ERROR_FAIL; + } + + return adapter_resets((trst == VALUE_DEASSERT) ? TRST_DEASSERT : TRST_ASSERT, + (srst == VALUE_DEASSERT) ? SRST_DEASSERT : SRST_ASSERT); +} + #ifndef HAVE_JTAG_MINIDRIVER_H #ifdef HAVE_LIBUSB_GET_PORT_NUMBERS COMMAND_HANDLER(handle_usb_location_command) @@ -438,78 +524,103 @@ static const struct command_registration adapter_usb_command_handlers[] = { }; #endif /* MINIDRIVER */ -static const struct command_registration adapter_command_handlers[] = { -#ifndef HAVE_JTAG_MINIDRIVER_H +static const struct command_registration adapter_srst_command_handlers[] = { { - .name = "usb", + .name = "delay", + .handler = handle_adapter_srst_delay_command, .mode = COMMAND_ANY, - .help = "usb adapter command group", - .usage = "", - .chain = adapter_usb_command_handlers, + .help = "delay after deasserting SRST in ms", + .usage = "[milliseconds]", + }, + { + .name = "pulse_width", + .handler = handle_adapter_srst_pulse_width_command, + .mode = COMMAND_ANY, + .help = "SRST assertion pulse width in ms", + .usage = "[milliseconds]", }, -#endif /* MINIDRIVER */ COMMAND_REGISTRATION_DONE }; -static const struct command_registration interface_command_handlers[] = { +static const struct command_registration adapter_command_handlers[] = { { - .name = "adapter", - .mode = COMMAND_ANY, - .help = "adapter command group", - .usage = "", - .chain = adapter_command_handlers, + .name = "driver", + .handler = handle_adapter_driver_command, + .mode = COMMAND_CONFIG, + .help = "Select a debug adapter driver", + .usage = "driver_name", }, { - .name = "adapter_khz", - .handler = handle_adapter_khz_command, + .name = "speed", + .handler = handle_adapter_speed_command, .mode = COMMAND_ANY, .help = "With an argument, change to the specified maximum " "jtag speed. For JTAG, 0 KHz signifies adaptive " - " clocking. " + "clocking. " "With or without argument, display current setting.", .usage = "[khz]", }, { - .name = "adapter_name", + .name = "list", + .handler = handle_adapter_list_command, + .mode = COMMAND_ANY, + .help = "List all built-in debug adapter drivers", + .usage = "", + }, + { + .name = "name", .mode = COMMAND_ANY, .jim_handler = jim_adapter_name, .help = "Returns the name of the currently " "selected adapter (driver)", }, { - .name = "adapter_nsrst_delay", - .handler = handle_adapter_nsrst_delay_command, + .name = "srst", .mode = COMMAND_ANY, - .help = "delay after deasserting SRST in ms", - .usage = "[milliseconds]", + .help = "srst adapter command group", + .usage = "", + .chain = adapter_srst_command_handlers, }, { - .name = "adapter_nsrst_assert_width", - .handler = handle_adapter_nsrst_assert_width_command, + .name = "transports", + .handler = adapter_transports_command, + .mode = COMMAND_CONFIG, + .help = "Declare transports the adapter supports.", + .usage = "transport ... ", + }, +#ifndef HAVE_JTAG_MINIDRIVER_H + { + .name = "usb", .mode = COMMAND_ANY, - .help = "delay after asserting SRST in ms", - .usage = "[milliseconds]", + .help = "usb adapter command group", + .usage = "", + .chain = adapter_usb_command_handlers, }, +#endif /* MINIDRIVER */ { - .name = "interface", - .handler = handle_interface_command, - .mode = COMMAND_CONFIG, - .help = "Select a debug adapter interface (driver)", - .usage = "driver_name", + .name = "assert", + .handler = handle_adapter_reset_de_assert, + .mode = COMMAND_EXEC, + .help = "Controls SRST and TRST lines.", + .usage = "|deassert [srst|trst [assert|deassert srst|trst]]", }, { - .name = "interface_transports", - .handler = interface_transport_command, - .mode = COMMAND_CONFIG, - .help = "Declare transports the interface supports.", - .usage = "transport ... ", + .name = "deassert", + .handler = handle_adapter_reset_de_assert, + .mode = COMMAND_EXEC, + .help = "Controls SRST and TRST lines.", + .usage = "|assert [srst|trst [deassert|assert srst|trst]]", }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration interface_command_handlers[] = { { - .name = "interface_list", - .handler = handle_interface_list_command, + .name = "adapter", .mode = COMMAND_ANY, - .help = "List all built-in debug adapter interfaces (drivers)", + .help = "adapter command group", .usage = "", + .chain = adapter_command_handlers, }, { .name = "reset_config", diff --git a/src/jtag/aice/aice_interface.c b/src/jtag/aice/aice_interface.c index c83b8c2..90871a1 100644 --- a/src/jtag/aice/aice_interface.c +++ b/src/jtag/aice/aice_interface.c @@ -25,7 +25,6 @@ #include <transport/transport.h> #include <target/target.h> #include <jtag/aice/aice_transport.h> -#include <jtag/drivers/libusb_common.h> #include "aice_usb.h" #define AICE_KHZ_TO_SPEED_MAP_SIZE 16 @@ -518,14 +517,20 @@ static const struct command_registration aice_command_handlers[] = { /***************************************************************************/ /* End of Command handlers */ -struct jtag_interface aice_interface = { +static struct jtag_interface aice_interface = { + .execute_queue = aice_execute_queue, +}; + +struct adapter_driver aice_adapter_driver = { .name = "aice", - .commands = aice_command_handlers, .transports = aice_transports, + .commands = aice_command_handlers, + .init = aice_init, .quit = aice_quit, - .execute_queue = aice_execute_queue, .speed = aice_speed, /* set interface speed */ - .speed_div = aice_speed_div, /* return readable value */ .khz = aice_khz, /* convert khz to interface speed value */ + .speed_div = aice_speed_div, /* return readable value */ + + .jtag_ops = &aice_interface, }; diff --git a/src/jtag/aice/aice_transport.c b/src/jtag/aice/aice_transport.c index 15ebcac..ea710ad 100644 --- a/src/jtag/aice/aice_transport.c +++ b/src/jtag/aice/aice_transport.c @@ -47,6 +47,7 @@ static int jim_newtap_expected_id(Jim_Nvp *n, Jim_GetOptInfo *goi, return JIM_ERR; } + assert(pTap->expected_ids); memcpy(new_expected_ids, pTap->expected_ids, expected_len); new_expected_ids[pTap->expected_ids_cnt] = w; @@ -173,7 +174,7 @@ COMMAND_HANDLER(handle_scan_chain_command) while (tap) { uint32_t expected, expected_mask, ii; - snprintf(expected_id, sizeof expected_id, "0x%08x", + snprintf(expected_id, sizeof(expected_id), "0x%08x", (unsigned)((tap->expected_ids_cnt > 0) ? tap->expected_ids[0] : 0)); @@ -195,7 +196,7 @@ COMMAND_HANDLER(handle_scan_chain_command) (unsigned int)(expected_mask)); for (ii = 1; ii < tap->expected_ids_cnt; ii++) { - snprintf(expected_id, sizeof expected_id, "0x%08x", + snprintf(expected_id, sizeof(expected_id), "0x%08x", (unsigned) tap->expected_ids[ii]); if (tap->ignore_version) expected_id[2] = '*'; @@ -442,4 +443,3 @@ static void aice_constructor(void) { transport_register(&aice_jtag_transport); } - diff --git a/src/jtag/aice/aice_usb.c b/src/jtag/aice/aice_usb.c index 324ec7c..4427542 100644 --- a/src/jtag/aice/aice_usb.c +++ b/src/jtag/aice/aice_usb.c @@ -19,7 +19,7 @@ #include "config.h" #endif -#include <jtag/drivers/libusb_common.h> +#include <jtag/drivers/libusb_helper.h> #include <helper/log.h> #include <helper/time_support.h> #include <target/target.h> @@ -349,41 +349,53 @@ static void aice_unpack_dthmb(uint8_t *cmd_ack_code, uint8_t *target_id, /* calls the given usb_bulk_* function, allowing for the data to * trickle in with some timeouts */ static int usb_bulk_with_retries( - int (*f)(jtag_libusb_device_handle *, int, char *, int, int), - jtag_libusb_device_handle *dev, int ep, - char *bytes, int size, int timeout) + int (*f)(libusb_device_handle *, int, char *, int, int, int *), + libusb_device_handle *dev, int ep, + char *bytes, int size, int timeout, int *transferred) { int tries = 3, count = 0; while (tries && (count < size)) { - int result = f(dev, ep, bytes + count, size - count, timeout); - if (result > 0) + int result, ret; + + ret = f(dev, ep, bytes + count, size - count, timeout, &result); + if (ERROR_OK == ret) count += result; - else if ((-ETIMEDOUT != result) || !--tries) - return result; + else if ((ERROR_TIMEOUT_REACHED != ret) || !--tries) + return ret; } - return count; + + *transferred = count; + return ERROR_OK; } -static int wrap_usb_bulk_write(jtag_libusb_device_handle *dev, int ep, - char *buff, int size, int timeout) +static int wrap_usb_bulk_write(libusb_device_handle *dev, int ep, + char *buff, int size, int timeout, int *transferred) { + /* usb_bulk_write() takes const char *buff */ - return jtag_libusb_bulk_write(dev, ep, buff, size, timeout); + jtag_libusb_bulk_write(dev, ep, buff, size, timeout, transferred); + + return 0; } -static inline int usb_bulk_write_ex(jtag_libusb_device_handle *dev, int ep, +static inline int usb_bulk_write_ex(libusb_device_handle *dev, int ep, char *bytes, int size, int timeout) { - return usb_bulk_with_retries(&wrap_usb_bulk_write, - dev, ep, bytes, size, timeout); + int tr = 0; + + usb_bulk_with_retries(&wrap_usb_bulk_write, + dev, ep, bytes, size, timeout, &tr); + return tr; } -static inline int usb_bulk_read_ex(jtag_libusb_device_handle *dev, int ep, +static inline int usb_bulk_read_ex(struct libusb_device_handle *dev, int ep, char *bytes, int size, int timeout) { - return usb_bulk_with_retries(&jtag_libusb_bulk_read, - dev, ep, bytes, size, timeout); + int tr = 0; + usb_bulk_with_retries(&jtag_libusb_bulk_read, + dev, ep, bytes, size, timeout, &tr); + return tr; } /* Write data from out_buffer to USB. */ @@ -472,7 +484,9 @@ static int aice_usb_packet_flush(void) i = 0; while (1) { - aice_read_ctrl(AICE_READ_CTRL_BATCH_STATUS, &batch_status); + int retval = aice_read_ctrl(AICE_READ_CTRL_BATCH_STATUS, &batch_status); + if (retval != ERROR_OK) + return retval; if (batch_status & 0x1) return ERROR_OK; @@ -1785,8 +1799,8 @@ static int aice_write_reg(uint32_t coreid, uint32_t num, uint32_t val); static int check_suppressed_exception(uint32_t coreid, uint32_t dbger_value) { - uint32_t ir4_value; - uint32_t ir6_value; + uint32_t ir4_value = 0; + uint32_t ir6_value = 0; /* the default value of handling_suppressed_exception is false */ static bool handling_suppressed_exception; @@ -1840,7 +1854,7 @@ static int check_privilege(uint32_t coreid, uint32_t dbger_value) static int aice_check_dbger(uint32_t coreid, uint32_t expect_status) { uint32_t i = 0; - uint32_t value_dbger; + uint32_t value_dbger = 0; while (1) { aice_read_misc(coreid, NDS_EDM_MISC_DBGER, &value_dbger); @@ -1961,7 +1975,7 @@ static int aice_read_reg(uint32_t coreid, uint32_t num, uint32_t *val) aice_execute_dim(coreid, instructions, 4); - uint32_t value_edmsw; + uint32_t value_edmsw = 0; aice_read_edmsr(coreid, NDS_EDM_SR_EDMSW, &value_edmsw); if (value_edmsw & NDS_EDMSW_WDV) aice_read_dtr(coreid, val); @@ -2006,7 +2020,7 @@ static int aice_write_reg(uint32_t coreid, uint32_t num, uint32_t val) LOG_DEBUG("aice_write_reg, reg_no: 0x%08" PRIx32 ", value: 0x%08" PRIx32, num, val); uint32_t instructions[4]; /** execute instructions in DIM */ - uint32_t value_edmsw; + uint32_t value_edmsw = 0; aice_write_dtr(coreid, val); aice_read_edmsr(coreid, NDS_EDM_SR_EDMSW, &value_edmsw); @@ -2095,9 +2109,9 @@ static int aice_usb_open(struct aice_port_param_s *param) { const uint16_t vids[] = { param->vid, 0 }; const uint16_t pids[] = { param->pid, 0 }; - struct jtag_libusb_device_handle *devh; + struct libusb_device_handle *devh; - if (jtag_libusb_open(vids, pids, NULL, &devh) != ERROR_OK) + if (jtag_libusb_open(vids, pids, NULL, &devh, NULL) != ERROR_OK) return ERROR_FAIL; /* BE ***VERY CAREFUL*** ABOUT MAKING CHANGES IN THIS @@ -2113,7 +2127,7 @@ static int aice_usb_open(struct aice_port_param_s *param) #if IS_WIN32 == 0 - jtag_libusb_reset_device(devh); + libusb_reset_device(devh); #if IS_DARWIN == 0 @@ -2121,7 +2135,7 @@ static int aice_usb_open(struct aice_port_param_s *param) /* reopen jlink after usb_reset * on win32 this may take a second or two to re-enumerate */ int retval; - while ((retval = jtag_libusb_open(vids, pids, NULL, &devh)) != ERROR_OK) { + while ((retval = jtag_libusb_open(vids, pids, NULL, &devh, NULL)) != ERROR_OK) { usleep(1000); timeout--; if (!timeout) @@ -2134,8 +2148,8 @@ static int aice_usb_open(struct aice_port_param_s *param) #endif /* usb_set_configuration required under win32 */ - jtag_libusb_set_configuration(devh, 0); - jtag_libusb_claim_interface(devh, 0); + libusb_set_configuration(devh, 0); + libusb_claim_interface(devh, 0); unsigned int aice_read_ep; unsigned int aice_write_ep; @@ -2435,7 +2449,7 @@ static int aice_backup_tmp_registers(uint32_t coreid) LOG_DEBUG("backup_tmp_registers -"); /* backup target DTR first(if the target DTR is valid) */ - uint32_t value_edmsw; + uint32_t value_edmsw = 0; aice_read_edmsr(coreid, NDS_EDM_SR_EDMSW, &value_edmsw); core_info[coreid].edmsw_backup = value_edmsw; if (value_edmsw & 0x1) { /* EDMSW.WDV == 1 */ @@ -2602,13 +2616,13 @@ static int aice_usb_halt(uint32_t coreid) aice_init_edm_registers(coreid, false); /** Clear EDM_CTL.DBGIM & EDM_CTL.DBGACKM */ - uint32_t edm_ctl_value; + uint32_t edm_ctl_value = 0; aice_read_edmsr(coreid, NDS_EDM_SR_EDM_CTL, &edm_ctl_value); if (edm_ctl_value & 0x3) aice_write_edmsr(coreid, NDS_EDM_SR_EDM_CTL, edm_ctl_value & ~(0x3)); - uint32_t dbger; - uint32_t acc_ctl_value; + uint32_t dbger = 0; + uint32_t acc_ctl_value = 0; core_info[coreid].debug_under_dex_on = false; aice_read_misc(coreid, NDS_EDM_MISC_DBGER, &dbger); @@ -2649,7 +2663,7 @@ static int aice_usb_halt(uint32_t coreid) * it is only for debugging 'debug exception handler' purpose. * after openocd detaches from target, target behavior is * undefined. */ - uint32_t ir0_value; + uint32_t ir0_value = 0; uint32_t debug_mode_ir0_value; aice_read_reg(coreid, IR0, &ir0_value); debug_mode_ir0_value = ir0_value | 0x408; /* turn on DEX, set POM = 1 */ @@ -4017,7 +4031,7 @@ static int aice_usb_profiling(uint32_t coreid, uint32_t interval, uint32_t itera /* check status */ uint32_t i; - uint32_t batch_status; + uint32_t batch_status = 0; i = 0; while (1) { diff --git a/src/jtag/aice/aice_usb.h b/src/jtag/aice/aice_usb.h index 15cc1f6..04021de 100644 --- a/src/jtag/aice/aice_usb.h +++ b/src/jtag/aice/aice_usb.h @@ -93,7 +93,7 @@ struct aice_usb_handler_s { unsigned int usb_read_ep; unsigned int usb_write_ep; - struct jtag_libusb_device_handle *usb_handle; + struct libusb_device_handle *usb_handle; }; struct cache_info { diff --git a/src/jtag/commands.c b/src/jtag/commands.c index 3352e03..e88a3b7 100644 --- a/src/jtag/commands.c +++ b/src/jtag/commands.c @@ -31,6 +31,7 @@ #endif #include <jtag/jtag.h> +#include <transport/transport.h> #include "commands.h" struct cmd_queue_page { @@ -48,6 +49,19 @@ static struct jtag_command **next_command_pointer = &jtag_command_queue; void jtag_queue_command(struct jtag_command *cmd) { + if (!transport_is_jtag()) { + /* + * FIXME: This should not happen! + * There could be old code that queues jtag commands with non jtag interfaces so, for + * the moment simply highlight it by log an error. + * We should fix it quitting with assert(0) because it is an internal error, or returning + * an error after call to jtag_command_queue_reset() to free the jtag queue and avoid + * memory leaks. + * The fix can be applied immediately after next release (v0.11.0 ?) + */ + LOG_ERROR("JTAG API jtag_queue_command() called on non JTAG interface"); + } + /* this command goes on the end, so ensure the queue terminates */ cmd->next = NULL; diff --git a/src/jtag/core.c b/src/jtag/core.c index 5e7c1e4..1d424b2 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -126,10 +126,10 @@ static int rclk_fallback_speed_khz; static enum {CLOCK_MODE_UNSELECTED, CLOCK_MODE_KHZ, CLOCK_MODE_RCLK} clock_mode; static int jtag_speed; -static struct jtag_interface *jtag; +/* FIXME: change name to this variable, it is not anymore JTAG only */ +static struct adapter_driver *jtag; -/* configuration */ -struct jtag_interface *jtag_interface; +extern struct adapter_driver *adapter_driver; void jtag_set_flush_queue_sleep(int ms) { @@ -503,7 +503,7 @@ int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state state) { int retval; - if (!(jtag->supported & DEBUG_CAP_TMS_SEQ)) + if (!(jtag->jtag_ops->supported & DEBUG_CAP_TMS_SEQ)) return ERROR_JTAG_NOT_IMPLEMENTED; jtag_checks(); @@ -611,22 +611,91 @@ void jtag_add_clocks(int num_cycles) } } -void swd_add_reset(int req_srst) +static int adapter_system_reset(int req_srst) { + int retval; + if (req_srst) { if (!(jtag_reset_config & RESET_HAS_SRST)) { LOG_ERROR("BUG: can't assert SRST"); - jtag_set_error(ERROR_FAIL); - return; + return ERROR_FAIL; } req_srst = 1; } /* Maybe change SRST signal state */ if (jtag_srst != req_srst) { + retval = jtag->reset(0, req_srst); + if (retval != ERROR_OK) { + LOG_ERROR("SRST error"); + return ERROR_FAIL; + } + jtag_srst = req_srst; + + if (req_srst) { + LOG_DEBUG("SRST line asserted"); + if (adapter_nsrst_assert_width) + jtag_sleep(adapter_nsrst_assert_width * 1000); + } else { + LOG_DEBUG("SRST line released"); + if (adapter_nsrst_delay) + jtag_sleep(adapter_nsrst_delay * 1000); + } + } + + return ERROR_OK; +} + +static void legacy_jtag_add_reset(int req_tlr_or_trst, int req_srst) +{ + int trst_with_tlr = 0; + int new_srst = 0; + int new_trst = 0; + + /* Without SRST, we must use target-specific JTAG operations + * on each target; callers should not be requesting SRST when + * that signal doesn't exist. + * + * RESET_SRST_PULLS_TRST is a board or chip level quirk, which + * can kick in even if the JTAG adapter can't drive TRST. + */ + if (req_srst) { + if (!(jtag_reset_config & RESET_HAS_SRST)) { + LOG_ERROR("BUG: can't assert SRST"); + jtag_set_error(ERROR_FAIL); + return; + } + if ((jtag_reset_config & RESET_SRST_PULLS_TRST) != 0 + && !req_tlr_or_trst) { + LOG_ERROR("BUG: can't assert only SRST"); + jtag_set_error(ERROR_FAIL); + return; + } + new_srst = 1; + } + + /* JTAG reset (entry to TAP_RESET state) can always be achieved + * using TCK and TMS; that may go through a TAP_{IR,DR}UPDATE + * state first. TRST accelerates it, and bypasses those states. + * + * RESET_TRST_PULLS_SRST is a board or chip level quirk, which + * can kick in even if the JTAG adapter can't drive SRST. + */ + if (req_tlr_or_trst) { + if (!(jtag_reset_config & RESET_HAS_TRST)) + trst_with_tlr = 1; + else if ((jtag_reset_config & RESET_TRST_PULLS_SRST) != 0 + && !req_srst) + trst_with_tlr = 1; + else + new_trst = 1; + } + + /* Maybe change TRST and/or SRST signal state */ + if (jtag_srst != new_srst || jtag_trst != new_trst) { int retval; - retval = interface_jtag_add_reset(0, req_srst); + retval = interface_jtag_add_reset(new_trst, new_srst); if (retval != ERROR_OK) jtag_set_error(retval); else @@ -636,9 +705,11 @@ void swd_add_reset(int req_srst) LOG_ERROR("TRST/SRST error"); return; } + } - /* SRST resets everything hooked up to that signal */ - jtag_srst = req_srst; + /* SRST resets everything hooked up to that signal */ + if (jtag_srst != new_srst) { + jtag_srst = new_srst; if (jtag_srst) { LOG_DEBUG("SRST line asserted"); if (adapter_nsrst_assert_width) @@ -648,21 +719,54 @@ void swd_add_reset(int req_srst) if (adapter_nsrst_delay) jtag_add_sleep(adapter_nsrst_delay * 1000); } + } - retval = jtag_execute_queue(); - if (retval != ERROR_OK) { - LOG_ERROR("SRST timings error"); - return; + /* Maybe enter the JTAG TAP_RESET state ... + * - using only TMS, TCK, and the JTAG state machine + * - or else more directly, using TRST + * + * TAP_RESET should be invisible to non-debug parts of the system. + */ + if (trst_with_tlr) { + LOG_DEBUG("JTAG reset with TLR instead of TRST"); + jtag_add_tlr(); + + } else if (jtag_trst != new_trst) { + jtag_trst = new_trst; + if (jtag_trst) { + LOG_DEBUG("TRST line asserted"); + tap_set_state(TAP_RESET); + if (jtag_ntrst_assert_width) + jtag_add_sleep(jtag_ntrst_assert_width * 1000); + } else { + LOG_DEBUG("TRST line released"); + if (jtag_ntrst_delay) + jtag_add_sleep(jtag_ntrst_delay * 1000); + + /* We just asserted nTRST, so we're now in TAP_RESET. + * Inform possible listeners about this, now that + * JTAG instructions and data can be shifted. This + * sequence must match jtag_add_tlr(). + */ + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + jtag_notify_event(JTAG_TRST_ASSERTED); } } } +/* FIXME: name is misleading; we do not plan to "add" reset into jtag queue */ void jtag_add_reset(int req_tlr_or_trst, int req_srst) { + int retval; int trst_with_tlr = 0; int new_srst = 0; int new_trst = 0; + if (!jtag->reset) { + legacy_jtag_add_reset(req_tlr_or_trst, req_srst); + return; + } + /* Without SRST, we must use target-specific JTAG operations * on each target; callers should not be requesting SRST when * that signal doesn't exist. @@ -704,15 +808,12 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst) /* Maybe change TRST and/or SRST signal state */ if (jtag_srst != new_srst || jtag_trst != new_trst) { - int retval; - - retval = interface_jtag_add_reset(new_trst, new_srst); - if (retval != ERROR_OK) - jtag_set_error(retval); - else - retval = jtag_execute_queue(); + /* guarantee jtag queue empty before changing reset status */ + jtag_execute_queue(); + retval = jtag->reset(new_trst, new_srst); if (retval != ERROR_OK) { + jtag_set_error(retval); LOG_ERROR("TRST/SRST error"); return; } @@ -741,6 +842,7 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst) if (trst_with_tlr) { LOG_DEBUG("JTAG reset with TLR instead of TRST"); jtag_add_tlr(); + jtag_execute_queue(); } else if (jtag_trst != new_trst) { jtag_trst = new_trst; @@ -836,7 +938,88 @@ int default_interface_jtag_execute_queue(void) return ERROR_FAIL; } - return jtag->execute_queue(); + if (!transport_is_jtag()) { + /* + * FIXME: This should not happen! + * There could be old code that queues jtag commands with non jtag interfaces so, for + * the moment simply highlight it by log an error and return on empty execute_queue. + * We should fix it quitting with assert(0) because it is an internal error. + * The fix can be applied immediately after next release (v0.11.0 ?) + */ + LOG_ERROR("JTAG API jtag_execute_queue() called on non JTAG interface"); + if (!jtag->jtag_ops || !jtag->jtag_ops->execute_queue) + return ERROR_OK; + } + + int result = jtag->jtag_ops->execute_queue(); + +#if !BUILD_ZY1000 + /* Only build this if we use a regular driver with a command queue. + * Otherwise jtag_command_queue won't be found at compile/link time. Its + * definition is in jtag/commands.c, which is only built/linked by + * jtag/Makefile.am if MINIDRIVER_DUMMY || !MINIDRIVER, but those variables + * aren't accessible here. */ + struct jtag_command *cmd = jtag_command_queue; + while (debug_level >= LOG_LVL_DEBUG && cmd) { + switch (cmd->type) { + case JTAG_SCAN: + LOG_DEBUG_IO("JTAG %s SCAN to %s", + cmd->cmd.scan->ir_scan ? "IR" : "DR", + tap_state_name(cmd->cmd.scan->end_state)); + for (int i = 0; i < cmd->cmd.scan->num_fields; i++) { + struct scan_field *field = cmd->cmd.scan->fields + i; + if (field->out_value) { + char *str = buf_to_str(field->out_value, field->num_bits, 16); + LOG_DEBUG_IO(" %db out: %s", field->num_bits, str); + free(str); + } + if (field->in_value) { + char *str = buf_to_str(field->in_value, field->num_bits, 16); + LOG_DEBUG_IO(" %db in: %s", field->num_bits, str); + free(str); + } + } + break; + case JTAG_TLR_RESET: + LOG_DEBUG_IO("JTAG TLR RESET to %s", + tap_state_name(cmd->cmd.statemove->end_state)); + break; + case JTAG_RUNTEST: + LOG_DEBUG_IO("JTAG RUNTEST %d cycles to %s", + cmd->cmd.runtest->num_cycles, + tap_state_name(cmd->cmd.runtest->end_state)); + break; + case JTAG_RESET: + { + const char *reset_str[3] = { + "leave", "deassert", "assert" + }; + LOG_DEBUG_IO("JTAG RESET %s TRST, %s SRST", + reset_str[cmd->cmd.reset->trst + 1], + reset_str[cmd->cmd.reset->srst + 1]); + } + break; + case JTAG_PATHMOVE: + LOG_DEBUG_IO("JTAG PATHMOVE (TODO)"); + break; + case JTAG_SLEEP: + LOG_DEBUG_IO("JTAG SLEEP (TODO)"); + break; + case JTAG_STABLECLOCKS: + LOG_DEBUG_IO("JTAG STABLECLOCKS (TODO)"); + break; + case JTAG_TMS: + LOG_DEBUG_IO("JTAG TMS (TODO)"); + break; + default: + LOG_ERROR("Unknown JTAG command: %d", cmd->type); + break; + } + cmd = cmd->next; + } +#endif + + return result; } void jtag_execute_queue_noclear(void) @@ -1050,7 +1233,7 @@ static int jtag_examine_chain(void) /* Add room for end-of-chain marker. */ max_taps++; - uint8_t *idcode_buffer = malloc(max_taps * 4); + uint8_t *idcode_buffer = calloc(4, max_taps); if (idcode_buffer == NULL) return ERROR_JTAG_INIT_FAILED; @@ -1086,7 +1269,7 @@ static int jtag_examine_chain(void) * REVISIT create a jtag_alloc(chip, tap) routine, and * share it with jim_newtap_cmd(). */ - tap = calloc(1, sizeof *tap); + tap = calloc(1, sizeof(*tap)); if (!tap) { retval = ERROR_FAIL; goto out; @@ -1107,7 +1290,8 @@ static int jtag_examine_chain(void) if ((idcode & 1) == 0) { /* Zero for LSB indicates a device in bypass */ - LOG_INFO("TAP %s has invalid IDCODE (0x%x)", tap->dotted_name, idcode); + LOG_INFO("TAP %s does not have valid IDCODE (idcode=0x%x)", + tap->dotted_name, idcode); tap->hasidcode = false; tap->idcode = 0; @@ -1222,7 +1406,7 @@ static int jtag_validate_ircapture(void) && tap->ir_length < JTAG_IRLEN_MAX) { tap->ir_length++; } - LOG_WARNING("AUTO %s - use \"jtag newtap " "%s %s -irlen %d " + LOG_WARNING("AUTO %s - use \"jtag newtap %s %s -irlen %d " "-expected-id 0x%08" PRIx32 "\"", tap->dotted_name, tap->chip, tap->tapname, tap->ir_length, tap->idcode); } @@ -1335,18 +1519,18 @@ int adapter_init(struct command_context *cmd_ctx) if (jtag) return ERROR_OK; - if (!jtag_interface) { - /* nothing was previously specified by "interface" command */ + if (!adapter_driver) { + /* nothing was previously specified by "adapter driver" command */ LOG_ERROR("Debug Adapter has to be specified, " - "see \"interface\" command"); + "see \"adapter driver\" command"); return ERROR_JTAG_INVALID_INTERFACE; } int retval; - retval = jtag_interface->init(); + retval = adapter_driver->init(); if (retval != ERROR_OK) return retval; - jtag = jtag_interface; + jtag = adapter_driver; if (jtag->speed == NULL) { LOG_INFO("This adapter doesn't support configurable speed"); @@ -1355,7 +1539,7 @@ int adapter_init(struct command_context *cmd_ctx) if (CLOCK_MODE_UNSELECTED == clock_mode) { LOG_ERROR("An adapter speed is not selected in the init script." - " Insert a call to adapter_khz or jtag_rclk to proceed."); + " Insert a call to \"adapter speed\" or \"jtag_rclk\" to proceed."); return ERROR_JTAG_INIT_FAILED; } @@ -1486,17 +1670,19 @@ int adapter_quit(void) int swd_init_reset(struct command_context *cmd_ctx) { - int retval = adapter_init(cmd_ctx); + int retval, retval1; + + retval = adapter_init(cmd_ctx); if (retval != ERROR_OK) return retval; LOG_DEBUG("Initializing with hard SRST reset"); if (jtag_reset_config & RESET_HAS_SRST) - swd_add_reset(1); - swd_add_reset(0); - retval = jtag_execute_queue(); - return retval; + retval = adapter_system_reset(1); + retval1 = adapter_system_reset(0); + + return (retval == ERROR_OK) ? retval1 : retval; } int jtag_init_reset(struct command_context *cmd_ctx) @@ -1686,7 +1872,7 @@ void jtag_set_verify(bool enable) jtag_verify = enable; } -bool jtag_will_verify() +bool jtag_will_verify(void) { return jtag_verify; } @@ -1696,7 +1882,7 @@ void jtag_set_verify_capture_ir(bool enable) jtag_verify_capture_ir = enable; } -bool jtag_will_verify_capture_ir() +bool jtag_will_verify_capture_ir(void) { return jtag_verify_capture_ir; } @@ -1819,42 +2005,98 @@ bool transport_is_jtag(void) return get_current_transport() == &jtag_transport; } -void adapter_assert_reset(void) +int adapter_resets(int trst, int srst) +{ + if (get_current_transport() == NULL) { + LOG_ERROR("transport is not selected"); + return ERROR_FAIL; + } + + if (transport_is_jtag()) { + if (srst == SRST_ASSERT && !(jtag_reset_config & RESET_HAS_SRST)) { + LOG_ERROR("adapter has no srst signal"); + return ERROR_FAIL; + } + + /* adapters without trst signal will eventually use tlr sequence */ + jtag_add_reset(trst, srst); + /* + * The jtag queue is still used for reset by some adapter. Flush it! + * FIXME: To be removed when all adapter drivers will be updated! + */ + jtag_execute_queue(); + return ERROR_OK; + } else if (transport_is_swd() || transport_is_hla() || + transport_is_dapdirect_swd() || transport_is_dapdirect_jtag() || + transport_is_swim()) { + if (trst == TRST_ASSERT) { + LOG_ERROR("transport %s has no trst signal", + get_current_transport()->name); + return ERROR_FAIL; + } + + if (srst == SRST_ASSERT && !(jtag_reset_config & RESET_HAS_SRST)) { + LOG_ERROR("adapter has no srst signal"); + return ERROR_FAIL; + } + adapter_system_reset(srst); + return ERROR_OK; + } + + if (trst == TRST_DEASSERT && srst == SRST_DEASSERT) + return ERROR_OK; + + LOG_ERROR("reset is not supported on transport %s", + get_current_transport()->name); + + return ERROR_FAIL; +} + +int adapter_assert_reset(void) { if (transport_is_jtag()) { if (jtag_reset_config & RESET_SRST_PULLS_TRST) jtag_add_reset(1, 1); else jtag_add_reset(0, 1); - } else if (transport_is_swd()) - swd_add_reset(1); + return ERROR_OK; + } else if (transport_is_swd() || transport_is_hla() || + transport_is_dapdirect_jtag() || transport_is_dapdirect_swd() || + transport_is_swim()) + return adapter_system_reset(1); else if (get_current_transport() != NULL) LOG_ERROR("reset is not supported on %s", get_current_transport()->name); else LOG_ERROR("transport is not selected"); + return ERROR_FAIL; } -void adapter_deassert_reset(void) +int adapter_deassert_reset(void) { - if (transport_is_jtag()) + if (transport_is_jtag()) { jtag_add_reset(0, 0); - else if (transport_is_swd()) - swd_add_reset(0); + return ERROR_OK; + } else if (transport_is_swd() || transport_is_hla() || + transport_is_dapdirect_jtag() || transport_is_dapdirect_swd() || + transport_is_swim()) + return adapter_system_reset(0); else if (get_current_transport() != NULL) LOG_ERROR("reset is not supported on %s", get_current_transport()->name); else LOG_ERROR("transport is not selected"); + return ERROR_FAIL; } int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, - uint32_t port_size, unsigned int *trace_freq) + uint32_t port_size, unsigned int *trace_freq, + unsigned int traceclkin_freq, uint16_t *prescaler) { - if (jtag->config_trace) - return jtag->config_trace(enabled, pin_protocol, port_size, - trace_freq); - else if (enabled) { + if (jtag->config_trace) { + return jtag->config_trace(enabled, pin_protocol, port_size, trace_freq, + traceclkin_freq, prescaler); + } else if (enabled) { LOG_ERROR("The selected interface does not support tracing"); return ERROR_FAIL; } diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index 572cd24..07824f6 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -22,7 +22,7 @@ DRIVERFILES += %D%/driver.c DRIVERFILES += %D%/jtag_usb_common.c if USE_LIBUSB1 -DRIVERFILES += %D%/libusb1_common.c +DRIVERFILES += %D%/libusb_helper.c %C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBUSB1_CFLAGS) %C%_libocdjtagdrivers_la_LIBADD += $(LIBUSB1_LIBS) endif @@ -31,9 +31,6 @@ if USE_LIBUSB0 DRIVERFILES += %D%/usb_common.c %C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBUSB0_CFLAGS) %C%_libocdjtagdrivers_la_LIBADD += $(LIBUSB0_LIBS) -if !USE_LIBUSB1 -DRIVERFILES += %D%/libusb0_common.c -endif endif if USE_LIBFTDI @@ -136,6 +133,9 @@ if HLADAPTER DRIVERFILES += %D%/stlink_usb.c DRIVERFILES += %D%/ti_icdi_usb.c endif +if RSHIM +DRIVERFILES += %D%/rshim.c +endif if OSBDM DRIVERFILES += %D%/osbdm.c endif @@ -145,6 +145,9 @@ endif if SYSFSGPIO DRIVERFILES += %D%/sysfsgpio.c endif +if XLNX_PCIE_XVC +DRIVERFILES += %D%/xlnx-pcie-xvc.c +endif if BCM2835GPIO DRIVERFILES += %D%/bcm2835gpio.c endif @@ -168,9 +171,7 @@ DRIVERHEADERS = \ %D%/bitbang.h \ %D%/bitq.h \ %D%/jtag_usb_common.h \ - %D%/libusb0_common.h \ - %D%/libusb1_common.h \ - %D%/libusb_common.h \ + %D%/libusb_helper.h \ %D%/minidriver_imp.h \ %D%/mpsse.h \ %D%/rlink.h \ @@ -183,4 +184,3 @@ DRIVERHEADERS = \ %D%/versaloon/versaloon.h \ %D%/versaloon/versaloon_include.h \ %D%/versaloon/versaloon_internal.h - diff --git a/src/jtag/drivers/amt_jtagaccel.c b/src/jtag/drivers/amt_jtagaccel.c index 045672f..f5918a0 100644 --- a/src/jtag/drivers/amt_jtagaccel.c +++ b/src/jtag/drivers/amt_jtagaccel.c @@ -393,7 +393,7 @@ int amt_jtagaccel_get_giveio_access(void) HANDLE h; OSVERSIONINFO version; - version.dwOSVersionInfoSize = sizeof version; + version.dwOSVersionInfoSize = sizeof(version); if (!GetVersionEx(&version)) { errno = EINVAL; return -1; @@ -584,7 +584,11 @@ static const struct command_registration amtjtagaccel_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct jtag_interface amt_jtagaccel_interface = { +static struct jtag_interface amt_jtagaccel_interface = { + .execute_queue = amt_jtagaccel_execute_queue, +}; + +struct adapter_driver amt_jtagaccel_adapter_driver = { .name = "amt_jtagaccel", .transports = jtag_only, .commands = amtjtagaccel_command_handlers, @@ -592,5 +596,6 @@ struct jtag_interface amt_jtagaccel_interface = { .init = amt_jtagaccel_init, .quit = amt_jtagaccel_quit, .speed = amt_jtagaccel_speed, - .execute_queue = amt_jtagaccel_execute_queue, + + .jtag_ops = &amt_jtagaccel_interface, }; diff --git a/src/jtag/drivers/arm-jtag-ew.c b/src/jtag/drivers/arm-jtag-ew.c index 285bf9b..405278b 100644 --- a/src/jtag/drivers/arm-jtag-ew.c +++ b/src/jtag/drivers/arm-jtag-ew.c @@ -107,7 +107,7 @@ static int armjtagew_execute_queue(void) switch (cmd->type) { case JTAG_RUNTEST: LOG_DEBUG_IO("runtest %i cycles, end in %i", - cmd->cmd.runtest->num_cycles, \ + cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); armjtagew_end_state(cmd->cmd.runtest->end_state); @@ -122,8 +122,8 @@ static int armjtagew_execute_queue(void) break; case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %i states, end in %i", \ - cmd->cmd.pathmove->num_states, \ + LOG_DEBUG_IO("pathmove: %i states, end in %i", + cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); armjtagew_path_move(cmd->cmd.pathmove->num_states, @@ -459,10 +459,10 @@ static int armjtagew_get_version_info(void) auxinfo[256] = '\0'; LOG_INFO( - "ARM-JTAG-EW firmware version %d.%d, hardware revision %c, SN=%s, Additional info: %s", \ + "ARM-JTAG-EW firmware version %d.%d, hardware revision %c, SN=%s, Additional info: %s", usb_in_buffer[1], - usb_in_buffer[0], \ - isgraph(usb_in_buffer[2]) ? usb_in_buffer[2] : 'X', \ + usb_in_buffer[0], + isgraph(usb_in_buffer[2]) ? usb_in_buffer[2] : 'X', sn, auxinfo); @@ -495,16 +495,22 @@ static const struct command_registration armjtagew_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct jtag_interface armjtagew_interface = { +static struct jtag_interface armjtagew_interface = { + .execute_queue = armjtagew_execute_queue, +}; + +struct adapter_driver armjtagew_adapter_driver = { .name = "arm-jtag-ew", - .commands = armjtagew_command_handlers, .transports = jtag_only, - .execute_queue = armjtagew_execute_queue, - .speed = armjtagew_speed, - .speed_div = armjtagew_speed_div, - .khz = armjtagew_khz, + .commands = armjtagew_command_handlers, + .init = armjtagew_init, .quit = armjtagew_quit, + .speed = armjtagew_speed, + .khz = armjtagew_khz, + .speed_div = armjtagew_speed_div, + + .jtag_ops = &armjtagew_interface, }; /************************************************************************** @@ -677,7 +683,7 @@ static int armjtagew_tap_execute(void) /**************************************************************************** * JLink USB low-level functions */ -static struct armjtagew *armjtagew_usb_open() +static struct armjtagew *armjtagew_usb_open(void) { usb_init(); @@ -744,7 +750,7 @@ static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length) return -1; } - result = usb_bulk_write(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_OUT, \ + result = usb_bulk_write(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_OUT, (char *)usb_out_buffer, out_length, ARMJTAGEW_USB_TIMEOUT); LOG_DEBUG_IO("armjtagew_usb_write, out_length = %d, result = %d", out_length, result); @@ -758,7 +764,7 @@ static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length) /* Read data from USB into in_buffer. */ static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length) { - int result = usb_bulk_read(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_IN, \ + int result = usb_bulk_read(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_IN, (char *)usb_in_buffer, exp_in_length, ARMJTAGEW_USB_TIMEOUT); LOG_DEBUG_IO("armjtagew_usb_read, result = %d", result); diff --git a/src/jtag/drivers/at91rm9200.c b/src/jtag/drivers/at91rm9200.c index ac65563..1026847 100644 --- a/src/jtag/drivers/at91rm9200.c +++ b/src/jtag/drivers/at91rm9200.c @@ -111,7 +111,6 @@ static uint32_t *pio_base; */ static bb_value_t at91rm9200_read(void); static int at91rm9200_write(int tck, int tms, int tdi); -static int at91rm9200_reset(int trst, int srst); static int at91rm9200_init(void); static int at91rm9200_quit(void); @@ -119,7 +118,6 @@ static int at91rm9200_quit(void); static struct bitbang_interface at91rm9200_bitbang = { .read = at91rm9200_read, .write = at91rm9200_write, - .reset = at91rm9200_reset, .blink = 0 }; @@ -189,13 +187,20 @@ static const struct command_registration at91rm9200_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct jtag_interface at91rm9200_interface = { - .name = "at91rm9200", +static struct jtag_interface at91rm9200_interface = { .execute_queue = bitbang_execute_queue, +}; + +struct adapter_driver at91rm9200_adapter_driver = { + .name = "at91rm9200", .transports = jtag_only, .commands = at91rm9200_command_handlers, + .init = at91rm9200_init, .quit = at91rm9200_quit, + .reset = at91rm9200_reset, + + .jtag_ops = &at91rm9200_interface, }; static int at91rm9200_init(void) diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index 36e10b6..df557c5 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -51,7 +51,6 @@ static volatile uint32_t *pio_base; static bb_value_t bcm2835gpio_read(void); static int bcm2835gpio_write(int tck, int tms, int tdi); -static int bcm2835gpio_reset(int trst, int srst); static int bcm2835_swdio_read(void); static void bcm2835_swdio_drive(bool is_output); @@ -62,7 +61,6 @@ static int bcm2835gpio_quit(void); static struct bitbang_interface bcm2835gpio_bitbang = { .read = bcm2835gpio_read, .write = bcm2835gpio_write, - .reset = bcm2835gpio_reset, .swdio_read = bcm2835_swdio_read, .swdio_drive = bcm2835_swdio_drive, .blink = NULL @@ -407,18 +405,25 @@ static const struct command_registration bcm2835gpio_command_handlers[] = { static const char * const bcm2835_transports[] = { "jtag", "swd", NULL }; -struct jtag_interface bcm2835gpio_interface = { - .name = "bcm2835gpio", +static struct jtag_interface bcm2835gpio_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, +}; + +struct adapter_driver bcm2835gpio_adapter_driver = { + .name = "bcm2835gpio", .transports = bcm2835_transports, - .swd = &bitbang_swd, - .speed = bcm2835gpio_speed, - .khz = bcm2835gpio_khz, - .speed_div = bcm2835gpio_speed_div, .commands = bcm2835gpio_command_handlers, + .init = bcm2835gpio_init, .quit = bcm2835gpio_quit, + .reset = bcm2835gpio_reset, + .speed = bcm2835gpio_speed, + .khz = bcm2835gpio_khz, + .speed_div = bcm2835gpio_speed_div, + + .jtag_ops = &bcm2835gpio_interface, + .swd_ops = &bitbang_swd, }; static bool bcm2835gpio_jtag_mode_possible(void) @@ -461,7 +466,11 @@ static int bcm2835gpio_init(void) return ERROR_JTAG_INIT_FAILED; } - dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC); + dev_mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC); + if (dev_mem_fd < 0) { + LOG_DEBUG("Cannot open /dev/gpiomem, fallback to /dev/mem"); + dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC); + } if (dev_mem_fd < 0) { perror("open"); return ERROR_JTAG_INIT_FAILED; diff --git a/src/jtag/drivers/bitbang.c b/src/jtag/drivers/bitbang.c index b5078c0..72e9320 100644 --- a/src/jtag/drivers/bitbang.c +++ b/src/jtag/drivers/bitbang.c @@ -314,17 +314,6 @@ int bitbang_execute_queue(void) while (cmd) { switch (cmd->type) { - case JTAG_RESET: - LOG_DEBUG_IO("reset trst: %i srst %i", - cmd->cmd.reset->trst, - cmd->cmd.reset->srst); - if ((cmd->cmd.reset->trst == 1) || - (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) - tap_set_state(TAP_RESET); - if (bitbang_interface->reset(cmd->cmd.reset->trst, - cmd->cmd.reset->srst) != ERROR_OK) - return ERROR_FAIL; - break; case JTAG_RUNTEST: LOG_DEBUG_IO("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, diff --git a/src/jtag/drivers/bitbang.h b/src/jtag/drivers/bitbang.h index 577717e..bbbc693 100644 --- a/src/jtag/drivers/bitbang.h +++ b/src/jtag/drivers/bitbang.h @@ -51,13 +51,12 @@ struct bitbang_interface { /** Set TCK, TMS, and TDI to the given values. */ int (*write)(int tck, int tms, int tdi); - int (*reset)(int trst, int srst); int (*blink)(int on); int (*swdio_read)(void); void (*swdio_drive)(bool on); }; -const struct swd_driver bitbang_swd; +extern const struct swd_driver bitbang_swd; extern bool swd_mode; diff --git a/src/jtag/drivers/buspirate.c b/src/jtag/drivers/buspirate.c index 872896b..020c4ce 100644 --- a/src/jtag/drivers/buspirate.c +++ b/src/jtag/drivers/buspirate.c @@ -34,6 +34,7 @@ static int buspirate_execute_queue(void); static int buspirate_init(void); static int buspirate_quit(void); +static int buspirate_reset(int trst, int srst); static void buspirate_end_state(tap_state_t state); static void buspirate_state_move(void); @@ -133,7 +134,6 @@ static void buspirate_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command); static void buspirate_tap_make_space(int scan, int bits); -static void buspirate_reset(int trst, int srst); static void buspirate_set_feature(int, char, char); static void buspirate_set_mode(int, char); static void buspirate_set_speed(int, char); @@ -213,18 +213,6 @@ static int buspirate_execute_queue(void) buffer, scan_size, cmd->cmd.scan); break; - case JTAG_RESET: - LOG_DEBUG_IO("reset trst: %i srst %i", - cmd->cmd.reset->trst, cmd->cmd.reset->srst); - - /* flush buffers, so we can reset */ - buspirate_tap_execute(); - - if (cmd->cmd.reset->trst == 1) - tap_set_state(TAP_RESET); - buspirate_reset(cmd->cmd.reset->trst, - cmd->cmd.reset->srst); - break; case JTAG_SLEEP: LOG_DEBUG_IO("sleep %i", cmd->cmd.sleep->us); buspirate_tap_execute(); @@ -548,14 +536,21 @@ static const struct swd_driver buspirate_swd = { static const char * const buspirate_transports[] = { "jtag", "swd", NULL }; -struct jtag_interface buspirate_interface = { - .name = "buspirate", +static struct jtag_interface buspirate_interface = { .execute_queue = buspirate_execute_queue, - .commands = buspirate_command_handlers, +}; + +struct adapter_driver buspirate_adapter_driver = { + .name = "buspirate", .transports = buspirate_transports, - .swd = &buspirate_swd, + .commands = buspirate_command_handlers, + .init = buspirate_init, - .quit = buspirate_quit + .quit = buspirate_quit, + .reset = buspirate_reset, + + .jtag_ops = &buspirate_interface, + .swd_ops = &buspirate_swd, }; /*************** jtag execute commands **********************/ @@ -860,7 +855,7 @@ static void buspirate_tap_append_scan(int length, uint8_t *buffer, /*************** wrapper functions *********************/ /* (1) assert or (0) deassert reset lines */ -static void buspirate_reset(int trst, int srst) +static int buspirate_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); @@ -873,6 +868,8 @@ static void buspirate_reset(int trst, int srst) buspirate_set_feature(buspirate_fd, FEATURE_SRST, ACTION_DISABLE); else buspirate_set_feature(buspirate_fd, FEATURE_SRST, ACTION_ENABLE); + + return ERROR_OK; } static void buspirate_set_feature(int fd, char feat, char action) diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c index d52d698..ee1cb53 100644 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ b/src/jtag/drivers/cmsis_dap_usb.c @@ -364,8 +364,6 @@ static void cmsis_dap_usb_close(struct cmsis_dap *dap) free(pending_fifo[i].transfers); pending_fifo[i].transfers = NULL; } - - return; } static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen) @@ -509,15 +507,15 @@ static int cmsis_dap_cmd_DAP_Info(uint8_t info, uint8_t **data) return ERROR_OK; } -static int cmsis_dap_cmd_DAP_LED(uint8_t leds) +static int cmsis_dap_cmd_DAP_LED(uint8_t led, uint8_t state) { int retval; uint8_t *buffer = cmsis_dap_handle->packet_buffer; buffer[0] = 0; /* report number */ buffer[1] = CMD_DAP_LED; - buffer[2] = 0x00; - buffer[3] = leds; + buffer[2] = led; + buffer[3] = state; retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 4); if (retval != ERROR_OK || buffer[1] != 0x00) { @@ -1086,8 +1084,12 @@ static int cmsis_dap_init(void) if (retval != ERROR_OK) return ERROR_FAIL; } + /* Both LEDs on */ + retval = cmsis_dap_cmd_DAP_LED(LED_ID_CONNECT, LED_ON); + if (retval != ERROR_OK) + return ERROR_FAIL; - retval = cmsis_dap_cmd_DAP_LED(0x03); /* Both LEDs on */ + retval = cmsis_dap_cmd_DAP_LED(LED_ID_RUN, LED_ON); if (retval != ERROR_OK) return ERROR_FAIL; @@ -1102,9 +1104,6 @@ static int cmsis_dap_init(void) LOG_INFO("Connecting under reset"); } } - - cmsis_dap_cmd_DAP_LED(0x00); /* Both LEDs off */ - LOG_INFO("CMSIS-DAP: Interface ready"); return ERROR_OK; @@ -1119,28 +1118,31 @@ static int cmsis_dap_swd_init(void) static int cmsis_dap_quit(void) { cmsis_dap_cmd_DAP_Disconnect(); - cmsis_dap_cmd_DAP_LED(0x00); /* Both LEDs off */ + /* Both LEDs off */ + cmsis_dap_cmd_DAP_LED(LED_ID_RUN, LED_OFF); + cmsis_dap_cmd_DAP_LED(LED_ID_CONNECT, LED_OFF); cmsis_dap_usb_close(cmsis_dap_handle); return ERROR_OK; } -static void cmsis_dap_execute_reset(struct jtag_command *cmd) +static int cmsis_dap_reset(int trst, int srst) { /* Set both TRST and SRST even if they're not enabled as * there's no way to tristate them */ output_pins = 0; - if (!cmd->cmd.reset->srst) + if (!srst) output_pins |= SWJ_PIN_SRST; - if (!cmd->cmd.reset->trst) + if (!trst) output_pins |= SWJ_PIN_TRST; int retval = cmsis_dap_cmd_DAP_SWJ_Pins(output_pins, SWJ_PIN_TRST | SWJ_PIN_SRST, 0, NULL); if (retval != ERROR_OK) LOG_ERROR("CMSIS-DAP: Interface reset failed"); + return retval; } static void cmsis_dap_execute_sleep(struct jtag_command *cmd) @@ -1581,10 +1583,6 @@ static void cmsis_dap_execute_tms(struct jtag_command *cmd) static void cmsis_dap_execute_command(struct jtag_command *cmd) { switch (cmd->type) { - case JTAG_RESET: - cmsis_dap_flush(); - cmsis_dap_execute_reset(cmd); - break; case JTAG_SLEEP: cmsis_dap_flush(); cmsis_dap_execute_sleep(cmd); @@ -1631,10 +1629,10 @@ static int cmsis_dap_execute_queue(void) static int cmsis_dap_speed(int speed) { if (speed > DAP_MAX_CLOCK) - LOG_INFO("High speed (adapter_khz %d) may be limited by adapter firmware.", speed); + LOG_INFO("High speed (adapter speed %d) may be limited by adapter firmware.", speed); if (speed == 0) { - LOG_ERROR("RTCK not supported. Set nonzero adapter_khz."); + LOG_ERROR("RTCK not supported. Set nonzero \"adapter speed\"."); return ERROR_JTAG_NOT_IMPLEMENTED; } @@ -1789,17 +1787,23 @@ static const struct swd_driver cmsis_dap_swd_driver = { static const char * const cmsis_dap_transport[] = { "swd", "jtag", NULL }; -struct jtag_interface cmsis_dap_interface = { - .name = "cmsis-dap", +static struct jtag_interface cmsis_dap_interface = { .supported = DEBUG_CAP_TMS_SEQ, - .commands = cmsis_dap_command_handlers, - .swd = &cmsis_dap_swd_driver, + .execute_queue = cmsis_dap_execute_queue, +}; + +struct adapter_driver cmsis_dap_adapter_driver = { + .name = "cmsis-dap", .transports = cmsis_dap_transport, + .commands = cmsis_dap_command_handlers, - .execute_queue = cmsis_dap_execute_queue, - .speed = cmsis_dap_speed, - .speed_div = cmsis_dap_speed_div, - .khz = cmsis_dap_khz, .init = cmsis_dap_init, .quit = cmsis_dap_quit, + .reset = cmsis_dap_reset, + .speed = cmsis_dap_speed, + .khz = cmsis_dap_khz, + .speed_div = cmsis_dap_speed_div, + + .jtag_ops = &cmsis_dap_interface, + .swd_ops = &cmsis_dap_swd_driver, }; diff --git a/src/jtag/drivers/dummy.c b/src/jtag/drivers/dummy.c index 4e5b615..e66cb6b 100644 --- a/src/jtag/drivers/dummy.c +++ b/src/jtag/drivers/dummy.c @@ -91,7 +91,6 @@ static int dummy_led(int on) static struct bitbang_interface dummy_bitbang = { .read = &dummy_read, .write = &dummy_write, - .reset = &dummy_reset, .blink = &dummy_led, }; @@ -145,19 +144,22 @@ static const struct command_registration dummy_command_handlers[] = { /* The dummy driver is used to easily check the code path * where the target is unresponsive. */ -struct jtag_interface dummy_interface = { - .name = "dummy", - - .supported = DEBUG_CAP_TMS_SEQ, - .commands = dummy_command_handlers, - .transports = jtag_only, +static struct jtag_interface dummy_interface = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = &bitbang_execute_queue, +}; - .execute_queue = &bitbang_execute_queue, +struct adapter_driver dummy_adapter_driver = { + .name = "dummy", + .transports = jtag_only, + .commands = dummy_command_handlers, - .speed = &dummy_speed, - .khz = &dummy_khz, - .speed_div = &dummy_speed_div, + .init = &dummy_init, + .quit = &dummy_quit, + .reset = &dummy_reset, + .speed = &dummy_speed, + .khz = &dummy_khz, + .speed_div = &dummy_speed_div, - .init = &dummy_init, - .quit = &dummy_quit, - }; + .jtag_ops = &dummy_interface, +}; diff --git a/src/jtag/drivers/ep93xx.c b/src/jtag/drivers/ep93xx.c index 4cf3184..5e0e62a 100644 --- a/src/jtag/drivers/ep93xx.c +++ b/src/jtag/drivers/ep93xx.c @@ -50,21 +50,25 @@ static int ep93xx_quit(void); struct timespec ep93xx_zzzz; -struct jtag_interface ep93xx_interface = { - .name = "ep93xx", - +static struct jtag_interface ep93xx_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, +}; + +struct adapter_driver ep93xx_adapter_driver = { + .name = "ep93xx", .transports = jtag_only, .init = ep93xx_init, .quit = ep93xx_quit, + .reset = ep93xx_reset, + + .jtag_ops = &ep93xx_interface, }; static struct bitbang_interface ep93xx_bitbang = { .read = ep93xx_read, .write = ep93xx_write, - .reset = ep93xx_reset, .blink = 0, }; diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c index 8cda76e..c9ed304 100644 --- a/src/jtag/drivers/ft232r.c +++ b/src/jtag/drivers/ft232r.c @@ -29,7 +29,7 @@ #include <jtag/interface.h> #include <jtag/commands.h> #include <helper/time_support.h> -#include "libusb1_common.h" +#include "libusb_helper.h" /* system includes */ #include <string.h> @@ -71,7 +71,7 @@ static char *ft232r_serial_desc; static uint16_t ft232r_vid = 0x0403; /* FTDI */ static uint16_t ft232r_pid = 0x6001; /* FT232R */ -static jtag_libusb_device_handle *adapter; +static struct libusb_device_handle *adapter; static uint8_t *ft232r_output; static size_t ft232r_output_len; @@ -132,11 +132,11 @@ static int ft232r_send_recv(void) bytes_to_write = rxfifo_free; if (bytes_to_write) { - int n = jtag_libusb_bulk_write(adapter, IN_EP, - (char *) ft232r_output + total_written, - bytes_to_write, 1000); + int n; - if (n == 0) { + if (jtag_libusb_bulk_write(adapter, IN_EP, + (char *) ft232r_output + total_written, + bytes_to_write, 1000, &n) != ERROR_OK) { LOG_ERROR("usb bulk write failed"); return ERROR_JTAG_DEVICE_ERROR; } @@ -147,12 +147,10 @@ static int ft232r_send_recv(void) /* Read */ uint8_t reply[64]; + int n; - int n = jtag_libusb_bulk_read(adapter, OUT_EP, - (char *) reply, - sizeof(reply), 1000); - - if (n == 0) { + if (jtag_libusb_bulk_read(adapter, OUT_EP, (char *) reply, + sizeof(reply), 1000, &n) != ERROR_OK) { LOG_ERROR("usb bulk read failed"); return ERROR_JTAG_DEVICE_ERROR; } @@ -259,7 +257,7 @@ static int ft232r_init(void) { uint16_t avids[] = {ft232r_vid, 0}; uint16_t apids[] = {ft232r_pid, 0}; - if (jtag_libusb_open(avids, apids, ft232r_serial_desc, &adapter)) { + if (jtag_libusb_open(avids, apids, ft232r_serial_desc, &adapter, NULL)) { LOG_ERROR("ft232r not found: vid=%04x, pid=%04x, serial=%s\n", ft232r_vid, ft232r_pid, (ft232r_serial_desc == NULL) ? "[any]" : ft232r_serial_desc); return ERROR_JTAG_INIT_FAILED; @@ -270,7 +268,7 @@ static int ft232r_init(void) else /* serial port will be restored after jtag: */ libusb_set_auto_detach_kernel_driver(adapter, 1); /* 1: DONT_DETACH_SIO_MODULE */ - if (jtag_libusb_claim_interface(adapter, 0)) { + if (libusb_claim_interface(adapter, 0)) { LOG_ERROR("unable to claim interface"); return ERROR_JTAG_INIT_FAILED; } @@ -332,7 +330,7 @@ static int ft232r_quit(void) } } - if (jtag_libusb_release_interface(adapter, 0) != 0) + if (libusb_release_interface(adapter, 0) != 0) LOG_ERROR("usb release interface failed"); jtag_libusb_close(adapter); @@ -914,17 +912,21 @@ static int syncbb_execute_queue(void) return retval; } -struct jtag_interface ft232r_interface = { - .name = "ft232r", - .commands = ft232r_command_handlers, - .transports = jtag_only, +static struct jtag_interface ft232r_interface = { .supported = DEBUG_CAP_TMS_SEQ, - .execute_queue = syncbb_execute_queue, +}; + +struct adapter_driver ft232r_adapter_driver = { + .name = "ft232r", + .transports = jtag_only, + .commands = ft232r_command_handlers, - .speed = ft232r_speed, .init = ft232r_init, .quit = ft232r_quit, - .speed_div = ft232r_speed_div, + .speed = ft232r_speed, .khz = ft232r_khz, + .speed_div = ft232r_speed_div, + + .jtag_ops = &ft232r_interface, }; diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index ebe6016..34b42b8 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -249,7 +249,7 @@ static int ftdi_set_signal(const struct signal *s, char value) return ERROR_OK; } -static int ftdi_get_signal(const struct signal *s, uint16_t * value_out) +static int ftdi_get_signal(const struct signal *s, uint16_t *value_out) { uint8_t data_low = 0; uint8_t data_high = 0; @@ -582,46 +582,40 @@ static void ftdi_execute_scan(struct jtag_command *cmd) tap_state_name(tap_get_end_state())); } -static void ftdi_execute_reset(struct jtag_command *cmd) +static int ftdi_reset(int trst, int srst) { - LOG_DEBUG_IO("reset trst: %i srst %i", - cmd->cmd.reset->trst, cmd->cmd.reset->srst); - - if (cmd->cmd.reset->trst == 1 - || (cmd->cmd.reset->srst - && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) - tap_set_state(TAP_RESET); - - struct signal *trst = find_signal_by_name("nTRST"); - if (cmd->cmd.reset->trst == 1) { - if (trst) - ftdi_set_signal(trst, '0'); + struct signal *sig_ntrst = find_signal_by_name("nTRST"); + struct signal *sig_nsrst = find_signal_by_name("nSRST"); + + LOG_DEBUG_IO("reset trst: %i srst %i", trst, srst); + + if (trst == 1) { + if (sig_ntrst) + ftdi_set_signal(sig_ntrst, '0'); else LOG_ERROR("Can't assert TRST: nTRST signal is not defined"); - } else if (trst && jtag_get_reset_config() & RESET_HAS_TRST && - cmd->cmd.reset->trst == 0) { + } else if (sig_ntrst && jtag_get_reset_config() & RESET_HAS_TRST && + trst == 0) { if (jtag_get_reset_config() & RESET_TRST_OPEN_DRAIN) - ftdi_set_signal(trst, 'z'); + ftdi_set_signal(sig_ntrst, 'z'); else - ftdi_set_signal(trst, '1'); + ftdi_set_signal(sig_ntrst, '1'); } - struct signal *srst = find_signal_by_name("nSRST"); - if (cmd->cmd.reset->srst == 1) { - if (srst) - ftdi_set_signal(srst, '0'); + if (srst == 1) { + if (sig_nsrst) + ftdi_set_signal(sig_nsrst, '0'); else LOG_ERROR("Can't assert SRST: nSRST signal is not defined"); - } else if (srst && jtag_get_reset_config() & RESET_HAS_SRST && - cmd->cmd.reset->srst == 0) { + } else if (sig_nsrst && jtag_get_reset_config() & RESET_HAS_SRST && + srst == 0) { if (jtag_get_reset_config() & RESET_SRST_PUSH_PULL) - ftdi_set_signal(srst, '1'); + ftdi_set_signal(sig_nsrst, '1'); else - ftdi_set_signal(srst, 'z'); + ftdi_set_signal(sig_nsrst, 'z'); } - LOG_DEBUG_IO("trst: %i, srst: %i", - cmd->cmd.reset->trst, cmd->cmd.reset->srst); + return mpsse_flush(mpsse_ctx); } static void ftdi_execute_sleep(struct jtag_command *cmd) @@ -663,7 +657,6 @@ static void ftdi_execute_command(struct jtag_command *cmd) { switch (cmd->type) { case JTAG_RESET: - ftdi_execute_reset(cmd); #if BUILD_FTDI_OSCAN1 == 1 oscan1_reset_online_activate(); /* put the target back into OSCAN1 mode */ #endif @@ -727,6 +720,11 @@ static int ftdi_initialize(void) else LOG_DEBUG("ftdi interface using shortest path jtag state transitions"); + if (!ftdi_vid[0] && !ftdi_pid[0]) { + LOG_ERROR("Please specify ftdi_vid_pid"); + return ERROR_JTAG_INIT_FAILED; + } + for (int i = 0; ftdi_vid[i] || ftdi_pid[i]; i++) { mpsse_ctx = mpsse_open(&ftdi_vid[i], &ftdi_pid[i], ftdi_device_desc, ftdi_serial, jtag_usb_get_location(), ftdi_channel); @@ -1592,17 +1590,23 @@ static const struct swd_driver ftdi_swd = { static const char * const ftdi_transports[] = { "jtag", "swd", NULL }; -struct jtag_interface ftdi_interface = { - .name = "ftdi", +static struct jtag_interface ftdi_interface = { .supported = DEBUG_CAP_TMS_SEQ, - .commands = ftdi_command_handlers, + .execute_queue = ftdi_execute_queue, +}; + +struct adapter_driver ftdi_adapter_driver = { + .name = "ftdi", .transports = ftdi_transports, - .swd = &ftdi_swd, + .commands = ftdi_command_handlers, .init = ftdi_initialize, .quit = ftdi_quit, + .reset = ftdi_reset, .speed = ftdi_speed, - .speed_div = ftdi_speed_div, .khz = ftdi_khz, - .execute_queue = ftdi_execute_queue, + .speed_div = ftdi_speed_div, + + .jtag_ops = &ftdi_interface, + .swd_ops = &ftdi_swd, }; diff --git a/src/jtag/drivers/gw16012.c b/src/jtag/drivers/gw16012.c index e65f56c..d1699ef 100644 --- a/src/jtag/drivers/gw16012.c +++ b/src/jtag/drivers/gw16012.c @@ -350,7 +350,7 @@ static int gw16012_get_giveio_access(void) HANDLE h; OSVERSIONINFO version; - version.dwOSVersionInfoSize = sizeof version; + version.dwOSVersionInfoSize = sizeof(version); if (!GetVersionEx(&version)) { errno = EINVAL; return -1; @@ -448,7 +448,7 @@ static int gw16012_init_device(void) LOG_WARNING("No gw16012 port specified, using default '0x378' (LPT1)"); } - LOG_DEBUG("requesting privileges for parallel port 0x%lx...", (long unsigned)(gw16012_port)); + LOG_DEBUG("requesting privileges for parallel port 0x%" PRIx16 "...", gw16012_port); #if PARPORT_USE_GIVEIO == 1 if (gw16012_get_giveio_access() != 0) { #else /* PARPORT_USE_GIVEIO */ @@ -521,12 +521,17 @@ static const struct command_registration gw16012_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct jtag_interface gw16012_interface = { +static struct jtag_interface gw16012_interface = { + .execute_queue = gw16012_execute_queue, +}; + +struct adapter_driver gw16012_adapter_driver = { .name = "gw16012", .transports = jtag_only, .commands = gw16012_command_handlers, .init = gw16012_init, .quit = gw16012_quit, - .execute_queue = gw16012_execute_queue, + + .jtag_ops = &gw16012_interface, }; diff --git a/src/jtag/drivers/imx_gpio.c b/src/jtag/drivers/imx_gpio.c index 4923dab..7dcfb67 100644 --- a/src/jtag/drivers/imx_gpio.c +++ b/src/jtag/drivers/imx_gpio.c @@ -84,7 +84,6 @@ static inline bool gpio_level(int g) static bb_value_t imx_gpio_read(void); static int imx_gpio_write(int tck, int tms, int tdi); -static int imx_gpio_reset(int trst, int srst); static int imx_gpio_swdio_read(void); static void imx_gpio_swdio_drive(bool is_output); @@ -95,7 +94,6 @@ static int imx_gpio_quit(void); static struct bitbang_interface imx_gpio_bitbang = { .read = imx_gpio_read, .write = imx_gpio_write, - .reset = imx_gpio_reset, .swdio_read = imx_gpio_swdio_read, .swdio_drive = imx_gpio_swdio_drive, .blink = NULL @@ -429,18 +427,25 @@ static const struct command_registration imx_gpio_command_handlers[] = { static const char * const imx_gpio_transports[] = { "jtag", "swd", NULL }; -struct jtag_interface imx_gpio_interface = { - .name = "imx_gpio", +static struct jtag_interface imx_gpio_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, +}; + +struct adapter_driver imx_gpio_adapter_driver = { + .name = "imx_gpio", .transports = imx_gpio_transports, - .swd = &bitbang_swd, - .speed = imx_gpio_speed, - .khz = imx_gpio_khz, - .speed_div = imx_gpio_speed_div, .commands = imx_gpio_command_handlers, + .init = imx_gpio_init, .quit = imx_gpio_quit, + .reset = imx_gpio_reset, + .speed = imx_gpio_speed, + .khz = imx_gpio_khz, + .speed_div = imx_gpio_speed_div, + + .jtag_ops = &imx_gpio_interface, + .swd_ops = &bitbang_swd, }; static bool imx_gpio_jtag_mode_possible(void) diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 09b3a85..1baf345 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -39,6 +39,7 @@ #include <jtag/swd.h> #include <jtag/commands.h> #include <jtag/drivers/jtag_usb_common.h> +#include <target/cortex_m.h> #include <libjaylink/libjaylink.h> @@ -62,6 +63,9 @@ static bool trace_enabled; static unsigned int swd_buffer_size = JLINK_TAP_BUFFER_SIZE; +/* Maximum SWO frequency deviation. */ +#define SWO_MAX_FREQ_DEV 0.03 + /* 256 byte non-volatile memory */ struct device_config { uint8_t usb_address; @@ -90,6 +94,7 @@ static void jlink_path_move(int num_states, tap_state_t *path); static void jlink_stableclocks(int num_cycles); static void jlink_runtest(int num_cycles); static void jlink_reset(int trst, int srst); +static int jlink_reset_safe(int trst, int srst); static int jlink_swd_run_queue(void); static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk); static int jlink_swd_switch_seq(enum swd_special_seq seq); @@ -247,16 +252,6 @@ static void jlink_execute_scan(struct jtag_command *cmd) tap_state_name(tap_get_end_state())); } -static void jlink_execute_reset(struct jtag_command *cmd) -{ - LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, - cmd->cmd.reset->srst); - - jlink_flush(); - jlink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - jlink_flush(); -} - static void jlink_execute_sleep(struct jtag_command *cmd) { LOG_DEBUG_IO("sleep %" PRIi32 "", cmd->cmd.sleep->us); @@ -282,9 +277,6 @@ static int jlink_execute_command(struct jtag_command *cmd) case JTAG_SCAN: jlink_execute_scan(cmd); break; - case JTAG_RESET: - jlink_execute_reset(cmd); - break; case JTAG_SLEEP: jlink_execute_sleep(cmd); break; @@ -952,6 +944,13 @@ static void jlink_reset(int trst, int srst) jaylink_jtag_set_trst(devh); } +static int jlink_reset_safe(int trst, int srst) +{ + jlink_flush(); + jlink_reset(trst, srst); + return jlink_flush(); +} + COMMAND_HANDLER(jlink_usb_command) { int tmp; @@ -1267,55 +1266,74 @@ static uint32_t calculate_trace_buffer_size(void) return tmp & 0xffffff00; } -static bool check_trace_freq(struct jaylink_swo_speed speed, - uint32_t trace_freq) +static bool calculate_swo_prescaler(unsigned int traceclkin_freq, + uint32_t trace_freq, uint16_t *prescaler) { - double min; + unsigned int presc; double deviation; + + presc = ((1.0 - SWO_MAX_FREQ_DEV) * traceclkin_freq) / trace_freq + 1; + + if (presc > TPIU_ACPR_MAX_SWOSCALER) + return false; + + deviation = fabs(1.0 - ((double)trace_freq * presc / traceclkin_freq)); + + if (deviation > SWO_MAX_FREQ_DEV) + return false; + + *prescaler = presc; + + return true; +} + +static bool detect_swo_freq_and_prescaler(struct jaylink_swo_speed speed, + unsigned int traceclkin_freq, uint32_t *trace_freq, + uint16_t *prescaler) +{ uint32_t divider; + unsigned int presc; + double deviation; + + for (divider = speed.min_div; divider <= speed.max_div; divider++) { + *trace_freq = speed.freq / divider; + presc = ((1.0 - SWO_MAX_FREQ_DEV) * traceclkin_freq) / *trace_freq + 1; - min = fabs(1.0 - (speed.freq / ((double)trace_freq * speed.min_div))); + if (presc > TPIU_ACPR_MAX_SWOSCALER) + break; - for (divider = speed.min_div; divider < speed.max_div; divider++) { - deviation = fabs(1.0 - (speed.freq / ((double)trace_freq * divider))); + deviation = fabs(1.0 - ((double)*trace_freq * presc / traceclkin_freq)); - if (deviation < 0.03) { - LOG_DEBUG("Found suitable frequency divider %u with deviation of " - "%.02f %%.", divider, deviation); + if (deviation <= SWO_MAX_FREQ_DEV) { + *prescaler = presc; return true; } - - if (deviation < min) - min = deviation; } - LOG_ERROR("Selected trace frequency is not supported by the device. " - "Please choose a different trace frequency."); - LOG_ERROR("Maximum permitted deviation is 3.00 %%, but only %.02f %% " - "could be achieved.", min * 100); - return false; } static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, - uint32_t port_size, unsigned int *trace_freq) + uint32_t port_size, unsigned int *trace_freq, + unsigned int traceclkin_freq, uint16_t *prescaler) { int ret; uint32_t buffer_size; struct jaylink_swo_speed speed; + uint32_t divider; + uint32_t min_freq; + uint32_t max_freq; + + trace_enabled = enabled; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SWO)) { - LOG_ERROR("Trace capturing is not supported by the device."); - return ERROR_FAIL; - } + if (!enabled) + return ERROR_OK; - if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) { - LOG_ERROR("Selected pin protocol is not supported."); + LOG_ERROR("Trace capturing is not supported by the device."); return ERROR_FAIL; } - trace_enabled = enabled; - ret = jaylink_swo_stop(devh); if (ret != JAYLINK_OK) { @@ -1334,6 +1352,11 @@ static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, return ERROR_OK; } + if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) { + LOG_ERROR("Selected pin protocol is not supported."); + return ERROR_FAIL; + } + buffer_size = calculate_trace_buffer_size(); if (!buffer_size) { @@ -1349,13 +1372,45 @@ static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, return ERROR_FAIL; } - if (!*trace_freq) - *trace_freq = speed.freq / speed.min_div; + if (*trace_freq > 0) { + divider = speed.freq / *trace_freq; + min_freq = speed.freq / speed.max_div; + max_freq = speed.freq / speed.min_div; + + if (*trace_freq > max_freq) { + LOG_INFO("Given SWO frequency too high, using %u Hz instead.", + max_freq); + *trace_freq = max_freq; + } else if (*trace_freq < min_freq) { + LOG_INFO("Given SWO frequency too low, using %u Hz instead.", + min_freq); + *trace_freq = min_freq; + } else if (*trace_freq != speed.freq / divider) { + *trace_freq = speed.freq / divider; + + LOG_INFO("Given SWO frequency is not supported by the device, " + "using %u Hz instead.", *trace_freq); + } - if (!check_trace_freq(speed, *trace_freq)) - return ERROR_FAIL; + if (!calculate_swo_prescaler(traceclkin_freq, *trace_freq, + prescaler)) { + LOG_ERROR("SWO frequency is not suitable. Please choose a " + "different frequency or use auto-detection."); + return ERROR_FAIL; + } + } else { + LOG_INFO("Trying to auto-detect SWO frequency."); - LOG_DEBUG("Using %u bytes device memory for trace capturing.", buffer_size); + if (!detect_swo_freq_and_prescaler(speed, traceclkin_freq, trace_freq, + prescaler)) { + LOG_ERROR("Maximum permitted frequency deviation of %.02f %% " + "could not be achieved.", SWO_MAX_FREQ_DEV); + LOG_ERROR("Auto-detection of SWO frequency failed."); + return ERROR_FAIL; + } + + LOG_INFO("Using SWO frequency of %u Hz.", *trace_freq); + } ret = jaylink_swo_start(devh, JAYLINK_SWO_MODE_UART, *trace_freq, buffer_size); @@ -1365,6 +1420,9 @@ static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, return ERROR_FAIL; } + LOG_DEBUG("Using %u bytes device memory for trace capturing.", + buffer_size); + /* * Adjust the SWD transaction buffer size as starting SWO capturing * allocates device internal memory. @@ -1470,7 +1528,7 @@ COMMAND_HANDLER(jlink_handle_config_mac_address_command) } else if (CMD_ARGC == 1) { str = CMD_ARGV[0]; - if ((strlen(str) != 17) || (str[2] != ':' || str[5] != ':' || \ + if ((strlen(str) != 17) || (str[2] != ':' || str[5] != ':' || str[8] != ':' || str[11] != ':' || str[14] != ':')) { command_print(CMD, "Invalid MAC address format."); return ERROR_COMMAND_SYNTAX_ERROR; @@ -2212,17 +2270,24 @@ static const struct swd_driver jlink_swd = { static const char * const jlink_transports[] = { "jtag", "swd", NULL }; -struct jtag_interface jlink_interface = { +static struct jtag_interface jlink_interface = { + .execute_queue = &jlink_execute_queue, +}; + +struct adapter_driver jlink_adapter_driver = { .name = "jlink", - .commands = jlink_command_handlers, .transports = jlink_transports, - .swd = &jlink_swd, - .execute_queue = &jlink_execute_queue, - .speed = &jlink_speed, - .speed_div = &jlink_speed_div, - .khz = &jlink_khz, + .commands = jlink_command_handlers, + .init = &jlink_init, .quit = &jlink_quit, + .reset = &jlink_reset_safe, + .speed = &jlink_speed, + .khz = &jlink_khz, + .speed_div = &jlink_speed_div, .config_trace = &config_trace, .poll_trace = &poll_trace, + + .jtag_ops = &jlink_interface, + .swd_ops = &jlink_swd, }; diff --git a/src/jtag/drivers/jtag_vpi.c b/src/jtag/drivers/jtag_vpi.c index 1033ced..a5a95a5 100644 --- a/src/jtag/drivers/jtag_vpi.c +++ b/src/jtag/drivers/jtag_vpi.c @@ -33,6 +33,8 @@ #include <netinet/tcp.h> #endif +#include <string.h> + #define NO_TAP_SHIFT 0 #define TAP_SHIFT 1 @@ -47,34 +49,160 @@ #define CMD_SCAN_CHAIN_FLIP_TMS 3 #define CMD_STOP_SIMU 4 -int server_port = SERVER_PORT; -char *server_address; +/* jtag_vpi server port and address to connect to */ +static int server_port = SERVER_PORT; +static char *server_address; + +/* Send CMD_STOP_SIMU to server when OpenOCD exits? */ +static bool stop_sim_on_exit; -int sockfd; -struct sockaddr_in serv_addr; +static int sockfd; +static struct sockaddr_in serv_addr; +/* One jtag_vpi "packet" as sent over a TCP channel. */ struct vpi_cmd { - int cmd; + union { + uint32_t cmd; + unsigned char cmd_buf[4]; + }; unsigned char buffer_out[XFERT_MAX_SIZE]; unsigned char buffer_in[XFERT_MAX_SIZE]; - int length; - int nb_bits; + union { + uint32_t length; + unsigned char length_buf[4]; + }; + union { + uint32_t nb_bits; + unsigned char nb_bits_buf[4]; + }; }; +static char *jtag_vpi_cmd_to_str(int cmd_num) +{ + switch (cmd_num) { + case CMD_RESET: + return "CMD_RESET"; + case CMD_TMS_SEQ: + return "CMD_TMS_SEQ"; + case CMD_SCAN_CHAIN: + return "CMD_SCAN_CHAIN"; + case CMD_SCAN_CHAIN_FLIP_TMS: + return "CMD_SCAN_CHAIN_FLIP_TMS"; + case CMD_STOP_SIMU: + return "CMD_STOP_SIMU"; + default: + return "<unknown>"; + } +} + static int jtag_vpi_send_cmd(struct vpi_cmd *vpi) { - int retval = write_socket(sockfd, vpi, sizeof(struct vpi_cmd)); - if (retval <= 0) - return ERROR_FAIL; + int retval; + + /* Optional low-level JTAG debug */ + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { + if (vpi->nb_bits > 0) { + /* command with a non-empty data payload */ + char *char_buf = buf_to_str(vpi->buffer_out, + (vpi->nb_bits > DEBUG_JTAG_IOZ) + ? DEBUG_JTAG_IOZ + : vpi->nb_bits, + 16); + LOG_DEBUG_IO("sending JTAG VPI cmd: cmd=%s, " + "length=%" PRIu32 ", " + "nb_bits=%" PRIu32 ", " + "buf_out=0x%s%s", + jtag_vpi_cmd_to_str(vpi->cmd), + vpi->length, + vpi->nb_bits, + char_buf, + (vpi->nb_bits > DEBUG_JTAG_IOZ) ? "(...)" : ""); + free(char_buf); + } else { + /* command without data payload */ + LOG_DEBUG_IO("sending JTAG VPI cmd: cmd=%s, " + "length=%" PRIu32 ", " + "nb_bits=%" PRIu32, + jtag_vpi_cmd_to_str(vpi->cmd), + vpi->length, + vpi->nb_bits); + } + } + /* Use little endian when transmitting/receiving jtag_vpi cmds. + The choice of little endian goes against usual networking conventions + but is intentional to remain compatible with most older OpenOCD builds + (i.e. builds on little-endian platforms). */ + h_u32_to_le(vpi->cmd_buf, vpi->cmd); + h_u32_to_le(vpi->length_buf, vpi->length); + h_u32_to_le(vpi->nb_bits_buf, vpi->nb_bits); + +retry_write: + retval = write_socket(sockfd, vpi, sizeof(struct vpi_cmd)); + + if (retval < 0) { + /* Account for the case when socket write is interrupted. */ +#ifdef _WIN32 + int wsa_err = WSAGetLastError(); + if (wsa_err == WSAEINTR) + goto retry_write; +#else + if (errno == EINTR) + goto retry_write; +#endif + /* Otherwise this is an error using the socket, most likely fatal + for the connection. B*/ + log_socket_error("jtag_vpi xmit"); + /* TODO: Clean way how adapter drivers can report fatal errors + to upper layers of OpenOCD and let it perform an orderly shutdown? */ + exit(-1); + } else if (retval < (int)sizeof(struct vpi_cmd)) { + /* This means we could not send all data, which is most likely fatal + for the jtag_vpi connection (the underlying TCP connection likely not + usable anymore) */ + LOG_ERROR("Could not send all data through jtag_vpi connection."); + exit(-1); + } + + /* Otherwise the packet has been sent successfully. */ return ERROR_OK; } static int jtag_vpi_receive_cmd(struct vpi_cmd *vpi) { - int retval = read_socket(sockfd, vpi, sizeof(struct vpi_cmd)); - if (retval < (int)sizeof(struct vpi_cmd)) - return ERROR_FAIL; + unsigned bytes_buffered = 0; + while (bytes_buffered < sizeof(struct vpi_cmd)) { + int bytes_to_receive = sizeof(struct vpi_cmd) - bytes_buffered; + int retval = read_socket(sockfd, ((char *)vpi) + bytes_buffered, bytes_to_receive); + if (retval < 0) { +#ifdef _WIN32 + int wsa_err = WSAGetLastError(); + if (wsa_err == WSAEINTR) { + /* socket read interrupted by WSACancelBlockingCall() */ + continue; + } +#else + if (errno == EINTR) { + /* socket read interrupted by a signal */ + continue; + } +#endif + /* Otherwise, this is an error when accessing the socket. */ + log_socket_error("jtag_vpi recv"); + exit(-1); + } else if (retval == 0) { + /* Connection closed by the other side */ + LOG_ERROR("Connection prematurely closed by jtag_vpi server."); + exit(-1); + } + /* Otherwise, we have successfully received some data */ + bytes_buffered += retval; + } + + /* Use little endian when transmitting/receiving jtag_vpi cmds. */ + vpi->cmd = le_to_h_u32(vpi->cmd_buf); + vpi->length = le_to_h_u32(vpi->length_buf); + vpi->nb_bits = le_to_h_u32(vpi->nb_bits_buf); return ERROR_OK; } @@ -87,6 +215,7 @@ static int jtag_vpi_receive_cmd(struct vpi_cmd *vpi) static int jtag_vpi_reset(int trst, int srst) { struct vpi_cmd vpi; + memset(&vpi, 0, sizeof(struct vpi_cmd)); vpi.cmd = CMD_RESET; vpi.length = 0; @@ -109,6 +238,7 @@ static int jtag_vpi_tms_seq(const uint8_t *bits, int nb_bits) struct vpi_cmd vpi; int nb_bytes; + memset(&vpi, 0, sizeof(struct vpi_cmd)); nb_bytes = DIV_ROUND_UP(nb_bits, 8); vpi.cmd = CMD_TMS_SEQ; @@ -176,6 +306,8 @@ static int jtag_vpi_queue_tdi_xfer(uint8_t *bits, int nb_bits, int tap_shift) struct vpi_cmd vpi; int nb_bytes = DIV_ROUND_UP(nb_bits, 8); + memset(&vpi, 0, sizeof(struct vpi_cmd)); + vpi.cmd = tap_shift ? CMD_SCAN_CHAIN_FLIP_TMS : CMD_SCAN_CHAIN; if (bits) @@ -194,6 +326,16 @@ static int jtag_vpi_queue_tdi_xfer(uint8_t *bits, int nb_bits, int tap_shift) if (retval != ERROR_OK) return retval; + /* Optional low-level JTAG debug */ + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { + char *char_buf = buf_to_str(vpi.buffer_in, + (nb_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : nb_bits, + 16); + LOG_DEBUG_IO("recvd JTAG VPI data: nb_bits=%d, buf_in=0x%s%s", + nb_bits, char_buf, (nb_bits > DEBUG_JTAG_IOZ) ? "(...)" : ""); + free(char_buf); + } + if (bits) memcpy(bits, vpi.buffer_in, nb_bytes); @@ -384,6 +526,11 @@ static int jtag_vpi_execute_queue(void) case JTAG_SCAN: retval = jtag_vpi_scan(cmd->cmd.scan); break; + default: + LOG_ERROR("BUG: unknown JTAG command type 0x%X", + cmd->type); + retval = ERROR_FAIL; + break; } } @@ -433,10 +580,28 @@ static int jtag_vpi_init(void) return ERROR_OK; } +static int jtag_vpi_stop_simulation(void) +{ + struct vpi_cmd cmd; + memset(&cmd, 0, sizeof(struct vpi_cmd)); + cmd.length = 0; + cmd.nb_bits = 0; + cmd.cmd = CMD_STOP_SIMU; + return jtag_vpi_send_cmd(&cmd); +} + static int jtag_vpi_quit(void) { + if (stop_sim_on_exit) { + if (jtag_vpi_stop_simulation() != ERROR_OK) + LOG_WARNING("jtag_vpi: failed to send \"stop simulation\" command"); + } + if (close_socket(sockfd) != 0) { + LOG_WARNING("jtag_vpi: could not close jtag_vpi client socket"); + log_socket_error("jtag_vpi"); + } free(server_address); - return close(sockfd); + return ERROR_OK; } COMMAND_HANDLER(jtag_vpi_set_port) @@ -466,31 +631,55 @@ COMMAND_HANDLER(jtag_vpi_set_address) return ERROR_OK; } +COMMAND_HANDLER(jtag_vpi_stop_sim_on_exit_handler) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("jtag_vpi_stop_sim_on_exit expects 1 argument (on|off)"); + return ERROR_COMMAND_SYNTAX_ERROR; + } else { + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], stop_sim_on_exit); + } + return ERROR_OK; +} + static const struct command_registration jtag_vpi_command_handlers[] = { { .name = "jtag_vpi_set_port", .handler = &jtag_vpi_set_port, .mode = COMMAND_CONFIG, .help = "set the port of the VPI server", - .usage = "description_string", + .usage = "tcp_port_num", }, { .name = "jtag_vpi_set_address", .handler = &jtag_vpi_set_address, .mode = COMMAND_CONFIG, .help = "set the address of the VPI server", - .usage = "description_string", + .usage = "ipv4_addr", + }, + { + .name = "jtag_vpi_stop_sim_on_exit", + .handler = &jtag_vpi_stop_sim_on_exit_handler, + .mode = COMMAND_CONFIG, + .help = "Configure if simulation stop command shall be sent " + "before OpenOCD exits (default: off)", + .usage = "<on|off>", }, COMMAND_REGISTRATION_DONE }; -struct jtag_interface jtag_vpi_interface = { - .name = "jtag_vpi", +static struct jtag_interface jtag_vpi_interface = { .supported = DEBUG_CAP_TMS_SEQ, - .commands = jtag_vpi_command_handlers, + .execute_queue = jtag_vpi_execute_queue, +}; + +struct adapter_driver jtag_vpi_adapter_driver = { + .name = "jtag_vpi", .transports = jtag_only, + .commands = jtag_vpi_command_handlers, .init = jtag_vpi_init, .quit = jtag_vpi_quit, - .execute_queue = jtag_vpi_execute_queue, + + .jtag_ops = &jtag_vpi_interface, }; diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c index e3ad84d..efb8da2 100644 --- a/src/jtag/drivers/kitprog.c +++ b/src/jtag/drivers/kitprog.c @@ -43,7 +43,7 @@ #include <jtag/swd.h> #include <jtag/commands.h> -#include "libusb_common.h" +#include "libusb_helper.h" #define VID 0x04b4 #define PID 0xf139 @@ -95,7 +95,7 @@ struct kitprog { hid_device *hid_handle; - struct jtag_libusb_device_handle *usb_handle; + struct libusb_device_handle *usb_handle; uint16_t packet_size; uint16_t packet_index; uint8_t *packet_buffer; @@ -280,7 +280,7 @@ static int kitprog_usb_open(void) const uint16_t pids[] = { PID, 0 }; if (jtag_libusb_open(vids, pids, kitprog_serial, - &kitprog_handle->usb_handle) != ERROR_OK) { + &kitprog_handle->usb_handle, NULL) != ERROR_OK) { LOG_ERROR("Failed to open or find the device"); return ERROR_FAIL; } @@ -311,7 +311,7 @@ static int kitprog_usb_open(void) } /* Claim the KitProg Programmer (bulk transfer) interface */ - if (jtag_libusb_claim_interface(kitprog_handle->usb_handle, 1) != ERROR_OK) { + if (libusb_claim_interface(kitprog_handle->usb_handle, 1) != ERROR_OK) { LOG_ERROR("Failed to claim KitProg Programmer (bulk transfer) interface"); return ERROR_FAIL; } @@ -358,7 +358,7 @@ static int kitprog_get_version(void) unsigned char command[3] = {HID_TYPE_START | HID_TYPE_WRITE, 0x00, HID_COMMAND_VERSION}; unsigned char data[64]; - ret = kitprog_hid_command(command, sizeof command, data, sizeof data); + ret = kitprog_hid_command(command, sizeof(command), data, sizeof(data)); if (ret != ERROR_OK) return ret; @@ -376,7 +376,7 @@ static int kitprog_get_millivolts(void) unsigned char command[3] = {HID_TYPE_START | HID_TYPE_READ, 0x00, HID_COMMAND_POWER}; unsigned char data[64]; - ret = kitprog_hid_command(command, sizeof command, data, sizeof data); + ret = kitprog_hid_command(command, sizeof(command), data, sizeof(data)); if (ret != ERROR_OK) return ret; @@ -603,7 +603,7 @@ static int kitprog_generic_acquire(void) * will take the Cortex-M3 out of reset and enable debugging. */ for (int i = 0; i < 2; i++) { - for (uint8_t j = 0; j < sizeof devices && acquire_count == i; j++) { + for (uint8_t j = 0; j < sizeof(devices) && acquire_count == i; j++) { retval = kitprog_acquire_psoc(devices[j], ACQUIRE_MODE_RESET, 3); if (retval != ERROR_OK) { LOG_DEBUG("Aquisition function failed for device 0x%02x.", devices[j]); @@ -731,14 +731,14 @@ static int kitprog_swd_run_queue(void) } } - ret = jtag_libusb_bulk_write(kitprog_handle->usb_handle, - BULK_EP_OUT, (char *)buffer, write_count, 0); - if (ret > 0) { - queued_retval = ERROR_OK; - } else { + if (jtag_libusb_bulk_write(kitprog_handle->usb_handle, + BULK_EP_OUT, (char *)buffer, + write_count, 0, &ret)) { LOG_ERROR("Bulk write failed"); queued_retval = ERROR_FAIL; break; + } else { + queued_retval = ERROR_OK; } /* KitProg firmware does not send a zero length packet @@ -754,18 +754,17 @@ static int kitprog_swd_run_queue(void) if (read_count % 64 == 0) read_count_workaround = read_count; - ret = jtag_libusb_bulk_read(kitprog_handle->usb_handle, + if (jtag_libusb_bulk_read(kitprog_handle->usb_handle, BULK_EP_IN | LIBUSB_ENDPOINT_IN, (char *)buffer, - read_count_workaround, 1000); - if (ret > 0) { + read_count_workaround, 1000, &ret)) { + LOG_ERROR("Bulk read failed"); + queued_retval = ERROR_FAIL; + break; + } else { /* Handle garbage data by offsetting the initial read index */ if ((unsigned int)ret > read_count) read_index = ret - read_count; queued_retval = ERROR_OK; - } else { - LOG_ERROR("Bulk read failed"); - queued_retval = ERROR_FAIL; - break; } for (int i = 0; i < pending_transfer_count; i++) { @@ -819,11 +818,16 @@ static void kitprog_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data) /*************** jtag lowlevel functions ********************/ -static void kitprog_execute_reset(struct jtag_command *cmd) +static int kitprog_reset(int trst, int srst) { int retval = ERROR_OK; - if (cmd->cmd.reset->srst == 1) { + if (trst == 1) { + LOG_ERROR("KitProg: Interface has no TRST"); + return ERROR_FAIL; + } + + if (srst == 1) { retval = kitprog_reset_target(); /* Since the previous command also disables SWCLK output, we need to send an * SWD bus reset command to re-enable it. For some reason, running @@ -836,38 +840,7 @@ static void kitprog_execute_reset(struct jtag_command *cmd) if (retval != ERROR_OK) LOG_ERROR("KitProg: Interface reset failed"); -} - -static void kitprog_execute_sleep(struct jtag_command *cmd) -{ - jtag_sleep(cmd->cmd.sleep->us); -} - -static void kitprog_execute_command(struct jtag_command *cmd) -{ - switch (cmd->type) { - case JTAG_RESET: - kitprog_execute_reset(cmd); - break; - case JTAG_SLEEP: - kitprog_execute_sleep(cmd); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); - } -} - -static int kitprog_execute_queue(void) -{ - struct jtag_command *cmd = jtag_command_queue; - - while (cmd != NULL) { - kitprog_execute_command(cmd); - cmd = cmd->next; - } - - return ERROR_OK; + return retval; } COMMAND_HANDLER(kitprog_handle_info_command) @@ -961,12 +934,14 @@ static const struct swd_driver kitprog_swd = { static const char * const kitprog_transports[] = { "swd", NULL }; -struct jtag_interface kitprog_interface = { +struct adapter_driver kitprog_adapter_driver = { .name = "kitprog", - .commands = kitprog_command_handlers, .transports = kitprog_transports, - .swd = &kitprog_swd, - .execute_queue = kitprog_execute_queue, + .commands = kitprog_command_handlers, + .init = kitprog_init, - .quit = kitprog_quit + .quit = kitprog_quit, + .reset = kitprog_reset, + + .swd_ops = &kitprog_swd, }; diff --git a/src/jtag/drivers/libusb0_common.c b/src/jtag/drivers/libusb0_common.c deleted file mode 100644 index 14a8b61..0000000 --- a/src/jtag/drivers/libusb0_common.c +++ /dev/null @@ -1,196 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> * - * * - * Copyright (C) 2011 by Mauro Gamba <maurillo71@gmail.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 "log.h" -#include "libusb0_common.h" - -static bool jtag_libusb_match(struct jtag_libusb_device *dev, - const uint16_t vids[], const uint16_t pids[]) -{ - for (unsigned i = 0; vids[i]; i++) { - if (dev->descriptor.idVendor == vids[i] && - dev->descriptor.idProduct == pids[i]) { - return true; - } - } - return false; -} - -/* Returns true if the string descriptor indexed by str_index in device matches string */ -static bool string_descriptor_equal(usb_dev_handle *device, uint8_t str_index, - const char *string) -{ - int retval; - bool matched; - char desc_string[256+1]; /* Max size of string descriptor */ - - if (str_index == 0) - return false; - - retval = usb_get_string_simple(device, str_index, - desc_string, sizeof(desc_string)-1); - if (retval < 0) { - LOG_ERROR("usb_get_string_simple() failed with %d", retval); - return false; - } - - /* Null terminate descriptor string in case it needs to be logged. */ - desc_string[sizeof(desc_string)-1] = '\0'; - - matched = strncmp(string, desc_string, sizeof(desc_string)) == 0; - if (!matched) - LOG_DEBUG("Device serial number '%s' doesn't match requested serial '%s'", - desc_string, string); - return matched; -} - -int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], - const char *serial, - struct jtag_libusb_device_handle **out) -{ - int retval = ERROR_FAIL; - bool serial_mismatch = false; - struct jtag_libusb_device_handle *libusb_handle; - usb_init(); - - usb_find_busses(); - usb_find_devices(); - - struct usb_bus *busses = usb_get_busses(); - for (struct usb_bus *bus = busses; bus; bus = bus->next) { - for (struct usb_device *dev = bus->devices; - dev; dev = dev->next) { - if (!jtag_libusb_match(dev, vids, pids)) - continue; - - libusb_handle = usb_open(dev); - if (NULL == libusb_handle) { - LOG_ERROR("usb_open() failed with %s", usb_strerror()); - continue; - } - - /* Device must be open to use libusb_get_string_descriptor_ascii. */ - if (serial != NULL && - !string_descriptor_equal(libusb_handle, dev->descriptor.iSerialNumber, serial)) { - serial_mismatch = true; - usb_close(libusb_handle); - continue; - } - *out = libusb_handle; - retval = ERROR_OK; - serial_mismatch = false; - break; - } - } - - if (serial_mismatch) - LOG_INFO("No device matches the serial string"); - - return retval; -} - -void jtag_libusb_close(jtag_libusb_device_handle *dev) -{ - /* Close device */ - usb_close(dev); -} - -int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, uint8_t requestType, - uint8_t request, uint16_t wValue, uint16_t wIndex, char *bytes, - uint16_t size, unsigned int timeout) -{ - int transferred = 0; - - transferred = usb_control_msg(dev, requestType, request, wValue, wIndex, - bytes, size, timeout); - - if (transferred < 0) - transferred = 0; - - return transferred; -} - -int jtag_libusb_bulk_write(jtag_libusb_device_handle *dev, int ep, char *bytes, - int size, int timeout) -{ - return usb_bulk_write(dev, ep, bytes, size, timeout); -} - -int jtag_libusb_bulk_read(jtag_libusb_device_handle *dev, int ep, char *bytes, - int size, int timeout) -{ - return usb_bulk_read(dev, ep, bytes, size, timeout); -} - -int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh, - int configuration) -{ - struct jtag_libusb_device *udev = jtag_libusb_get_device(devh); - - return usb_set_configuration(devh, - udev->config[configuration].bConfigurationValue); -} - -int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh, - unsigned int *usb_read_ep, - unsigned int *usb_write_ep, - int bclass, int subclass, int protocol, int trans_type) -{ - struct jtag_libusb_device *udev = jtag_libusb_get_device(devh); - struct usb_interface *iface = udev->config->interface; - struct usb_interface_descriptor *desc = iface->altsetting; - - *usb_read_ep = *usb_write_ep = 0; - - for (int i = 0; i < desc->bNumEndpoints; i++) { - if ((bclass > 0 && desc->bInterfaceClass != bclass) || - (subclass > 0 && desc->bInterfaceSubClass != subclass) || - (protocol > 0 && desc->bInterfaceProtocol != protocol) || - (trans_type > 0 && (desc->endpoint[i].bmAttributes & 0x3) != trans_type)) - continue; - - uint8_t epnum = desc->endpoint[i].bEndpointAddress; - bool is_input = epnum & 0x80; - LOG_DEBUG("usb ep %s %02x", is_input ? "in" : "out", epnum); - if (is_input) - *usb_read_ep = epnum; - else - *usb_write_ep = epnum; - - if (*usb_read_ep && *usb_write_ep) { - LOG_DEBUG("Claiming interface %d", (int)desc->bInterfaceNumber); - usb_claim_interface(devh, (int)desc->bInterfaceNumber); - return ERROR_OK; - } - } - - return ERROR_FAIL; -} - -int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid) -{ - if (!dev) - return ERROR_FAIL; - - *pid = dev->descriptor.idProduct; - return ERROR_OK; -} diff --git a/src/jtag/drivers/libusb0_common.h b/src/jtag/drivers/libusb0_common.h deleted file mode 100644 index 676f43a..0000000 --- a/src/jtag/drivers/libusb0_common.h +++ /dev/null @@ -1,74 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> * - * * - * Copyright (C) 2011 by Mauro Gamba <maurillo71@gmail.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_JTAG_DRIVERS_LIBUSB0_COMMON_H -#define OPENOCD_JTAG_DRIVERS_LIBUSB0_COMMON_H - -#include <usb.h> - -#define jtag_libusb_device usb_device -#define jtag_libusb_device_handle usb_dev_handle -#define jtag_libusb_device_descriptor usb_device_descriptor -#define jtag_libusb_interface usb_interface -#define jtag_libusb_interface_descriptor usb_interface_descriptor -#define jtag_libusb_endpoint_descriptor usb_endpoint_descriptor -#define jtag_libusb_config_descriptor usb_config_descriptor - -#define jtag_libusb_reset_device(dev) usb_reset(dev) -#define jtag_libusb_get_device(devh) usb_device(devh) - -/* make some defines compatible to libusb1 */ -#define LIBUSB_REQUEST_TYPE_VENDOR USB_TYPE_VENDOR -#define LIBUSB_RECIPIENT_DEVICE USB_RECIP_DEVICE -#define LIBUSB_ENDPOINT_OUT USB_ENDPOINT_OUT -#define LIBUSB_ENDPOINT_IN USB_ENDPOINT_IN -#define LIBUSB_TRANSFER_TYPE_BULK USB_ENDPOINT_TYPE_BULK - -static inline int jtag_libusb_claim_interface(jtag_libusb_device_handle *devh, - int iface) -{ - return usb_claim_interface(devh, iface); -}; - -static inline int jtag_libusb_release_interface(jtag_libusb_device_handle *devh, - int iface) -{ - return usb_release_interface(devh, iface); -} - -int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], - const char *serial, - struct jtag_libusb_device_handle **out); -void jtag_libusb_close(jtag_libusb_device_handle *dev); -int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, - uint8_t requestType, uint8_t request, uint16_t wValue, - uint16_t wIndex, char *bytes, uint16_t size, unsigned int timeout); -int jtag_libusb_bulk_write(struct jtag_libusb_device_handle *dev, int ep, - char *bytes, int size, int timeout); -int jtag_libusb_bulk_read(struct jtag_libusb_device_handle *dev, int ep, - char *bytes, int size, int timeout); -int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh, - int configuration); -int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh, - unsigned int *usb_read_ep, - unsigned int *usb_write_ep, - int bclass, int subclass, int protocol, int trans_type); -int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid); - -#endif /* OPENOCD_JTAG_DRIVERS_LIBUSB0_COMMON_H */ diff --git a/src/jtag/drivers/libusb1_common.c b/src/jtag/drivers/libusb_helper.c index d96ac76..184882a 100644 --- a/src/jtag/drivers/libusb1_common.c +++ b/src/jtag/drivers/libusb_helper.c @@ -21,7 +21,7 @@ #include "config.h" #endif #include <jtag/drivers/jtag_usb_common.h> -#include "libusb1_common.h" +#include "libusb_helper.h" #include "log.h" /* @@ -33,7 +33,32 @@ static struct libusb_context *jtag_libusb_context; /**< Libusb context **/ static libusb_device **devs; /**< The usb device list **/ -static bool jtag_libusb_match(struct libusb_device_descriptor *dev_desc, +static int jtag_libusb_error(int err) +{ + switch (err) { + case LIBUSB_SUCCESS: + return ERROR_OK; + case LIBUSB_ERROR_TIMEOUT: + return ERROR_TIMEOUT_REACHED; + case LIBUSB_ERROR_IO: + case LIBUSB_ERROR_INVALID_PARAM: + case LIBUSB_ERROR_ACCESS: + case LIBUSB_ERROR_NO_DEVICE: + case LIBUSB_ERROR_NOT_FOUND: + case LIBUSB_ERROR_BUSY: + case LIBUSB_ERROR_OVERFLOW: + case LIBUSB_ERROR_PIPE: + case LIBUSB_ERROR_INTERRUPTED: + case LIBUSB_ERROR_NO_MEM: + case LIBUSB_ERROR_NOT_SUPPORTED: + case LIBUSB_ERROR_OTHER: + return ERROR_FAIL; + default: + return ERROR_FAIL; + } +} + +static bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc, const uint16_t vids[], const uint16_t pids[]) { for (unsigned i = 0; vids[i]; i++) { @@ -98,14 +123,45 @@ static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_in return matched; } +static bool jtag_libusb_match_serial(libusb_device_handle *device, + struct libusb_device_descriptor *dev_desc, const char *serial, + adapter_get_alternate_serial_fn adapter_get_alternate_serial) +{ + if (string_descriptor_equal(device, dev_desc->iSerialNumber, serial)) + return true; + + /* check the alternate serial helper */ + if (!adapter_get_alternate_serial) + return false; + + /* get the alternate serial */ + char *alternate_serial = adapter_get_alternate_serial(device, dev_desc); + + /* check possible failures */ + if (alternate_serial == NULL) + return false; + + /* then compare and free the alternate serial */ + bool match = false; + if (strcmp(serial, alternate_serial) == 0) + match = true; + else + LOG_DEBUG("Device alternate serial number '%s' doesn't match requested serial '%s'", + alternate_serial, serial); + + free(alternate_serial); + return match; +} + int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], const char *serial, - struct jtag_libusb_device_handle **out) + struct libusb_device_handle **out, + adapter_get_alternate_serial_fn adapter_get_alternate_serial) { int cnt, idx, errCode; int retval = ERROR_FAIL; bool serial_mismatch = false; - struct jtag_libusb_device_handle *libusb_handle = NULL; + struct libusb_device_handle *libusb_handle = NULL; if (libusb_init(&jtag_libusb_context) < 0) return ERROR_FAIL; @@ -118,7 +174,7 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], if (libusb_get_device_descriptor(devs[idx], &dev_desc) != 0) continue; - if (!jtag_libusb_match(&dev_desc, vids, pids)) + if (!jtag_libusb_match_ids(&dev_desc, vids, pids)) continue; if (jtag_usb_get_location() && !jtag_libusb_location_equal(devs[idx])) @@ -134,7 +190,7 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], /* Device must be open to use libusb_get_string_descriptor_ascii. */ if (serial != NULL && - !string_descriptor_equal(libusb_handle, dev_desc.iSerialNumber, serial)) { + !jtag_libusb_match_serial(libusb_handle, &dev_desc, serial, adapter_get_alternate_serial)) { serial_mismatch = true; libusb_close(libusb_handle); continue; @@ -152,10 +208,13 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], if (serial_mismatch) LOG_INFO("No device matches the serial string"); + if (retval != ERROR_OK) + libusb_exit(jtag_libusb_context); + return retval; } -void jtag_libusb_close(jtag_libusb_device_handle *dev) +void jtag_libusb_close(struct libusb_device_handle *dev) { /* Close device */ libusb_close(dev); @@ -163,7 +222,7 @@ void jtag_libusb_close(jtag_libusb_device_handle *dev) libusb_exit(jtag_libusb_context); } -int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, uint8_t requestType, +int jtag_libusb_control_transfer(struct libusb_device_handle *dev, uint8_t requestType, uint8_t request, uint16_t wValue, uint16_t wIndex, char *bytes, uint16_t size, unsigned int timeout) { @@ -178,30 +237,44 @@ int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, uint8_t request return transferred; } -int jtag_libusb_bulk_write(jtag_libusb_device_handle *dev, int ep, char *bytes, - int size, int timeout) +int jtag_libusb_bulk_write(struct libusb_device_handle *dev, int ep, char *bytes, + int size, int timeout, int *transferred) { - int transferred = 0; + int ret; - libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size, - &transferred, timeout); - return transferred; + *transferred = 0; + + ret = libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size, + transferred, timeout); + if (ret != LIBUSB_SUCCESS) { + LOG_ERROR("libusb_bulk_write error: %s", libusb_error_name(ret)); + return jtag_libusb_error(ret); + } + + return ERROR_OK; } -int jtag_libusb_bulk_read(jtag_libusb_device_handle *dev, int ep, char *bytes, - int size, int timeout) +int jtag_libusb_bulk_read(struct libusb_device_handle *dev, int ep, char *bytes, + int size, int timeout, int *transferred) { - int transferred = 0; + int ret; - libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size, - &transferred, timeout); - return transferred; + *transferred = 0; + + ret = libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size, + transferred, timeout); + if (ret != LIBUSB_SUCCESS) { + LOG_ERROR("libusb_bulk_read error: %s", libusb_error_name(ret)); + return jtag_libusb_error(ret); + } + + return ERROR_OK; } -int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh, +int jtag_libusb_set_configuration(struct libusb_device_handle *devh, int configuration) { - struct jtag_libusb_device *udev = jtag_libusb_get_device(devh); + struct libusb_device *udev = libusb_get_device(devh); int retCode = -99; struct libusb_config_descriptor *config = NULL; @@ -226,12 +299,12 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh, return retCode; } -int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh, +int jtag_libusb_choose_interface(struct libusb_device_handle *devh, unsigned int *usb_read_ep, unsigned int *usb_write_ep, int bclass, int subclass, int protocol, int trans_type) { - struct jtag_libusb_device *udev = jtag_libusb_get_device(devh); + struct libusb_device *udev = libusb_get_device(devh); const struct libusb_interface *inter; const struct libusb_interface_descriptor *interdesc; const struct libusb_endpoint_descriptor *epdesc; @@ -278,7 +351,7 @@ int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh, return ERROR_FAIL; } -int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid) +int jtag_libusb_get_pid(struct libusb_device *dev, uint16_t *pid) { struct libusb_device_descriptor dev_desc; diff --git a/src/jtag/drivers/libusb1_common.h b/src/jtag/drivers/libusb_helper.h index 7c73d29..74bb23c 100644 --- a/src/jtag/drivers/libusb1_common.h +++ b/src/jtag/drivers/libusb_helper.h @@ -17,46 +17,29 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ***************************************************************************/ -#ifndef OPENOCD_JTAG_DRIVERS_LIBUSB1_COMMON_H -#define OPENOCD_JTAG_DRIVERS_LIBUSB1_COMMON_H +#ifndef OPENOCD_JTAG_DRIVERS_LIBUSB_HELPER_H +#define OPENOCD_JTAG_DRIVERS_LIBUSB_HELPER_H #include <libusb.h> -#define jtag_libusb_device libusb_device -#define jtag_libusb_device_handle libusb_device_handle -#define jtag_libusb_device_descriptor libusb_device_descriptor -#define jtag_libusb_interface libusb_interface -#define jtag_libusb_interface_descriptor libusb_interface_descriptor -#define jtag_libusb_endpoint_descriptor libusb_endpoint_descriptor -#define jtag_libusb_config_descriptor libusb_config_descriptor - -#define jtag_libusb_reset_device(dev) libusb_reset_device(dev) -#define jtag_libusb_get_device(devh) libusb_get_device(devh) - -static inline int jtag_libusb_claim_interface(jtag_libusb_device_handle *devh, - int iface) -{ - return libusb_claim_interface(devh, iface); -}; - -static inline int jtag_libusb_release_interface(jtag_libusb_device_handle *devh, - int iface) -{ - return libusb_release_interface(devh, iface); -} +/* this callback should return a non NULL value only when the serial could not + * be retrieved by the standard 'libusb_get_string_descriptor_ascii' */ +typedef char * (*adapter_get_alternate_serial_fn)(libusb_device_handle *device, + struct libusb_device_descriptor *dev_desc); int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], const char *serial, - struct jtag_libusb_device_handle **out); -void jtag_libusb_close(jtag_libusb_device_handle *dev); -int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, + struct libusb_device_handle **out, + adapter_get_alternate_serial_fn adapter_get_alternate_serial); +void jtag_libusb_close(struct libusb_device_handle *dev); +int jtag_libusb_control_transfer(struct libusb_device_handle *dev, uint8_t requestType, uint8_t request, uint16_t wValue, uint16_t wIndex, char *bytes, uint16_t size, unsigned int timeout); -int jtag_libusb_bulk_write(struct jtag_libusb_device_handle *dev, int ep, - char *bytes, int size, int timeout); -int jtag_libusb_bulk_read(struct jtag_libusb_device_handle *dev, int ep, - char *bytes, int size, int timeout); -int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh, +int jtag_libusb_bulk_write(struct libusb_device_handle *dev, int ep, + char *bytes, int size, int timeout, int *transferred); +int jtag_libusb_bulk_read(struct libusb_device_handle *dev, int ep, + char *bytes, int size, int timeout, int *transferred); +int jtag_libusb_set_configuration(struct libusb_device_handle *devh, int configuration); /** * Find the first interface optionally matching class, subclass and @@ -72,10 +55,10 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh, * @param trans_type `bmAttributes Bits 0..1 Transfer type` to match, or -1 to ignore this field. * @returns Returns ERROR_OK on success, ERROR_FAIL otherwise. */ -int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh, +int jtag_libusb_choose_interface(struct libusb_device_handle *devh, unsigned int *usb_read_ep, unsigned int *usb_write_ep, int bclass, int subclass, int protocol, int trans_type); -int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid); +int jtag_libusb_get_pid(struct libusb_device *dev, uint16_t *pid); -#endif /* OPENOCD_JTAG_DRIVERS_LIBUSB1_COMMON_H */ +#endif /* OPENOCD_JTAG_DRIVERS_LIBUSB_HELPER_H */ diff --git a/src/jtag/drivers/mpsse.c b/src/jtag/drivers/mpsse.c index c0d883b..7488d9d 100644 --- a/src/jtag/drivers/mpsse.c +++ b/src/jtag/drivers/mpsse.c @@ -890,6 +890,7 @@ int mpsse_flush(struct mpsse_ctx *ctx) /* Polling loop, more or less taken from libftdi */ int64_t start = timeval_ms(); + int64_t warn_after = 2000; while (!write_result.done || !read_result.done) { struct timeval timeout_usb; @@ -913,9 +914,11 @@ int mpsse_flush(struct mpsse_ctx *ctx) } } - if (timeval_ms() - start > 2000) { - LOG_ERROR("Timed out handling USB events in mpsse_flush()."); - break; + int64_t now = timeval_ms(); + if (now - start > warn_after) { + LOG_WARNING("Haven't made progress in mpsse_flush() for %" PRId64 + "ms.", now - start); + warn_after *= 2; } } diff --git a/src/jtag/drivers/opendous.c b/src/jtag/drivers/opendous.c index 5f352af..bb223f4 100644 --- a/src/jtag/drivers/opendous.c +++ b/src/jtag/drivers/opendous.c @@ -32,7 +32,7 @@ #include <jtag/interface.h> #include <jtag/commands.h> -#include "libusb_common.h" +#include "libusb_helper.h" #include <string.h> #include <time.h> @@ -134,7 +134,7 @@ static void opendous_tap_append_scan(int length, uint8_t *buffer, struct scan_co /* opendous lowlevel functions */ struct opendous_jtag { - struct jtag_libusb_device_handle *usb_handle; + struct libusb_device_handle *usb_handle; }; static struct opendous_jtag *opendous_usb_open(void); @@ -234,13 +234,19 @@ static const struct command_registration opendous_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct jtag_interface opendous_interface = { +static struct jtag_interface opendous_interface = { + .execute_queue = opendous_execute_queue, +}; + +struct adapter_driver opendous_adapter_driver = { .name = "opendous", .transports = jtag_only, .commands = opendous_command_handlers, - .execute_queue = opendous_execute_queue, + .init = opendous_init, .quit = opendous_quit, + + .jtag_ops = &opendous_interface, }; static int opendous_execute_queue(void) @@ -253,7 +259,7 @@ static int opendous_execute_queue(void) while (cmd != NULL) { switch (cmd->type) { case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, \ + LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); if (cmd->cmd.runtest->end_state != -1) @@ -270,8 +276,8 @@ static int opendous_execute_queue(void) break; case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %i states, end in %i", \ - cmd->cmd.pathmove->num_states, \ + LOG_DEBUG_IO("pathmove: %i states, end in %i", + cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); opendous_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); @@ -708,12 +714,12 @@ struct opendous_jtag *opendous_usb_open(void) { struct opendous_jtag *result; - struct jtag_libusb_device_handle *devh; - if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, NULL, &devh) != ERROR_OK) + struct libusb_device_handle *devh; + if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, NULL, &devh, NULL) != ERROR_OK) return NULL; jtag_libusb_set_configuration(devh, 0); - jtag_libusb_claim_interface(devh, 0); + libusb_claim_interface(devh, 0); result = malloc(sizeof(*result)); result->usb_handle = devh; @@ -764,8 +770,8 @@ int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length) LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, FUNC_WRITE_DATA, 0, 0, (char *) usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT); } else { - result = jtag_libusb_bulk_write(opendous_jtag->usb_handle, OPENDOUS_WRITE_ENDPOINT, \ - (char *)usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT); + jtag_libusb_bulk_write(opendous_jtag->usb_handle, OPENDOUS_WRITE_ENDPOINT, + (char *)usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT, &result); } #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("USB write end: %d bytes", result); @@ -791,8 +797,8 @@ int opendous_usb_read(struct opendous_jtag *opendous_jtag) LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, FUNC_READ_DATA, 0, 0, (char *) usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT); } else { - result = jtag_libusb_bulk_read(opendous_jtag->usb_handle, OPENDOUS_READ_ENDPOINT, - (char *)usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT); + jtag_libusb_bulk_read(opendous_jtag->usb_handle, OPENDOUS_READ_ENDPOINT, + (char *)usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT, &result); } #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("USB read end: %d bytes", result); diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c index 7a3aa23..7eab5c1 100644 --- a/src/jtag/drivers/openjtag.c +++ b/src/jtag/drivers/openjtag.c @@ -45,7 +45,7 @@ #include <jtag/interface.h> #include <jtag/commands.h> -#include "libusb_common.h" +#include "libusb_helper.h" static enum { OPENJTAG_VARIANT_STANDARD, @@ -111,7 +111,7 @@ static uint8_t usb_rx_buf[OPENJTAG_BUFFER_SIZE]; static struct openjtag_scan_result openjtag_scan_result_buffer[OPENJTAG_MAX_PENDING_RESULTS]; static int openjtag_scan_result_count; -static jtag_libusb_device_handle *usbh; +static struct libusb_device_handle *usbh; /* CY7C65215 model only */ #define CY7C65215_JTAG_REQUEST 0x40 /* bmRequestType: vendor host-to-device */ @@ -229,7 +229,7 @@ static int openjtag_buf_write_standard( return ERROR_JTAG_DEVICE_ERROR; } - *bytes_written += retval; + *bytes_written = retval; return ERROR_OK; } @@ -256,10 +256,9 @@ static int openjtag_buf_write_cy7c65215( return ERROR_JTAG_DEVICE_ERROR; } - ret = jtag_libusb_bulk_write(usbh, ep_out, (char *)buf, size, - CY7C65215_USB_TIMEOUT); - if (ret < 0) { - LOG_ERROR("bulk write failed, error %d", ret); + if (jtag_libusb_bulk_write(usbh, ep_out, (char *)buf, size, + CY7C65215_USB_TIMEOUT, &ret)) { + LOG_ERROR("bulk write failed, error"); return ERROR_JTAG_DEVICE_ERROR; } *bytes_written = ret; @@ -324,10 +323,9 @@ static int openjtag_buf_read_cy7c65215( return ERROR_JTAG_DEVICE_ERROR; } - ret = jtag_libusb_bulk_read(usbh, ep_in, (char *)buf, qty, - CY7C65215_USB_TIMEOUT); - if (ret < 0) { - LOG_ERROR("bulk read failed, error %d", ret); + if (jtag_libusb_bulk_read(usbh, ep_in, (char *)buf, qty, + CY7C65215_USB_TIMEOUT, &ret)) { + LOG_ERROR("bulk read failed, error"); return ERROR_JTAG_DEVICE_ERROR; } *bytes_read = ret; @@ -451,7 +449,7 @@ static int openjtag_init_cy7c65215(void) int ret; usbh = NULL; - ret = jtag_libusb_open(cy7c65215_vids, cy7c65215_pids, NULL, &usbh); + ret = jtag_libusb_open(cy7c65215_vids, cy7c65215_pids, NULL, &usbh, NULL); if (ret != ERROR_OK) { LOG_ERROR("unable to open cy7c65215 device"); goto err; @@ -654,7 +652,6 @@ static void openjtag_add_scan(uint8_t *buffer, int length, struct scan_command * /* whole byte */ /* bits to transfer */ - bits = 7; command |= (7 << 5); length -= 8; } @@ -692,7 +689,7 @@ static void openjtag_execute_sleep(struct jtag_command *cmd) static void openjtag_set_state(uint8_t openocd_state) { - int8_t state = openjtag_get_tap_state(openocd_state); + uint8_t state = openjtag_get_tap_state(openocd_state); uint8_t buf = 0; buf = 0x01; @@ -892,17 +889,20 @@ static const struct command_registration openjtag_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct jtag_interface openjtag_interface = { +static struct jtag_interface openjtag_interface = { + .execute_queue = openjtag_execute_queue, +}; + +struct adapter_driver openjtag_adapter_driver = { .name = "openjtag", .transports = jtag_only, .commands = openjtag_command_handlers, - .execute_queue = openjtag_execute_queue, - .speed = openjtag_speed, - .speed_div = openjtag_speed_div, - .khz = openjtag_khz, .init = openjtag_init, .quit = openjtag_quit, -}; - + .speed = openjtag_speed, + .khz = openjtag_khz, + .speed_div = openjtag_speed_div, + .jtag_ops = &openjtag_interface, +}; diff --git a/src/jtag/drivers/osbdm.c b/src/jtag/drivers/osbdm.c index 5db36a1..dc23666 100644 --- a/src/jtag/drivers/osbdm.c +++ b/src/jtag/drivers/osbdm.c @@ -23,7 +23,7 @@ #include <helper/binarybuffer.h> #include <helper/command.h> #include <jtag/interface.h> -#include "libusb_common.h" +#include "libusb_helper.h" struct sequence { int len; @@ -132,7 +132,7 @@ static const uint16_t osbdm_vid[] = { 0x15a2, 0x15a2, 0x15a2, 0 }; static const uint16_t osbdm_pid[] = { 0x0042, 0x0058, 0x005e, 0 }; struct osbdm { - struct jtag_libusb_device_handle *devh; /* USB handle */ + struct libusb_device_handle *devh; /* USB handle */ uint8_t buffer[OSBDM_USB_BUFSIZE]; /* Data to send and receive */ int count; /* Count data to send and to read */ }; @@ -144,10 +144,12 @@ static struct osbdm osbdm_context; static int osbdm_send_and_recv(struct osbdm *osbdm) { /* Send request */ - int count = jtag_libusb_bulk_write(osbdm->devh, OSBDM_USB_EP_WRITE, - (char *)osbdm->buffer, osbdm->count, OSBDM_USB_TIMEOUT); + int count, ret; - if (count != osbdm->count) { + ret = jtag_libusb_bulk_write(osbdm->devh, OSBDM_USB_EP_WRITE, + (char *)osbdm->buffer, osbdm->count, + OSBDM_USB_TIMEOUT, &count); + if (ret || count != osbdm->count) { LOG_ERROR("OSBDM communication error: can't write"); return ERROR_FAIL; } @@ -156,13 +158,12 @@ static int osbdm_send_and_recv(struct osbdm *osbdm) uint8_t cmd_saved = osbdm->buffer[0]; /* Reading answer */ - osbdm->count = jtag_libusb_bulk_read(osbdm->devh, OSBDM_USB_EP_READ, - (char *)osbdm->buffer, OSBDM_USB_BUFSIZE, OSBDM_USB_TIMEOUT); - + ret = jtag_libusb_bulk_read(osbdm->devh, OSBDM_USB_EP_READ, + (char *)osbdm->buffer, OSBDM_USB_BUFSIZE, + OSBDM_USB_TIMEOUT, &osbdm->count); /* Now perform basic checks for data sent by BDM device */ - - if (osbdm->count < 0) { + if (ret) { LOG_ERROR("OSBDM communication error: can't read"); return ERROR_FAIL; } @@ -296,7 +297,7 @@ static int osbdm_swap(struct osbdm *osbdm, void *tms, void *tdi, return ERROR_OK; } -static int osbdm_flush(struct osbdm *osbdm, struct queue* queue) +static int osbdm_flush(struct osbdm *osbdm, struct queue *queue) { uint8_t tms[DIV_ROUND_UP(OSBDM_SWAP_MAX, 8)]; uint8_t tdi[DIV_ROUND_UP(OSBDM_SWAP_MAX, 8)]; @@ -373,10 +374,10 @@ static int osbdm_flush(struct osbdm *osbdm, struct queue* queue) static int osbdm_open(struct osbdm *osbdm) { (void)memset(osbdm, 0, sizeof(*osbdm)); - if (jtag_libusb_open(osbdm_vid, osbdm_pid, NULL, &osbdm->devh) != ERROR_OK) + if (jtag_libusb_open(osbdm_vid, osbdm_pid, NULL, &osbdm->devh, NULL) != ERROR_OK) return ERROR_FAIL; - if (jtag_libusb_claim_interface(osbdm->devh, 0) != ERROR_OK) + if (libusb_claim_interface(osbdm->devh, 0) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; @@ -688,12 +689,16 @@ static int osbdm_init(void) return ERROR_OK; } -struct jtag_interface osbdm_interface = { - .name = "osbdm", +static struct jtag_interface osbdm_interface = { + .execute_queue = osbdm_execute_queue, +}; +struct adapter_driver osbdm_adapter_driver = { + .name = "osbdm", .transports = jtag_only, - .execute_queue = osbdm_execute_queue, .init = osbdm_init, - .quit = osbdm_quit + .quit = osbdm_quit, + + .jtag_ops = &osbdm_interface, }; diff --git a/src/jtag/drivers/parport.c b/src/jtag/drivers/parport.c index 8e44dcb..b3abd12 100644 --- a/src/jtag/drivers/parport.c +++ b/src/jtag/drivers/parport.c @@ -237,7 +237,7 @@ static int parport_get_giveio_access(void) HANDLE h; OSVERSIONINFO version; - version.dwOSVersionInfoSize = sizeof version; + version.dwOSVersionInfoSize = sizeof(version); if (!GetVersionEx(&version)) { errno = EINVAL; return -1; @@ -260,7 +260,6 @@ static int parport_get_giveio_access(void) static struct bitbang_interface parport_bitbang = { .read = &parport_read, .write = &parport_write, - .reset = &parport_reset, .blink = &parport_led, }; @@ -514,16 +513,22 @@ static const struct command_registration parport_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct jtag_interface parport_interface = { - .name = "parport", +static struct jtag_interface parport_interface = { .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = bitbang_execute_queue, +}; + +struct adapter_driver parport_adapter_driver = { + .name = "parport", .transports = jtag_only, .commands = parport_command_handlers, .init = parport_init, .quit = parport_quit, + .reset = parport_reset, + .speed = parport_speed, .khz = parport_khz, .speed_div = parport_speed_div, - .speed = parport_speed, - .execute_queue = bitbang_execute_queue, + + .jtag_ops = &parport_interface, }; diff --git a/src/jtag/drivers/presto.c b/src/jtag/drivers/presto.c index 2a94d06..3849a27 100644 --- a/src/jtag/drivers/presto.c +++ b/src/jtag/drivers/presto.c @@ -561,15 +561,20 @@ static int presto_jtag_quit(void) return ERROR_OK; } -struct jtag_interface presto_interface = { +static struct jtag_interface presto_interface = { + .execute_queue = bitq_execute_queue, +}; + +struct adapter_driver presto_adapter_driver = { .name = "presto", .transports = jtag_only, .commands = presto_command_handlers, - .execute_queue = bitq_execute_queue, + .init = presto_jtag_init, + .quit = presto_jtag_quit, .speed = presto_jtag_speed, .khz = presto_adapter_khz, .speed_div = presto_jtag_speed_div, - .init = presto_jtag_init, - .quit = presto_jtag_quit, + + .jtag_ops = &presto_interface, }; diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c index a354894..6637952 100644 --- a/src/jtag/drivers/remote_bitbang.c +++ b/src/jtag/drivers/remote_bitbang.c @@ -199,7 +199,6 @@ static struct bitbang_interface remote_bitbang_bitbang = { .sample = &remote_bitbang_sample, .read_sample = &remote_bitbang_read_sample, .write = &remote_bitbang_write, - .reset = &remote_bitbang_reset, .blink = &remote_bitbang_blink, }; @@ -342,11 +341,18 @@ static const struct command_registration remote_bitbang_command_handlers[] = { COMMAND_REGISTRATION_DONE, }; -struct jtag_interface remote_bitbang_interface = { - .name = "remote_bitbang", +static struct jtag_interface remote_bitbang_interface = { .execute_queue = &bitbang_execute_queue, +}; + +struct adapter_driver remote_bitbang_adapter_driver = { + .name = "remote_bitbang", .transports = jtag_only, .commands = remote_bitbang_command_handlers, + .init = &remote_bitbang_init, .quit = &remote_bitbang_quit, + .reset = &remote_bitbang_reset, + + .jtag_ops = &remote_bitbang_interface, }; diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c index 317e8b8..e053399 100644 --- a/src/jtag/drivers/rlink.c +++ b/src/jtag/drivers/rlink.c @@ -1660,13 +1660,19 @@ static int rlink_quit(void) return ERROR_OK; } -struct jtag_interface rlink_interface = { +static struct jtag_interface rlink_interface = { + .execute_queue = rlink_execute_queue, +}; + +struct adapter_driver rlink_adapter_driver = { .name = "rlink", .transports = jtag_only, + .init = rlink_init, .quit = rlink_quit, .speed = rlink_speed, - .speed_div = rlink_speed_div, .khz = rlink_khz, - .execute_queue = rlink_execute_queue, + .speed_div = rlink_speed_div, + + .jtag_ops = &rlink_interface, }; diff --git a/src/jtag/drivers/rlink_call.m4 b/src/jtag/drivers/rlink_call.m4 index b27f392..bf07afa 100644 --- a/src/jtag/drivers/rlink_call.m4 +++ b/src/jtag/drivers/rlink_call.m4 @@ -479,5 +479,3 @@ m4_delay(HOLD_DELAY_CYCLES - 10) A = X DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it BRANCH - - diff --git a/src/jtag/drivers/rlink_speed_table.c b/src/jtag/drivers/rlink_speed_table.c index b843577..660aac4 100644 --- a/src/jtag/drivers/rlink_speed_table.c +++ b/src/jtag/drivers/rlink_speed_table.c @@ -98,4 +98,3 @@ const struct rlink_speed_table rlink_speed_table[] = {{ } }; const size_t rlink_speed_table_size = ARRAY_SIZE(rlink_speed_table); - diff --git a/src/jtag/drivers/rshim.c b/src/jtag/drivers/rshim.c new file mode 100644 index 0000000..c718af5 --- /dev/null +++ b/src/jtag/drivers/rshim.c @@ -0,0 +1,523 @@ +/* + * Copyright (c) 2020, Mellanox Technologies Ltd. - All Rights Reserved + * Liming Sun <lsun@mellanox.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 <helper/types.h> +#include <helper/system.h> +#include <helper/time_support.h> +#include <helper/list.h> +#include <jtag/interface.h> +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif +#include <target/arm_adi_v5.h> +#include <transport/transport.h> + +/* Rshim channel where the CoreSight register resides. */ +#define RSH_MMIO_CHANNEL_RSHIM 0x1 + +/* APB and tile address translation. */ +#define RSH_CS_ROM_BASE 0x80000000 +#define RSH_CS_TILE_BASE 0x44000000 +#define RSH_CS_TILE_SIZE 0x04000000 + +/* + * APB-AP Identification Register + * The default value is defined in "CoreSight on-chip trace and debug + * (Revision: r1p0)", Section 3.16.5 APB-AP register summary. + */ +#define APB_AP_IDR 0x44770002 + +/* CoreSight register definition. */ +#define RSH_CORESIGHT_CTL 0x0e00 +#define RSH_CORESIGHT_CTL_GO_SHIFT 0 +#define RSH_CORESIGHT_CTL_GO_MASK 0x1ULL +#define RSH_CORESIGHT_CTL_ACTION_SHIFT 1 +#define RSH_CORESIGHT_CTL_ACTION_MASK 0x2ULL +#define RSH_CORESIGHT_CTL_ADDR_SHIFT 2 +#define RSH_CORESIGHT_CTL_ADDR_MASK 0x7ffffffcULL +#define RSH_CORESIGHT_CTL_ERR_SHIFT 31 +#define RSH_CORESIGHT_CTL_ERR_MASK 0x80000000ULL +#define RSH_CORESIGHT_CTL_DATA_SHIFT 32 +#define RSH_CORESIGHT_CTL_DATA_MASK 0xffffffff00000000ULL + +/* Util macros to access the CoreSight register. */ +#define RSH_CS_GET_FIELD(reg, field) \ + (((uint64_t)(reg) & RSH_CORESIGHT_CTL_##field##_MASK) >> \ + RSH_CORESIGHT_CTL_##field##_SHIFT) + +#define RSH_CS_SET_FIELD(reg, field, value) \ + (reg) = (((reg) & ~RSH_CORESIGHT_CTL_##field##_MASK) | \ + (((uint64_t)(value) << RSH_CORESIGHT_CTL_##field##_SHIFT) & \ + RSH_CORESIGHT_CTL_##field##_MASK)) + +#ifdef HAVE_SYS_IOCTL_H +/* Message used to program rshim via ioctl(). */ +typedef struct { + uint32_t addr; + uint64_t data; +} __attribute__((packed)) rshim_ioctl_msg; + +enum { + RSH_IOC_READ = _IOWR('R', 0, rshim_ioctl_msg), + RSH_IOC_WRITE = _IOWR('R', 1, rshim_ioctl_msg), +}; +#endif + +/* Use local variable stub for DP/AP registers. */ +static uint32_t dp_ctrl_stat; +static uint32_t dp_id_code; +static uint32_t ap_sel, ap_bank; +static uint32_t ap_csw; +static uint32_t ap_drw; +static uint32_t ap_tar, ap_tar_inc; + +/* Static functions to read/write via rshim/coresight. */ +static int (*rshim_read)(int chan, int addr, uint64_t *value); +static int (*rshim_write)(int chan, int addr, uint64_t value); +static int coresight_write(uint32_t tile, uint32_t addr, uint32_t wdata); +static int coresight_read(uint32_t tile, uint32_t addr, uint32_t *value); + +/* RShim file handler. */ +static int rshim_fd = -1; + +/* DAP error code. */ +static int rshim_dap_retval = ERROR_OK; + +/* Default rshim device. */ +#define RSHIM_DEV_PATH_DEFAULT "/dev/rshim0/rshim" +static char *rshim_dev_path; + +static int rshim_dev_read(int chan, int addr, uint64_t *value) +{ + int rc; + + addr = (addr & 0xFFFF) | (1 << 16); + rc = pread(rshim_fd, value, sizeof(*value), addr); + +#ifdef HAVE_SYS_IOCTL_H + if (rc < 0 && errno == ENOSYS) { + rshim_ioctl_msg msg; + + msg.addr = addr; + msg.data = 0; + rc = ioctl(rshim_fd, RSH_IOC_READ, &msg); + if (!rc) + *value = msg.data; + } +#endif + + return rc; +} + +static int rshim_dev_write(int chan, int addr, uint64_t value) +{ + int rc; + + addr = (addr & 0xFFFF) | (1 << 16); + rc = pwrite(rshim_fd, &value, sizeof(value), addr); + +#ifdef HAVE_SYS_IOCTL_H + if (rc < 0 && errno == ENOSYS) { + rshim_ioctl_msg msg; + + msg.addr = addr; + msg.data = value; + rc = ioctl(rshim_fd, RSH_IOC_WRITE, &msg); + } +#endif + + return rc; +} + +/* Convert AP address to tile local address. */ +static void ap_addr_2_tile(int *tile, uint32_t *addr) +{ + *addr -= RSH_CS_ROM_BASE; + + if (*addr < RSH_CS_TILE_BASE) { + *tile = 0; + } else { + *addr -= RSH_CS_TILE_BASE; + *tile = *addr / RSH_CS_TILE_SIZE + 1; + *addr = *addr % RSH_CS_TILE_SIZE; + } +} + +/* + * Write 4 bytes on the APB bus. + * tile = 0: access the root CS_ROM table + * > 0: access the ROM table of cluster (tile - 1) + */ +static int coresight_write(uint32_t tile, uint32_t addr, uint32_t wdata) +{ + uint64_t ctl = 0; + int rc; + + if (!rshim_read || !rshim_write) + return ERROR_FAIL; + + /* + * ADDR[28] - must be set to 1 due to coresight ip. + * ADDR[27:24] - linear tile id + */ + addr = (addr >> 2) | (tile << 24); + if (tile) + addr |= (1 << 28); + RSH_CS_SET_FIELD(ctl, ADDR, addr); + RSH_CS_SET_FIELD(ctl, ACTION, 0); /* write */ + RSH_CS_SET_FIELD(ctl, DATA, wdata); + RSH_CS_SET_FIELD(ctl, GO, 1); /* start */ + + rshim_write(RSH_MMIO_CHANNEL_RSHIM, RSH_CORESIGHT_CTL, ctl); + + do { + rc = rshim_read(RSH_MMIO_CHANNEL_RSHIM, + RSH_CORESIGHT_CTL, &ctl); + if (rc < 0) { + LOG_ERROR("Failed to read rshim.\n"); + return rc; + } + } while (RSH_CS_GET_FIELD(ctl, GO)); + + return ERROR_OK; +} + +static int coresight_read(uint32_t tile, uint32_t addr, uint32_t *value) +{ + uint64_t ctl = 0; + int rc; + + if (!rshim_read || !rshim_write) + return ERROR_FAIL; + + /* + * ADDR[28] - must be set to 1 due to coresight ip. + * ADDR[27:24] - linear tile id + */ + addr = (addr >> 2) | (tile << 24); + if (tile) + addr |= (1 << 28); + RSH_CS_SET_FIELD(ctl, ADDR, addr); + RSH_CS_SET_FIELD(ctl, ACTION, 1); /* read */ + RSH_CS_SET_FIELD(ctl, GO, 1); /* start */ + + rshim_write(RSH_MMIO_CHANNEL_RSHIM, RSH_CORESIGHT_CTL, ctl); + + do { + rc = rshim_read(RSH_MMIO_CHANNEL_RSHIM, + RSH_CORESIGHT_CTL, &ctl); + if (rc < 0) { + LOG_ERROR("Failed to write rshim.\n"); + return rc; + } + } while (RSH_CS_GET_FIELD(ctl, GO)); + + *value = RSH_CS_GET_FIELD(ctl, DATA); + return ERROR_OK; +} + +static int rshim_dp_q_read(struct adiv5_dap *dap, unsigned int reg, + uint32_t *data) +{ + if (!data) + return ERROR_OK; + + switch (reg) { + case DP_DPIDR: + *data = dp_id_code; + break; + + case DP_CTRL_STAT: + *data = CDBGPWRUPACK | CSYSPWRUPACK; + break; + + default: + break; + } + + return ERROR_OK; +} + +static int rshim_dp_q_write(struct adiv5_dap *dap, unsigned int reg, + uint32_t data) +{ + switch (reg) { + case DP_CTRL_STAT: + dp_ctrl_stat = data; + break; + case DP_SELECT: + ap_sel = (data & DP_SELECT_APSEL) >> 24; + ap_bank = (data & DP_SELECT_APBANK) >> 4; + break; + default: + LOG_INFO("Unknown command"); + break; + } + + return ERROR_OK; +} + +static int rshim_ap_q_read(struct adiv5_ap *ap, unsigned int reg, + uint32_t *data) +{ + uint32_t addr; + int rc = ERROR_OK, tile; + + switch (reg) { + case MEM_AP_REG_CSW: + *data = ap_csw; + break; + + case MEM_AP_REG_CFG: + *data = 0; + break; + + case MEM_AP_REG_BASE: + *data = RSH_CS_ROM_BASE; + break; + + case AP_REG_IDR: + if (ap->ap_num == 0) + *data = APB_AP_IDR; + else + *data = 0; + break; + + case MEM_AP_REG_BD0: + case MEM_AP_REG_BD1: + case MEM_AP_REG_BD2: + case MEM_AP_REG_BD3: + addr = (ap_tar & ~0xf) + (reg & 0x0C); + ap_addr_2_tile(&tile, &addr); + rc = coresight_read(tile, addr, data); + break; + + case MEM_AP_REG_DRW: + addr = (ap_tar & ~0x3) + ap_tar_inc; + ap_addr_2_tile(&tile, &addr); + rc = coresight_read(tile, addr, data); + if (!rc && (ap_csw & CSW_ADDRINC_MASK)) + ap_tar_inc += (ap_csw & 0x03) * 2; + break; + + default: + LOG_INFO("Unknown command"); + rc = ERROR_FAIL; + break; + } + + /* Track the last error code. */ + if (rc != ERROR_OK) + rshim_dap_retval = rc; + + return rc; +} + +static int rshim_ap_q_write(struct adiv5_ap *ap, unsigned int reg, + uint32_t data) +{ + int rc = ERROR_OK, tile; + uint32_t addr; + + if (ap_bank != 0) { + rshim_dap_retval = ERROR_FAIL; + return ERROR_FAIL; + } + + switch (reg) { + case MEM_AP_REG_CSW: + ap_csw = data; + break; + + case MEM_AP_REG_TAR: + ap_tar = data; + ap_tar_inc = 0; + break; + + case MEM_AP_REG_BD0: + case MEM_AP_REG_BD1: + case MEM_AP_REG_BD2: + case MEM_AP_REG_BD3: + addr = (ap_tar & ~0xf) + (reg & 0x0C); + ap_addr_2_tile(&tile, &addr); + rc = coresight_write(tile, addr, data); + break; + + case MEM_AP_REG_DRW: + ap_drw = data; + addr = (ap_tar & ~0x3) + ap_tar_inc; + ap_addr_2_tile(&tile, &addr); + rc = coresight_write(tile, addr, data); + if (!rc && (ap_csw & CSW_ADDRINC_MASK)) + ap_tar_inc += (ap_csw & 0x03) * 2; + break; + + default: + rc = EINVAL; + break; + } + + /* Track the last error code. */ + if (rc != ERROR_OK) + rshim_dap_retval = rc; + + return rc; +} + +static int rshim_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack) +{ + return ERROR_OK; +} + +static int rshim_dp_run(struct adiv5_dap *dap) +{ + int retval = rshim_dap_retval; + + /* Clear the error code. */ + rshim_dap_retval = ERROR_OK; + + return retval; +} + +static int rshim_connect(struct adiv5_dap *dap) +{ + char *path = rshim_dev_path ? rshim_dev_path : RSHIM_DEV_PATH_DEFAULT; + + rshim_fd = open(path, O_RDWR | O_SYNC); + if (rshim_fd == -1) { + LOG_ERROR("Unable to open %s\n", path); + return ERROR_FAIL; + } + + /* + * Set read/write operation via the device file. Funtion pointers + * are used here so more ways like remote accessing via socket could + * be added later. + */ + rshim_read = rshim_dev_read; + rshim_write = rshim_dev_write; + + return ERROR_OK; +} + +static void rshim_disconnect(struct adiv5_dap *dap) +{ + if (rshim_fd != -1) { + close(rshim_fd); + rshim_fd = -1; + } +} + +COMMAND_HANDLER(rshim_dap_device_command) +{ + if (CMD_ARGC != 1) { + command_print(CMD, "Too many arguments"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + free(rshim_dev_path); + rshim_dev_path = strdup(CMD_ARGV[0]); + return ERROR_OK; +} + +static const struct command_registration rshim_dap_subcommand_handlers[] = { + { + .name = "device", + .handler = rshim_dap_device_command, + .mode = COMMAND_CONFIG, + .help = "set the rshim device", + .usage = "</dev/rshim<N>/rshim>", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration rshim_dap_command_handlers[] = { + { + .name = "rshim", + .mode = COMMAND_ANY, + .help = "perform rshim management", + .chain = rshim_dap_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +static int rshim_dap_init(void) +{ + return ERROR_OK; +} + +static int rshim_dap_quit(void) +{ + return ERROR_OK; +} + +static int rshim_dap_reset(int req_trst, int req_srst) +{ + return ERROR_OK; +} + +static int rshim_dap_speed(int speed) +{ + return ERROR_OK; +} + +static int rshim_dap_khz(int khz, int *jtag_speed) +{ + *jtag_speed = khz; + return ERROR_OK; +} + +static int rshim_dap_speed_div(int speed, int *khz) +{ + *khz = speed; + return ERROR_OK; +} + +/* DAP operations. */ +static const struct dap_ops rshim_dap_ops = { + .connect = rshim_connect, + .queue_dp_read = rshim_dp_q_read, + .queue_dp_write = rshim_dp_q_write, + .queue_ap_read = rshim_ap_q_read, + .queue_ap_write = rshim_ap_q_write, + .queue_ap_abort = rshim_ap_q_abort, + .run = rshim_dp_run, + .quit = rshim_disconnect, +}; + +static const char *const rshim_dap_transport[] = { "dapdirect_swd", NULL }; + +struct adapter_driver rshim_dap_adapter_driver = { + .name = "rshim", + .transports = rshim_dap_transport, + .commands = rshim_dap_command_handlers, + + .init = rshim_dap_init, + .quit = rshim_dap_quit, + .reset = rshim_dap_reset, + .speed = rshim_dap_speed, + .khz = rshim_dap_khz, + .speed_div = rshim_dap_speed_div, + + .dap_swd_ops = &rshim_dap_ops, +}; diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index ea3dc00..72975d5 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -31,27 +31,31 @@ /* project specific includes */ #include <helper/binarybuffer.h> +#include <helper/bits.h> #include <jtag/interface.h> #include <jtag/hla/hla_layout.h> #include <jtag/hla/hla_transport.h> #include <jtag/hla/hla_interface.h> +#include <jtag/swim.h> #include <target/target.h> +#include <transport/transport.h> #include <target/cortex_m.h> -#include "libusb_common.h" +#include "libusb_helper.h" #ifdef HAVE_LIBUSB1 #define USE_LIBUSB_ASYNCIO #endif +#define STLINK_SERIAL_LEN 24 + #define ENDPOINT_IN 0x80 #define ENDPOINT_OUT 0x00 #define STLINK_WRITE_TIMEOUT 1000 #define STLINK_READ_TIMEOUT 1000 -#define STLINK_NULL_EP 0 #define STLINK_RX_EP (1|ENDPOINT_IN) #define STLINK_TX_EP (2|ENDPOINT_OUT) #define STLINK_TRACE_EP (3|ENDPOINT_IN) @@ -76,7 +80,7 @@ /* * ST-Link/V1, ST-Link/V2 and ST-Link/V2.1 are full-speed USB devices and * this limits the bulk packet size and the 8bit read/writes to max 64 bytes. - * STLINK-V3 is a high speed USB 2.0 and the limit is 512 bytes. + * STLINK-V3 is a high speed USB 2.0 and the limit is 512 bytes from FW V3J6. */ #define STLINK_MAX_RW8 (64) #define STLINKV3_MAX_RW8 (512) @@ -92,6 +96,15 @@ enum stlink_jtag_api_version { STLINK_JTAG_API_V3, }; +enum stlink_mode { + STLINK_MODE_UNKNOWN = 0, + STLINK_MODE_DFU, + STLINK_MODE_MASS, + STLINK_MODE_DEBUG_JTAG, + STLINK_MODE_DEBUG_SWD, + STLINK_MODE_DEBUG_SWIM +}; + /** */ struct stlink_usb_version { /** */ @@ -109,7 +122,7 @@ struct stlink_usb_version { /** */ struct stlink_usb_handle_s { /** */ - struct jtag_libusb_device_handle *fd; + struct libusb_device_handle *fd; /** */ struct libusb_transfer *trans; /** */ @@ -129,7 +142,7 @@ struct stlink_usb_handle_s { /** */ uint32_t max_mem_packet; /** */ - enum hl_transports transport; + enum stlink_mode st_mode; /** */ struct stlink_usb_version version; /** */ @@ -265,10 +278,14 @@ struct stlink_usb_handle_s { #define STLINK_DEBUG_APIV2_GET_TRACE_NB 0x42 #define STLINK_DEBUG_APIV2_SWD_SET_FREQ 0x43 #define STLINK_DEBUG_APIV2_JTAG_SET_FREQ 0x44 - +#define STLINK_DEBUG_APIV2_READ_DAP_REG 0x45 +#define STLINK_DEBUG_APIV2_WRITE_DAP_REG 0x46 #define STLINK_DEBUG_APIV2_READMEM_16BIT 0x47 #define STLINK_DEBUG_APIV2_WRITEMEM_16BIT 0x48 +#define STLINK_DEBUG_APIV2_INIT_AP 0x4B +#define STLINK_DEBUG_APIV2_CLOSE_AP_DBG 0x4C + #define STLINK_APIV3_SET_COM_FREQ 0x61 #define STLINK_APIV3_GET_COM_FREQ 0x62 @@ -278,21 +295,13 @@ struct stlink_usb_handle_s { #define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH 0x01 #define STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE 0x02 +#define STLINK_DEBUG_PORT_ACCESS 0xffff + #define STLINK_TRACE_SIZE 4096 #define STLINK_TRACE_MAX_HZ 2000000 #define STLINK_V3_MAX_FREQ_NB 10 -/** */ -enum stlink_mode { - STLINK_MODE_UNKNOWN = 0, - STLINK_MODE_DFU, - STLINK_MODE_MASS, - STLINK_MODE_DEBUG_JTAG, - STLINK_MODE_DEBUG_SWD, - STLINK_MODE_DEBUG_SWIM -}; - #define REQUEST_SENSE 0x03 #define REQUEST_SENSE_LENGTH 18 @@ -300,11 +309,17 @@ enum stlink_mode { * Map the relevant features, quirks and workaround for specific firmware * version of stlink */ -#define STLINK_F_HAS_TRACE (1UL << 0) -#define STLINK_F_HAS_SWD_SET_FREQ (1UL << 1) -#define STLINK_F_HAS_JTAG_SET_FREQ (1UL << 2) -#define STLINK_F_HAS_MEM_16BIT (1UL << 3) -#define STLINK_F_HAS_GETLASTRWSTATUS2 (1UL << 4) +#define STLINK_F_HAS_TRACE BIT(0) +#define STLINK_F_HAS_SWD_SET_FREQ BIT(1) +#define STLINK_F_HAS_JTAG_SET_FREQ BIT(2) +#define STLINK_F_HAS_MEM_16BIT BIT(3) +#define STLINK_F_HAS_GETLASTRWSTATUS2 BIT(4) +#define STLINK_F_HAS_DAP_REG BIT(5) +#define STLINK_F_QUIRK_JTAG_DP_READ BIT(6) +#define STLINK_F_HAS_AP_INIT BIT(7) +#define STLINK_F_HAS_DPBANKSEL BIT(8) +#define STLINK_F_HAS_RW8_512BYTES BIT(9) +#define STLINK_F_FIX_CLOSE_AP BIT(10) /* aliases */ #define STLINK_F_HAS_TARGET_VOLT STLINK_F_HAS_TRACE @@ -332,7 +347,6 @@ static const struct speed_map stlink_khz_to_speed_map_swd[] = { /* JTAG clock speed */ static const struct speed_map stlink_khz_to_speed_map_jtag[] = { - {18000, 2}, {9000, 4}, {4500, 8}, {2250, 16}, @@ -347,6 +361,7 @@ static int stlink_swim_status(void *handle); void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size); static int stlink_get_com_freq(void *handle, bool is_jtag, struct speed_map *map); static int stlink_speed(void *handle, int khz, bool query); +static int stlink_usb_open_ap(void *handle, unsigned short apsel); /** */ static unsigned int stlink_usb_block(void *handle) @@ -355,7 +370,7 @@ static unsigned int stlink_usb_block(void *handle) assert(handle != NULL); - if (h->version.stlink == 3) + if (h->version.flags & STLINK_F_HAS_RW8_512BYTES) return STLINKV3_MAX_RW8; else return STLINK_MAX_RW8; @@ -437,7 +452,8 @@ struct jtag_xfer { struct libusb_transfer *transfer; }; -static int jtag_libusb_bulk_transfer_n(jtag_libusb_device_handle *dev_handle, +static int jtag_libusb_bulk_transfer_n( + struct libusb_device_handle *dev_handle, struct jtag_xfer *transfers, size_t n_transfers, int timeout) @@ -518,14 +534,16 @@ static int jtag_libusb_bulk_transfer_n(jtag_libusb_device_handle *dev_handle, static int stlink_usb_xfer_v1_get_status(void *handle) { struct stlink_usb_handle_s *h = handle; + int tr, ret; assert(handle != NULL); /* read status */ memset(h->cmdbuf, 0, STLINK_SG_SIZE); - if (jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)h->cmdbuf, - 13, STLINK_READ_TIMEOUT) != 13) + ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)h->cmdbuf, 13, + STLINK_READ_TIMEOUT, &tr); + if (ret || tr != 13) return ERROR_FAIL; uint32_t t1; @@ -589,23 +607,26 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int size) { struct stlink_usb_handle_s *h = handle; + int tr, ret; assert(handle != NULL); - if (jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)h->cmdbuf, cmdsize, - STLINK_WRITE_TIMEOUT) != cmdsize) { + ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)h->cmdbuf, + cmdsize, STLINK_WRITE_TIMEOUT, &tr); + if (ret || tr != cmdsize) return ERROR_FAIL; - } if (h->direction == h->tx_ep && size) { - if (jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)buf, - size, STLINK_WRITE_TIMEOUT) != size) { + ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)buf, + size, STLINK_WRITE_TIMEOUT, &tr); + if (ret || tr != size) { LOG_DEBUG("bulk write failed"); return ERROR_FAIL; } } else if (h->direction == h->rx_ep && size) { - if (jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)buf, - size, STLINK_READ_TIMEOUT) != size) { + ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)buf, + size, STLINK_READ_TIMEOUT, &tr); + if (ret || tr != size) { LOG_DEBUG("bulk read failed"); return ERROR_FAIL; } @@ -691,7 +712,7 @@ static int stlink_usb_error_check(void *handle) assert(handle != NULL); - if (h->transport == HL_TRANSPORT_SWIM) { + if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { switch (h->databuf[0]) { case STLINK_SWIM_ERR_OK: return ERROR_OK; @@ -800,13 +821,13 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size) struct stlink_usb_handle_s *h = handle; while (1) { - if ((h->transport != HL_TRANSPORT_SWIM) || !retries) { + if ((h->st_mode != STLINK_MODE_DEBUG_SWIM) || !retries) { res = stlink_usb_xfer_noerrcheck(handle, buf, size); if (res != ERROR_OK) return res; } - if (h->transport == HL_TRANSPORT_SWIM) { + if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { res = stlink_swim_status(handle); if (res != ERROR_OK) return res; @@ -814,7 +835,7 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size) res = stlink_usb_error_check(handle); if (res == ERROR_WAIT && retries < MAX_WAIT_RETRIES) { - useconds_t delay_us = (1<<retries++) * 1000; + unsigned int delay_us = (1<<retries++) * 1000; LOG_DEBUG("stlink_cmd_allow_retry ERROR_WAIT, retry %d, delaying %u microseconds", retries, delay_us); usleep(delay_us); continue; @@ -827,13 +848,15 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size) static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size) { struct stlink_usb_handle_s *h = handle; + int tr, ret; assert(handle != NULL); assert(h->version.flags & STLINK_F_HAS_TRACE); - if (jtag_libusb_bulk_read(h->fd, h->trace_ep, (char *)buf, - size, STLINK_READ_TIMEOUT) != size) { + ret = jtag_libusb_bulk_read(h->fd, h->trace_ep, (char *)buf, size, + STLINK_READ_TIMEOUT, &tr); + if (ret || tr != size) { LOG_ERROR("bulk trace read failed"); return ERROR_FAIL; } @@ -991,13 +1014,32 @@ static int stlink_usb_version(void *handle) flags |= STLINK_F_HAS_SWD_SET_FREQ; /* API to set JTAG frequency from J24 */ - if (h->version.jtag >= 24) + /* API to access DAP registers from J24 */ + if (h->version.jtag >= 24) { flags |= STLINK_F_HAS_JTAG_SET_FREQ; + flags |= STLINK_F_HAS_DAP_REG; + } + + /* Quirk for read DP in JTAG mode (V2 only) from J24, fixed in J32 */ + if (h->version.jtag >= 24 && h->version.jtag < 32) + flags |= STLINK_F_QUIRK_JTAG_DP_READ; /* API to read/write memory at 16 bit from J26 */ if (h->version.jtag >= 26) flags |= STLINK_F_HAS_MEM_16BIT; + /* API required to init AP before any AP access from J28 */ + if (h->version.jtag >= 28) + flags |= STLINK_F_HAS_AP_INIT; + + /* API required to return proper error code on close AP from J29 */ + if (h->version.jtag >= 29) + flags |= STLINK_F_FIX_CLOSE_AP; + + /* Banked regs (DPv1 & DPv2) support from V2J32 */ + if (h->version.jtag >= 32) + flags |= STLINK_F_HAS_DPBANKSEL; + break; case 3: /* all STLINK-V3 use api-v3 */ @@ -1012,9 +1054,26 @@ static int stlink_usb_version(void *handle) /* preferred API to get last R/W status */ flags |= STLINK_F_HAS_GETLASTRWSTATUS2; + /* API to access DAP registers */ + flags |= STLINK_F_HAS_DAP_REG; + /* API to read/write memory at 16 bit */ flags |= STLINK_F_HAS_MEM_16BIT; + /* API required to init AP before any AP access */ + flags |= STLINK_F_HAS_AP_INIT; + + /* API required to return proper error code on close AP */ + flags |= STLINK_F_FIX_CLOSE_AP; + + /* Banked regs (DPv1 & DPv2) support from V3J2 */ + if (h->version.jtag >= 2) + flags |= STLINK_F_HAS_DPBANKSEL; + + /* 8bit read/write max packet size 512 bytes from V3J6 */ + if (h->version.jtag >= 6) + flags |= STLINK_F_HAS_RW8_512BYTES; + break; default: break; @@ -1180,9 +1239,8 @@ static int stlink_usb_mode_enter(void *handle, enum stlink_mode type) case STLINK_MODE_DEBUG_SWIM: h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER; - /* no answer for this function... */ - rx_size = 0; - break; + /* swim enter does not return any response or status */ + return stlink_usb_xfer_noerrcheck(handle, h->databuf, 0); case STLINK_MODE_DFU: case STLINK_MODE_MASS: default: @@ -1200,7 +1258,8 @@ static int stlink_usb_mode_leave(void *handle, enum stlink_mode type) assert(handle != NULL); - stlink_usb_init_buffer(handle, STLINK_NULL_EP, 0); + /* command with no reply, use a valid endpoint but zero size */ + stlink_usb_init_buffer(handle, h->rx_ep, 0); switch (type) { case STLINK_MODE_DEBUG_JTAG: @@ -1221,7 +1280,7 @@ static int stlink_usb_mode_leave(void *handle, enum stlink_mode type) return ERROR_FAIL; } - res = stlink_usb_xfer_noerrcheck(handle, 0, 0); + res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 0); if (res != ERROR_OK) return res; @@ -1238,20 +1297,17 @@ static enum stlink_mode stlink_get_mode(enum hl_transports t) return STLINK_MODE_DEBUG_SWD; case HL_TRANSPORT_JTAG: return STLINK_MODE_DEBUG_JTAG; - case HL_TRANSPORT_SWIM: - return STLINK_MODE_DEBUG_SWIM; default: return STLINK_MODE_UNKNOWN; } } /** */ -static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int initial_interface_speed) +static int stlink_usb_exit_mode(void *handle) { int res; uint8_t mode; enum stlink_mode emode; - struct stlink_usb_handle_s *h = handle; assert(handle != NULL); @@ -1280,12 +1336,25 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init break; } - if (emode != STLINK_MODE_UNKNOWN) { - res = stlink_usb_mode_leave(handle, emode); + if (emode != STLINK_MODE_UNKNOWN) + return stlink_usb_mode_leave(handle, emode); - if (res != ERROR_OK) - return res; - } + return ERROR_OK; +} + +/** */ +static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int initial_interface_speed) +{ + int res; + uint8_t mode; + enum stlink_mode emode; + struct stlink_usb_handle_s *h = handle; + + assert(handle != NULL); + + res = stlink_usb_exit_mode(handle); + if (res != ERROR_OK) + return res; res = stlink_usb_current_mode(handle, &mode); @@ -1318,7 +1387,7 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init LOG_DEBUG("MODE: 0x%02X", mode); /* set selected mode */ - emode = stlink_get_mode(h->transport); + emode = h->st_mode; if (emode == STLINK_MODE_UNKNOWN) { LOG_ERROR("selected mode (transport) not supported"); @@ -1326,12 +1395,12 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init } /* set the speed before entering the mode, as the chip discovery phase should be done at this speed too */ - if (h->transport == HL_TRANSPORT_JTAG) { + if (emode == STLINK_MODE_DEBUG_JTAG) { if (h->version.flags & STLINK_F_HAS_JTAG_SET_FREQ) { stlink_dump_speed_map(stlink_khz_to_speed_map_jtag, ARRAY_SIZE(stlink_khz_to_speed_map_jtag)); stlink_speed(h, initial_interface_speed, false); } - } else if (h->transport == HL_TRANSPORT_SWD) { + } else if (emode == STLINK_MODE_DEBUG_SWD) { if (h->version.flags & STLINK_F_HAS_SWD_SET_FREQ) { stlink_dump_speed_map(stlink_khz_to_speed_map_swd, ARRAY_SIZE(stlink_khz_to_speed_map_swd)); stlink_speed(h, initial_interface_speed, false); @@ -1341,7 +1410,7 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init if (h->version.jtag_api == STLINK_JTAG_API_V3) { struct speed_map map[STLINK_V3_MAX_FREQ_NB]; - stlink_get_com_freq(h, (h->transport == HL_TRANSPORT_JTAG), map); + stlink_get_com_freq(h, (emode == STLINK_MODE_DEBUG_JTAG), map); stlink_dump_speed_map(map, ARRAY_SIZE(map)); stlink_speed(h, initial_interface_speed, false); } @@ -1582,7 +1651,7 @@ static int stlink_usb_idcode(void *handle, uint32_t *idcode) assert(handle != NULL); /* there is no swim read core id cmd */ - if (h->transport == HL_TRANSPORT_SWIM) { + if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { *idcode = 0; return ERROR_OK; } @@ -1713,22 +1782,9 @@ static enum target_state stlink_usb_state(void *handle) assert(handle != NULL); - if (h->transport == HL_TRANSPORT_SWIM) { - res = stlink_usb_mode_enter(handle, stlink_get_mode(h->transport)); - if (res != ERROR_OK) - return TARGET_UNKNOWN; - - res = stlink_swim_resync(handle); - if (res != ERROR_OK) - return TARGET_UNKNOWN; - - return ERROR_OK; - } - if (h->reconnect_pending) { LOG_INFO("Previous state query failed, trying to reconnect"); - res = stlink_usb_mode_enter(handle, stlink_get_mode(h->transport)); - + res = stlink_usb_mode_enter(handle, h->st_mode); if (res != ERROR_OK) return TARGET_UNKNOWN; @@ -1768,7 +1824,7 @@ static int stlink_usb_assert_srst(void *handle, int srst) assert(handle != NULL); - if (h->transport == HL_TRANSPORT_SWIM) + if (h->st_mode == STLINK_MODE_DEBUG_SWIM) return stlink_swim_assert_reset(handle, srst); if (h->version.stlink == 1) @@ -1845,9 +1901,6 @@ static int stlink_usb_reset(void *handle) assert(handle != NULL); - if (h->transport == HL_TRANSPORT_SWIM) - return stlink_swim_generate_rst(handle); - stlink_usb_init_buffer(handle, h->rx_ep, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; @@ -2269,17 +2322,12 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size, while (count) { - bytes_remaining = (size != 1) ? \ + bytes_remaining = (size != 1) ? stlink_max_block_size(h->max_mem_packet, addr) : stlink_usb_block(h); if (count < bytes_remaining) bytes_remaining = count; - if (h->transport == HL_TRANSPORT_SWIM) { - retval = stlink_swim_readbytes(handle, addr, bytes_remaining, buffer); - if (retval != ERROR_OK) - return retval; - } else /* * all stlink support 8/32bit memory read/writes and only from * stlink V2J26 there is support for 16 bit memory read/write. @@ -2354,17 +2402,12 @@ static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size, while (count) { - bytes_remaining = (size != 1) ? \ + bytes_remaining = (size != 1) ? stlink_max_block_size(h->max_mem_packet, addr) : stlink_usb_block(h); if (count < bytes_remaining) bytes_remaining = count; - if (h->transport == HL_TRANSPORT_SWIM) { - retval = stlink_swim_writebytes(handle, addr, bytes_remaining, buffer); - if (retval != ERROR_OK) - return retval; - } else /* * all stlink support 8/32bit memory read/writes and only from * stlink V2J26 there is support for 16 bit memory read/write. @@ -2430,17 +2473,20 @@ static int stlink_usb_override_target(const char *targetname) static int stlink_speed_swim(void *handle, int khz, bool query) { + int retval; + /* - we dont care what the khz rate is we only have low and high speed... before changing speed the SWIM_CSR HS bit must be updated */ - if (khz == 0) - stlink_swim_speed(handle, 0); - else - stlink_swim_speed(handle, 1); - return khz; + if (!query) { + retval = stlink_swim_speed(handle, (khz < SWIM_FREQ_HIGH) ? 0 : 1); + if (retval != ERROR_OK) + LOG_ERROR("Unable to set adapter speed"); + } + + return (khz < SWIM_FREQ_HIGH) ? SWIM_FREQ_LOW : SWIM_FREQ_HIGH; } static int stlink_match_speed_map(const struct speed_map *map, unsigned int map_size, int khz, bool query) @@ -2478,7 +2524,7 @@ static int stlink_match_speed_map(const struct speed_map *map, unsigned int map_ match = false; if (!match && query) { - LOG_INFO("Unable to match requested speed %d kHz, using %d kHz", \ + LOG_INFO("Unable to match requested speed %d kHz, using %d kHz", khz, map[speed_index].speed); } @@ -2624,17 +2670,16 @@ static int stlink_speed(void *handle, int khz, bool query) if (!handle) return khz; - switch (h->transport) { - case HL_TRANSPORT_SWIM: + switch (h->st_mode) { + case STLINK_MODE_DEBUG_SWIM: return stlink_speed_swim(handle, khz, query); - break; - case HL_TRANSPORT_SWD: + case STLINK_MODE_DEBUG_SWD: if (h->version.jtag_api == STLINK_JTAG_API_V3) return stlink_speed_v3(handle, false, khz, query); else return stlink_speed_swd(handle, khz, query); break; - case HL_TRANSPORT_JTAG: + case STLINK_MODE_DEBUG_JTAG: if (h->version.jtag_api == STLINK_JTAG_API_V3) return stlink_speed_v3(handle, true, khz, query); else @@ -2650,53 +2695,101 @@ static int stlink_speed(void *handle, int khz, bool query) /** */ static int stlink_usb_close(void *handle) { - int res; - uint8_t mode; - enum stlink_mode emode; struct stlink_usb_handle_s *h = handle; - if (h && h->fd) - res = stlink_usb_current_mode(handle, &mode); - else - res = ERROR_FAIL; - /* do not exit if return code != ERROR_OK, - it prevents us from closing jtag_libusb */ - - if (res == ERROR_OK) { - /* try to exit current mode */ - switch (mode) { - case STLINK_DEV_DFU_MODE: - emode = STLINK_MODE_DFU; - break; - case STLINK_DEV_DEBUG_MODE: - emode = STLINK_MODE_DEBUG_SWD; - break; - case STLINK_DEV_SWIM_MODE: - emode = STLINK_MODE_DEBUG_SWIM; - break; - case STLINK_DEV_BOOTLOADER_MODE: - case STLINK_DEV_MASS_MODE: - default: - emode = STLINK_MODE_UNKNOWN; - break; - } - - if (emode != STLINK_MODE_UNKNOWN) - stlink_usb_mode_leave(handle, emode); - /* do not check return code, it prevent - us from closing jtag_libusb */ - } - - if (h && h->fd) + if (h && h->fd) { + stlink_usb_exit_mode(h); + /* do not check return code, it prevent + us from closing jtag_libusb */ jtag_libusb_close(h->fd); + } free(h); return ERROR_OK; } +/* Compute ST-Link serial number from the device descriptor + * this function will help to work-around a bug in old ST-Link/V2 DFU + * the buggy DFU returns an incorrect serial in the USB descriptor + * example for the following serial "57FF72067265575742132067" + * - the correct descriptor serial is: + * 0x32, 0x03, 0x35, 0x00, 0x37, 0x00, 0x46, 0x00, 0x46, 0x00, 0x37, 0x00, 0x32, 0x00 ... + * this contains the length (0x32 = 50), the type (0x3 = DT_STRING) and the serial in unicode format + * the serial part is: 0x0035, 0x0037, 0x0046, 0x0046, 0x0037, 0x0032 ... >> 57FF72 ... + * this format could be read correctly by 'libusb_get_string_descriptor_ascii' + * so this case is managed by libusb_helper::string_descriptor_equal + * - the buggy DFU is not doing any unicode conversion and returns a raw serial data in the descriptor + * 0x1a, 0x03, 0x57, 0x00, 0xFF, 0x00, 0x72, 0x00 ... + * >> 57 FF 72 ... + * based on the length (0x1a = 26) we could easily decide if we have to fixup the serial + * and then we have just to convert the raw data into printable characters using sprintf + */ +char *stlink_usb_get_alternate_serial(libusb_device_handle *device, + struct libusb_device_descriptor *dev_desc) +{ + int usb_retval; + unsigned char desc_serial[(STLINK_SERIAL_LEN + 1) * 2]; + + if (dev_desc->iSerialNumber == 0) + return NULL; + + /* get the LANGID from String Descriptor Zero */ + usb_retval = libusb_get_string_descriptor(device, 0, 0, desc_serial, + sizeof(desc_serial)); + + if (usb_retval < LIBUSB_SUCCESS) { + LOG_ERROR("libusb_get_string_descriptor() failed: %s(%d)", + libusb_error_name(usb_retval), usb_retval); + return NULL; + } else if (usb_retval < 4) { + /* the size should be least 4 bytes to contain a minimum of 1 supported LANGID */ + LOG_ERROR("could not get the LANGID"); + return NULL; + } + + uint32_t langid = desc_serial[2] | (desc_serial[3] << 8); + + /* get the serial */ + usb_retval = libusb_get_string_descriptor(device, dev_desc->iSerialNumber, + langid, desc_serial, sizeof(desc_serial)); + + unsigned char len = desc_serial[0]; + + if (usb_retval < LIBUSB_SUCCESS) { + LOG_ERROR("libusb_get_string_descriptor() failed: %s(%d)", + libusb_error_name(usb_retval), usb_retval); + return NULL; + } else if (desc_serial[1] != LIBUSB_DT_STRING || len > usb_retval) { + LOG_ERROR("invalid string in ST-LINK USB serial descriptor"); + return NULL; + } + + if (len == ((STLINK_SERIAL_LEN + 1) * 2)) { + /* good ST-Link adapter, this case is managed by + * libusb::libusb_get_string_descriptor_ascii */ + return NULL; + } else if (len != ((STLINK_SERIAL_LEN / 2 + 1) * 2)) { + LOG_ERROR("unexpected serial length (%d) in descriptor", len); + return NULL; + } + + /* else (len == 26) => buggy ST-Link */ + + char *alternate_serial = malloc((STLINK_SERIAL_LEN + 1) * sizeof(char)); + if (alternate_serial == NULL) + return NULL; + + for (unsigned int i = 0; i < STLINK_SERIAL_LEN; i += 2) + sprintf(alternate_serial + i, "%02X", desc_serial[i + 2]); + + alternate_serial[STLINK_SERIAL_LEN] = '\0'; + + return alternate_serial; +} + /** */ -static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) +static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd) { int err, retry_count = 1; struct stlink_usb_handle_s *h; @@ -2710,11 +2803,11 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) return ERROR_FAIL; } - h->transport = param->transport; + h->st_mode = mode; for (unsigned i = 0; param->vid[i]; i++) { LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", - param->transport, param->vid[i], param->pid[i], + h->st_mode, param->vid[i], param->pid[i], param->serial ? param->serial : ""); } @@ -2728,14 +2821,15 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) in order to become operational. */ do { - if (jtag_libusb_open(param->vid, param->pid, param->serial, &h->fd) != ERROR_OK) { + if (jtag_libusb_open(param->vid, param->pid, param->serial, + &h->fd, stlink_usb_get_alternate_serial) != ERROR_OK) { LOG_ERROR("open failed"); goto error_open; } jtag_libusb_set_configuration(h->fd, 0); - if (jtag_libusb_claim_interface(h->fd, 0) != ERROR_OK) { + if (libusb_claim_interface(h->fd, 0) != ERROR_OK) { LOG_DEBUG("claim interface failed"); goto error_open; } @@ -2744,7 +2838,7 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) h->rx_ep = STLINK_RX_EP; uint16_t pid; - if (jtag_libusb_get_pid(jtag_libusb_get_device(h->fd), &pid) != ERROR_OK) { + if (jtag_libusb_get_pid(libusb_get_device(h->fd), &pid) != ERROR_OK) { LOG_DEBUG("libusb_get_pid failed"); goto error_open; } @@ -2788,13 +2882,13 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) LOG_ERROR("read version failed"); goto error_open; } else { - err = jtag_libusb_release_interface(h->fd, 0); + err = libusb_release_interface(h->fd, 0); if (err != ERROR_OK) { LOG_ERROR("release interface failed"); goto error_open; } - err = jtag_libusb_reset_device(h->fd); + err = libusb_reset_device(h->fd); if (err != ERROR_OK) { LOG_ERROR("reset device failed"); goto error_open; @@ -2813,16 +2907,16 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) /* check if mode is supported */ err = ERROR_OK; - switch (h->transport) { - case HL_TRANSPORT_SWD: + switch (h->st_mode) { + case STLINK_MODE_DEBUG_SWD: if (h->version.jtag_api == STLINK_JTAG_API_V1) err = ERROR_FAIL; /* fall-through */ - case HL_TRANSPORT_JTAG: + case STLINK_MODE_DEBUG_JTAG: if (h->version.jtag == 0) err = ERROR_FAIL; break; - case HL_TRANSPORT_SWIM: + case STLINK_MODE_DEBUG_SWIM: if (h->version.swim == 0) err = ERROR_FAIL; break; @@ -2844,7 +2938,7 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) goto error_open; } - if (h->transport == HL_TRANSPORT_SWIM) { + if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { err = stlink_swim_enter(h); if (err != ERROR_OK) { LOG_ERROR("stlink_swim_enter_failed (unable to connect to the target)"); @@ -2860,6 +2954,7 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) h->max_mem_packet = (1 << 10); uint8_t buffer[4]; + stlink_usb_open_ap(h, 0); err = stlink_usb_read_mem32(h, CPUID, 4, buffer); if (err == ERROR_OK) { uint32_t cpuid = le_to_h_u32(buffer); @@ -2882,10 +2977,18 @@ error_open: return ERROR_FAIL; } -int stlink_config_trace(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol, - uint32_t port_size, unsigned int *trace_freq) +static int stlink_usb_hl_open(struct hl_interface_param_s *param, void **fd) +{ + return stlink_usb_open(param, stlink_get_mode(param->transport), fd); +} + +int stlink_config_trace(void *handle, bool enabled, + enum tpiu_pin_protocol pin_protocol, uint32_t port_size, + unsigned int *trace_freq, unsigned int traceclkin_freq, + uint16_t *prescaler) { struct stlink_usb_handle_s *h = handle; + uint16_t presc; if (enabled && (!(h->version.flags & STLINK_F_HAS_TRACE) || pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART)) { @@ -2908,15 +3011,116 @@ int stlink_config_trace(void *handle, bool enabled, enum tpiu_pin_protocol pin_p if (!*trace_freq) *trace_freq = STLINK_TRACE_MAX_HZ; + + presc = traceclkin_freq / *trace_freq; + + if (traceclkin_freq % *trace_freq > 0) + presc++; + + if (presc > TPIU_ACPR_MAX_SWOSCALER) { + LOG_ERROR("SWO frequency is not suitable. Please choose a different " + "frequency."); + return ERROR_FAIL; + } + + *prescaler = presc; h->trace.source_hz = *trace_freq; return stlink_usb_trace_enable(h); } /** */ +static int stlink_usb_init_access_port(void *handle, unsigned char ap_num) +{ + struct stlink_usb_handle_s *h = handle; + + assert(handle != NULL); + + if (!(h->version.flags & STLINK_F_HAS_AP_INIT)) + return ERROR_COMMAND_NOTFOUND; + + LOG_DEBUG_IO("init ap_num = %d", ap_num); + stlink_usb_init_buffer(handle, h->rx_ep, 16); + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_INIT_AP; + h->cmdbuf[h->cmdidx++] = ap_num; + + return stlink_usb_xfer_errcheck(handle, h->databuf, 2); +} + +/** */ +static int stlink_usb_close_access_port(void *handle, unsigned char ap_num) +{ + struct stlink_usb_handle_s *h = handle; + + assert(handle != NULL); + + if (!(h->version.flags & STLINK_F_HAS_AP_INIT)) + return ERROR_COMMAND_NOTFOUND; + + LOG_DEBUG_IO("close ap_num = %d", ap_num); + stlink_usb_init_buffer(handle, h->rx_ep, 16); + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_CLOSE_AP_DBG; + h->cmdbuf[h->cmdidx++] = ap_num; + + /* ignore incorrectly returned error on bogus FW */ + if (h->version.flags & STLINK_F_FIX_CLOSE_AP) + return stlink_usb_xfer_errcheck(handle, h->databuf, 2); + else + return stlink_usb_xfer_noerrcheck(handle, h->databuf, 2); + +} + +/** */ +static int stlink_read_dap_register(void *handle, unsigned short dap_port, + unsigned short addr, uint32_t *val) +{ + struct stlink_usb_handle_s *h = handle; + int retval; + + assert(handle != NULL); + + if (!(h->version.flags & STLINK_F_HAS_DAP_REG)) + return ERROR_COMMAND_NOTFOUND; + + stlink_usb_init_buffer(handle, h->rx_ep, 16); + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READ_DAP_REG; + h_u16_to_le(&h->cmdbuf[2], dap_port); + h_u16_to_le(&h->cmdbuf[4], addr); + + retval = stlink_usb_xfer_errcheck(handle, h->databuf, 8); + *val = le_to_h_u32(h->databuf + 4); + LOG_DEBUG_IO("dap_port_read = %d, addr = 0x%x, value = 0x%x", dap_port, addr, *val); + return retval; +} + +/** */ +static int stlink_write_dap_register(void *handle, unsigned short dap_port, + unsigned short addr, uint32_t val) +{ + struct stlink_usb_handle_s *h = handle; + + assert(handle != NULL); + + if (!(h->version.flags & STLINK_F_HAS_DAP_REG)) + return ERROR_COMMAND_NOTFOUND; + + LOG_DEBUG_IO("dap_write port = %d, addr = 0x%x, value = 0x%x", dap_port, addr, val); + stlink_usb_init_buffer(handle, h->rx_ep, 16); + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITE_DAP_REG; + h_u16_to_le(&h->cmdbuf[2], dap_port); + h_u16_to_le(&h->cmdbuf[4], addr); + h_u32_to_le(&h->cmdbuf[6], val); + return stlink_usb_xfer_errcheck(handle, h->databuf, 2); +} + +/** */ struct hl_layout_api_s stlink_usb_layout_api = { /** */ - .open = stlink_usb_open, + .open = stlink_usb_hl_open, /** */ .close = stlink_usb_close, /** */ @@ -2954,3 +3158,648 @@ struct hl_layout_api_s stlink_usb_layout_api = { /** */ .poll_trace = stlink_usb_trace_read, }; + +/***************************************************************************** + * DAP direct interface + */ + +static struct stlink_usb_handle_s *stlink_dap_handle; +static struct hl_interface_param_s stlink_dap_param; +static DECLARE_BITMAP(opened_ap, DP_APSEL_MAX + 1); +static int stlink_dap_error = ERROR_OK; + +static int stlink_dap_op_queue_dp_read(struct adiv5_dap *dap, unsigned reg, + uint32_t *data); + +/** */ +static int stlink_dap_record_error(int error) +{ + if (stlink_dap_error == ERROR_OK) + stlink_dap_error = error; + return ERROR_OK; +} + +/** */ +static int stlink_dap_get_and_clear_error(void) +{ + int retval = stlink_dap_error; + stlink_dap_error = ERROR_OK; + return retval; +} + +static int stlink_usb_open_ap(void *handle, unsigned short apsel) +{ + struct stlink_usb_handle_s *h = handle; + int retval; + + /* nothing to do on old versions */ + if (!(h->version.flags & STLINK_F_HAS_AP_INIT)) + return ERROR_OK; + + if (apsel > DP_APSEL_MAX) + return ERROR_FAIL; + + if (test_bit(apsel, opened_ap)) + return ERROR_OK; + + retval = stlink_usb_init_access_port(h, apsel); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("AP %d enabled", apsel); + set_bit(apsel, opened_ap); + return ERROR_OK; +} + +static int stlink_dap_open_ap(unsigned short apsel) +{ + return stlink_usb_open_ap(stlink_dap_handle, apsel); +} + +/** */ +static int stlink_dap_closeall_ap(void) +{ + int retval, apsel; + + /* nothing to do on old versions */ + if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_AP_INIT)) + return ERROR_OK; + + for (apsel = 0; apsel <= DP_APSEL_MAX; apsel++) { + if (!test_bit(apsel, opened_ap)) + continue; + retval = stlink_usb_close_access_port(stlink_dap_handle, apsel); + if (retval != ERROR_OK) + return retval; + clear_bit(apsel, opened_ap); + } + return ERROR_OK; +} + +/** */ +static int stlink_dap_reinit_interface(void) +{ + int retval; + + /* + * On JTAG only, it should be enough to call stlink_usb_reset(). But on + * some firmware version it does not work as expected, and there is no + * equivalent for SWD. + * At least for now, to reset the interface quit from JTAG/SWD mode then + * select the mode again. + */ + + if (!stlink_dap_handle->reconnect_pending) { + stlink_dap_handle->reconnect_pending = true; + stlink_usb_mode_leave(stlink_dap_handle, stlink_dap_handle->st_mode); + } + + retval = stlink_usb_mode_enter(stlink_dap_handle, stlink_dap_handle->st_mode); + if (retval != ERROR_OK) + return retval; + + stlink_dap_handle->reconnect_pending = false; + /* on new FW, calling mode-leave closes all the opened AP; reopen them! */ + if (stlink_dap_handle->version.flags & STLINK_F_HAS_AP_INIT) + for (int apsel = 0; apsel <= DP_APSEL_MAX; apsel++) + if (test_bit(apsel, opened_ap)) { + clear_bit(apsel, opened_ap); + stlink_dap_open_ap(apsel); + } + return ERROR_OK; +} + +/** */ +static int stlink_dap_op_connect(struct adiv5_dap *dap) +{ + uint32_t idcode; + int retval; + + LOG_INFO("stlink_dap_op_connect(%sconnect)", dap->do_reconnect ? "re" : ""); + + /* Check if we should reset srst already when connecting, but not if reconnecting. */ + if (!dap->do_reconnect) { + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { + if (jtag_reset_config & RESET_SRST_NO_GATING) + adapter_assert_reset(); + else + LOG_WARNING("\'srst_nogate\' reset_config option is required"); + } + } + + dap->do_reconnect = false; + dap_invalidate_cache(dap); + + retval = dap_dp_init(dap); + if (retval != ERROR_OK) { + dap->do_reconnect = true; + return retval; + } + + retval = stlink_usb_idcode(stlink_dap_handle, &idcode); + if (retval == ERROR_OK) + LOG_INFO("%s %#8.8" PRIx32, + (stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG) ? "JTAG IDCODE" : "SWD DPIDR", + idcode); + else + dap->do_reconnect = true; + + return retval; +} + +/** */ +static int stlink_dap_check_reconnect(struct adiv5_dap *dap) +{ + int retval; + + if (!dap->do_reconnect) + return ERROR_OK; + + retval = stlink_dap_reinit_interface(); + if (retval != ERROR_OK) + return retval; + + return stlink_dap_op_connect(dap); +} + +/** */ +static int stlink_dap_op_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq) +{ + /* Ignore the request */ + return ERROR_OK; +} + +/** */ +static int stlink_dap_op_queue_dp_read(struct adiv5_dap *dap, unsigned reg, + uint32_t *data) +{ + uint32_t dummy; + int retval; + + if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_DPBANKSEL)) + if (reg & 0x000000F0) { + LOG_ERROR("Banked DP registers not supported in current STLink FW"); + return ERROR_COMMAND_NOTFOUND; + } + + retval = stlink_dap_check_reconnect(dap); + if (retval != ERROR_OK) + return retval; + + data = data ? : &dummy; + if (stlink_dap_handle->version.flags & STLINK_F_QUIRK_JTAG_DP_READ + && stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG) { + /* Quirk required in JTAG. Read RDBUFF to get the data */ + retval = stlink_read_dap_register(stlink_dap_handle, + STLINK_DEBUG_PORT_ACCESS, reg, &dummy); + if (retval == ERROR_OK) + retval = stlink_read_dap_register(stlink_dap_handle, + STLINK_DEBUG_PORT_ACCESS, DP_RDBUFF, data); + } else { + retval = stlink_read_dap_register(stlink_dap_handle, + STLINK_DEBUG_PORT_ACCESS, reg, data); + } + + return stlink_dap_record_error(retval); +} + +/** */ +static int stlink_dap_op_queue_dp_write(struct adiv5_dap *dap, unsigned reg, + uint32_t data) +{ + int retval; + + if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_DPBANKSEL)) + if (reg & 0x000000F0) { + LOG_ERROR("Banked DP registers not supported in current STLink FW"); + return ERROR_COMMAND_NOTFOUND; + } + + if (reg == DP_SELECT && (data & DP_SELECT_DPBANK) != 0) { + /* ignored if STLINK_F_HAS_DPBANKSEL, not properly managed otherwise */ + LOG_DEBUG("Ignoring DPBANKSEL while write SELECT"); + data &= ~DP_SELECT_DPBANK; + } + + retval = stlink_dap_check_reconnect(dap); + if (retval != ERROR_OK) + return retval; + + /* ST-Link does not like that we set CORUNDETECT */ + if (reg == DP_CTRL_STAT) + data &= ~CORUNDETECT; + + retval = stlink_write_dap_register(stlink_dap_handle, + STLINK_DEBUG_PORT_ACCESS, reg, data); + return stlink_dap_record_error(retval); +} + +/** */ +static int stlink_dap_op_queue_ap_read(struct adiv5_ap *ap, unsigned reg, + uint32_t *data) +{ + struct adiv5_dap *dap = ap->dap; + uint32_t dummy; + int retval; + + retval = stlink_dap_check_reconnect(dap); + if (retval != ERROR_OK) + return retval; + + if (reg != AP_REG_IDR) { + retval = stlink_dap_open_ap(ap->ap_num); + if (retval != ERROR_OK) + return retval; + } + data = data ? : &dummy; + retval = stlink_read_dap_register(stlink_dap_handle, ap->ap_num, reg, + data); + dap->stlink_flush_ap_write = false; + return stlink_dap_record_error(retval); +} + +/** */ +static int stlink_dap_op_queue_ap_write(struct adiv5_ap *ap, unsigned reg, + uint32_t data) +{ + struct adiv5_dap *dap = ap->dap; + int retval; + + retval = stlink_dap_check_reconnect(dap); + if (retval != ERROR_OK) + return retval; + + retval = stlink_dap_open_ap(ap->ap_num); + if (retval != ERROR_OK) + return retval; + + retval = stlink_write_dap_register(stlink_dap_handle, ap->ap_num, reg, + data); + dap->stlink_flush_ap_write = true; + return stlink_dap_record_error(retval); +} + +/** */ +static int stlink_dap_op_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) +{ + LOG_WARNING("stlink_dap_op_queue_ap_abort()"); + return ERROR_OK; +} + +/** */ +static int stlink_dap_op_run(struct adiv5_dap *dap) +{ + uint32_t ctrlstat, pwrmask; + int retval, saved_retval; + + /* Here no LOG_DEBUG. This is called continuously! */ + + /* + * ST-Link returns immediately after a DAP write, without waiting for it + * to complete. + * Run a dummy read to DP_RDBUFF, as suggested in + * http://infocenter.arm.com/help/topic/com.arm.doc.faqs/ka16363.html + */ + if (dap->stlink_flush_ap_write) { + dap->stlink_flush_ap_write = false; + retval = stlink_dap_op_queue_dp_read(dap, DP_RDBUFF, NULL); + if (retval != ERROR_OK) { + dap->do_reconnect = true; + return retval; + } + } + + saved_retval = stlink_dap_get_and_clear_error(); + + retval = stlink_dap_op_queue_dp_read(dap, DP_CTRL_STAT, &ctrlstat); + if (retval != ERROR_OK) { + dap->do_reconnect = true; + return retval; + } + retval = stlink_dap_get_and_clear_error(); + if (retval != ERROR_OK) { + LOG_ERROR("Fail reading CTRL/STAT register. Force reconnect"); + dap->do_reconnect = true; + return retval; + } + + if (ctrlstat & SSTICKYERR) { + if (stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG) + retval = stlink_dap_op_queue_dp_write(dap, DP_CTRL_STAT, + ctrlstat & (dap->dp_ctrl_stat | SSTICKYERR)); + else + retval = stlink_dap_op_queue_dp_write(dap, DP_ABORT, STKERRCLR); + if (retval != ERROR_OK) { + dap->do_reconnect = true; + return retval; + } + retval = stlink_dap_get_and_clear_error(); + if (retval != ERROR_OK) { + dap->do_reconnect = true; + return retval; + } + } + + /* check for power lost */ + pwrmask = dap->dp_ctrl_stat & (CDBGPWRUPREQ | CSYSPWRUPREQ); + if ((ctrlstat & pwrmask) != pwrmask) + dap->do_reconnect = true; + + return saved_retval; +} + +/** */ +static void stlink_dap_op_quit(struct adiv5_dap *dap) +{ + int retval; + + retval = stlink_dap_closeall_ap(); + if (retval != ERROR_OK) + LOG_ERROR("Error closing APs"); +} + +static int stlink_swim_op_srst(void) +{ + return stlink_swim_generate_rst(stlink_dap_handle); +} + +static int stlink_swim_op_read_mem(uint32_t addr, uint32_t size, + uint32_t count, uint8_t *buffer) +{ + int retval; + uint32_t bytes_remaining; + + LOG_DEBUG_IO("read at 0x%08x len %d*0x%08x", addr, size, count); + count *= size; + + while (count) { + bytes_remaining = (count > STLINK_DATA_SIZE) ? STLINK_DATA_SIZE : count; + retval = stlink_swim_readbytes(stlink_dap_handle, addr, bytes_remaining, buffer); + if (retval != ERROR_OK) + return retval; + + buffer += bytes_remaining; + addr += bytes_remaining; + count -= bytes_remaining; + } + + return ERROR_OK; +} + +static int stlink_swim_op_write_mem(uint32_t addr, uint32_t size, + uint32_t count, const uint8_t *buffer) +{ + int retval; + uint32_t bytes_remaining; + + LOG_DEBUG_IO("write at 0x%08x len %d*0x%08x", addr, size, count); + count *= size; + + while (count) { + bytes_remaining = (count > STLINK_DATA_SIZE) ? STLINK_DATA_SIZE : count; + retval = stlink_swim_writebytes(stlink_dap_handle, addr, bytes_remaining, buffer); + if (retval != ERROR_OK) + return retval; + + buffer += bytes_remaining; + addr += bytes_remaining; + count -= bytes_remaining; + } + + return ERROR_OK; +} + +static int stlink_swim_op_reconnect(void) +{ + int retval; + + retval = stlink_usb_mode_enter(stlink_dap_handle, STLINK_MODE_DEBUG_SWIM); + if (retval != ERROR_OK) + return retval; + + return stlink_swim_resync(stlink_dap_handle); +} + +static int stlink_dap_config_trace(bool enabled, + enum tpiu_pin_protocol pin_protocol, uint32_t port_size, + unsigned int *trace_freq, unsigned int traceclkin_freq, + uint16_t *prescaler) +{ + return stlink_config_trace(stlink_dap_handle, enabled, pin_protocol, + port_size, trace_freq, traceclkin_freq, + prescaler); +} + +static int stlink_dap_trace_read(uint8_t *buf, size_t *size) +{ + return stlink_usb_trace_read(stlink_dap_handle, buf, size); +} + +/** */ +COMMAND_HANDLER(stlink_dap_serial_command) +{ + LOG_DEBUG("stlink_dap_serial_command"); + + if (CMD_ARGC != 1) { + LOG_ERROR("Expected exactly one argument for \"st-link serial <serial-number>\"."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (stlink_dap_param.serial) { + LOG_WARNING("Command \"st-link serial\" already used. Replacing previous value"); + free((void *)stlink_dap_param.serial); + } + + stlink_dap_param.serial = strdup(CMD_ARGV[0]); + return ERROR_OK; +} + +/** */ +COMMAND_HANDLER(stlink_dap_vid_pid) +{ + unsigned int i, max_usb_ids = HLA_MAX_USB_IDS; + + if (CMD_ARGC > max_usb_ids * 2) { + LOG_WARNING("ignoring extra IDs in vid_pid " + "(maximum is %d pairs)", max_usb_ids); + CMD_ARGC = max_usb_ids * 2; + } + if (CMD_ARGC < 2 || (CMD_ARGC & 1)) { + LOG_WARNING("incomplete vid_pid configuration directive"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + for (i = 0; i < CMD_ARGC; i += 2) { + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], stlink_dap_param.vid[i / 2]); + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], stlink_dap_param.pid[i / 2]); + } + + /* null termination */ + stlink_dap_param.vid[i / 2] = stlink_dap_param.pid[i / 2] = 0; + + return ERROR_OK; +} + +/** */ +static const struct command_registration stlink_dap_subcommand_handlers[] = { + { + .name = "serial", + .handler = stlink_dap_serial_command, + .mode = COMMAND_CONFIG, + .help = "set the serial number of the adapter", + .usage = "<serial_number>", + }, + { + .name = "vid_pid", + .handler = stlink_dap_vid_pid, + .mode = COMMAND_CONFIG, + .help = "USB VID and PID of the adapter", + .usage = "(vid pid)+", + }, + COMMAND_REGISTRATION_DONE +}; + +/** */ +static const struct command_registration stlink_dap_command_handlers[] = { + { + .name = "st-link", + .mode = COMMAND_ANY, + .help = "perform st-link management", + .chain = stlink_dap_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +/** */ +static int stlink_dap_init(void) +{ + enum reset_types jtag_reset_config = jtag_get_reset_config(); + enum stlink_mode mode; + int retval; + + LOG_DEBUG("stlink_dap_init()"); + + if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { + if (jtag_reset_config & RESET_SRST_NO_GATING) + stlink_dap_param.connect_under_reset = true; + else + LOG_WARNING("\'srst_nogate\' reset_config option is required"); + } + + if (transport_is_dapdirect_swd()) + mode = STLINK_MODE_DEBUG_SWD; + else if (transport_is_dapdirect_jtag()) + mode = STLINK_MODE_DEBUG_JTAG; + else if (transport_is_swim()) + mode = STLINK_MODE_DEBUG_SWIM; + else { + LOG_ERROR("Unsupported transport"); + return ERROR_FAIL; + } + + retval = stlink_usb_open(&stlink_dap_param, mode, (void **)&stlink_dap_handle); + if (retval != ERROR_OK) + return retval; + + if ((mode != STLINK_MODE_DEBUG_SWIM) && + !(stlink_dap_handle->version.flags & STLINK_F_HAS_DAP_REG)) { + LOG_ERROR("ST-Link version does not support DAP direct transport"); + return ERROR_FAIL; + } + return ERROR_OK; +} + +/** */ +static int stlink_dap_quit(void) +{ + LOG_DEBUG("stlink_dap_quit()"); + + free((void *)stlink_dap_param.serial); + stlink_dap_param.serial = NULL; + + return stlink_usb_close(stlink_dap_handle); +} + +/** */ +static int stlink_dap_reset(int req_trst, int req_srst) +{ + LOG_DEBUG("stlink_dap_reset(%d)", req_srst); + return stlink_usb_assert_srst(stlink_dap_handle, + req_srst ? STLINK_DEBUG_APIV2_DRIVE_NRST_LOW + : STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH); +} + +/** */ +static int stlink_dap_speed(int speed) +{ + if (speed == 0) { + LOG_ERROR("RTCK not supported. Set nonzero adapter_khz."); + return ERROR_JTAG_NOT_IMPLEMENTED; + } + + stlink_dap_param.initial_interface_speed = speed; + stlink_speed(stlink_dap_handle, speed, false); + return ERROR_OK; +} + +/** */ +static int stlink_dap_khz(int khz, int *jtag_speed) +{ + if (khz == 0) { + LOG_ERROR("RCLK not supported"); + return ERROR_FAIL; + } + + *jtag_speed = stlink_speed(stlink_dap_handle, khz, true); + return ERROR_OK; +} + +/** */ +static int stlink_dap_speed_div(int speed, int *khz) +{ + *khz = speed; + return ERROR_OK; +} + +static const struct dap_ops stlink_dap_ops = { + .connect = stlink_dap_op_connect, + .send_sequence = stlink_dap_op_send_sequence, + .queue_dp_read = stlink_dap_op_queue_dp_read, + .queue_dp_write = stlink_dap_op_queue_dp_write, + .queue_ap_read = stlink_dap_op_queue_ap_read, + .queue_ap_write = stlink_dap_op_queue_ap_write, + .queue_ap_abort = stlink_dap_op_queue_ap_abort, + .run = stlink_dap_op_run, + .sync = NULL, /* optional */ + .quit = stlink_dap_op_quit, /* optional */ +}; + +static const struct swim_driver stlink_swim_ops = { + .srst = stlink_swim_op_srst, + .read_mem = stlink_swim_op_read_mem, + .write_mem = stlink_swim_op_write_mem, + .reconnect = stlink_swim_op_reconnect, +}; + +static const char *const stlink_dap_transport[] = { "dapdirect_swd", "dapdirect_jtag", "swim", NULL }; + +struct adapter_driver stlink_dap_adapter_driver = { + .name = "st-link", + .transports = stlink_dap_transport, + .commands = stlink_dap_command_handlers, + + .init = stlink_dap_init, + .quit = stlink_dap_quit, + .reset = stlink_dap_reset, + .speed = stlink_dap_speed, + .khz = stlink_dap_khz, + .speed_div = stlink_dap_speed_div, + .config_trace = stlink_dap_config_trace, + .poll_trace = stlink_dap_trace_read, + + .dap_jtag_ops = &stlink_dap_ops, + .dap_swd_ops = &stlink_dap_ops, + .swim_ops = &stlink_swim_ops, +}; diff --git a/src/jtag/drivers/sysfsgpio.c b/src/jtag/drivers/sysfsgpio.c index eb4941e..a4d7ad9 100644 --- a/src/jtag/drivers/sysfsgpio.c +++ b/src/jtag/drivers/sysfsgpio.c @@ -52,6 +52,7 @@ #include "config.h" #endif +#include <helper/time_support.h> #include <jtag/interface.h> #include "bitbang.h" @@ -60,7 +61,7 @@ * * Assume here that there will be less than 10000 gpios on a system */ -static int is_gpio_valid(int gpio) +static bool is_gpio_valid(int gpio) { return gpio >= 0 && gpio < 10000; } @@ -97,8 +98,6 @@ static void unexport_sysfs_gpio(int gpio) snprintf(gpiostr, sizeof(gpiostr), "%d", gpio); if (open_write_close("/sys/class/gpio/unexport", gpiostr) < 0) LOG_ERROR("Couldn't unexport gpio %d", gpio); - - return; } /* @@ -112,6 +111,7 @@ static void unexport_sysfs_gpio(int gpio) */ static int setup_sysfs_gpio(int gpio, int is_output, int init_high) { + struct timeval timeout, now; char buf[40]; char gpiostr[5]; int ret; @@ -131,8 +131,19 @@ static int setup_sysfs_gpio(int gpio, int is_output, int init_high) } } + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, 0, 500000); + snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", gpio); - ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in"); + for (;;) { + ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in"); + if (ret >= 0 || errno != EACCES) + break; + gettimeofday(&now, NULL); + if (timeval_compare(&now, &timeout) >= 0) + break; + jtag_sleep(10000); + } if (ret < 0) { LOG_ERROR("Couldn't set direction for gpio %d", gpio); perror("sysfsgpio: "); @@ -141,7 +152,15 @@ static int setup_sysfs_gpio(int gpio, int is_output, int init_high) } snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio); - ret = open(buf, O_RDWR | O_NONBLOCK | O_SYNC); + for (;;) { + ret = open(buf, O_RDWR | O_NONBLOCK | O_SYNC); + if (ret >= 0 || errno != EACCES) + break; + gettimeofday(&now, NULL); + if (timeval_compare(&now, &timeout) >= 0) + break; + jtag_sleep(10000); + } if (ret < 0) { LOG_ERROR("Couldn't open value for gpio %d", gpio); perror("sysfsgpio: "); @@ -530,21 +549,27 @@ static int sysfsgpio_quit(void); static const char * const sysfsgpio_transports[] = { "jtag", "swd", NULL }; -struct jtag_interface sysfsgpio_interface = { - .name = "sysfsgpio", +static struct jtag_interface sysfsgpio_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, +}; + +struct adapter_driver sysfsgpio_adapter_driver = { + .name = "sysfsgpio", .transports = sysfsgpio_transports, - .swd = &bitbang_swd, .commands = sysfsgpio_command_handlers, + .init = sysfsgpio_init, .quit = sysfsgpio_quit, + .reset = sysfsgpio_reset, + + .jtag_ops = &sysfsgpio_interface, + .swd_ops = &bitbang_swd, }; static struct bitbang_interface sysfsgpio_bitbang = { .read = sysfsgpio_read, .write = sysfsgpio_write, - .reset = sysfsgpio_reset, .swdio_read = sysfsgpio_swdio_read, .swdio_drive = sysfsgpio_swdio_drive, .blink = 0 @@ -576,23 +601,23 @@ static void cleanup_all_fds(void) static bool sysfsgpio_jtag_mode_possible(void) { if (!is_gpio_valid(tck_gpio)) - return 0; + return false; if (!is_gpio_valid(tms_gpio)) - return 0; + return false; if (!is_gpio_valid(tdi_gpio)) - return 0; + return false; if (!is_gpio_valid(tdo_gpio)) - return 0; - return 1; + return false; + return true; } static bool sysfsgpio_swd_mode_possible(void) { if (!is_gpio_valid(swclk_gpio)) - return 0; + return false; if (!is_gpio_valid(swdio_gpio)) - return 0; - return 1; + return false; + return true; } static int sysfsgpio_init(void) @@ -688,4 +713,3 @@ static int sysfsgpio_quit(void) cleanup_all_fds(); return ERROR_OK; } - diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index bbe08aa..242c04f 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -235,7 +235,7 @@ int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd); int ulink_post_process_scan(struct ulink_cmd *ulink_cmd); int ulink_post_process_queue(struct ulink *device); -/* JTAG driver functions (registered in struct jtag_interface) */ +/* adapter driver functions */ static int ulink_execute_queue(void); static int ulink_khz(int khz, int *jtag_speed); static int ulink_speed(int speed); @@ -650,7 +650,7 @@ void ulink_clear_queue(struct ulink *device) int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd) { int newsize_out, newsize_in; - int ret; + int ret = ERROR_OK; newsize_out = ulink_get_queue_size(device, PAYLOAD_DIRECTION_OUT) + 1 + ulink_cmd->payload_out_size; @@ -663,14 +663,12 @@ int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd) /* New command does not fit. Execute all commands in queue before starting * new queue with the current command as first entry. */ ret = ulink_execute_queued_commands(device, USB_TIMEOUT); - if (ret != ERROR_OK) - return ret; - ret = ulink_post_process_queue(device); - if (ret != ERROR_OK) - return ret; + if (ret == ERROR_OK) + ret = ulink_post_process_queue(device); - ulink_clear_queue(device); + if (ret == ERROR_OK) + ulink_clear_queue(device); } if (device->queue_start == NULL) { @@ -687,7 +685,10 @@ int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd) device->queue_end = ulink_cmd; } - return ERROR_OK; + if (ret != ERROR_OK) + ulink_clear_queue(device); + + return ret; } /** @@ -764,58 +765,40 @@ static const char *ulink_cmd_id_string(uint8_t id) switch (id) { case CMD_SCAN_IN: return "CMD_SCAN_IN"; - break; case CMD_SLOW_SCAN_IN: return "CMD_SLOW_SCAN_IN"; - break; case CMD_SCAN_OUT: return "CMD_SCAN_OUT"; - break; case CMD_SLOW_SCAN_OUT: return "CMD_SLOW_SCAN_OUT"; - break; case CMD_SCAN_IO: return "CMD_SCAN_IO"; - break; case CMD_SLOW_SCAN_IO: return "CMD_SLOW_SCAN_IO"; - break; case CMD_CLOCK_TMS: return "CMD_CLOCK_TMS"; - break; case CMD_SLOW_CLOCK_TMS: return "CMD_SLOW_CLOCK_TMS"; - break; case CMD_CLOCK_TCK: return "CMD_CLOCK_TCK"; - break; case CMD_SLOW_CLOCK_TCK: return "CMD_SLOW_CLOCK_TCK"; - break; case CMD_SLEEP_US: return "CMD_SLEEP_US"; - break; case CMD_SLEEP_MS: return "CMD_SLEEP_MS"; - break; case CMD_GET_SIGNALS: return "CMD_GET_SIGNALS"; - break; case CMD_SET_SIGNALS: return "CMD_SET_SIGNALS"; - break; case CMD_CONFIGURE_TCK_FREQ: return "CMD_CONFIGURE_TCK_FREQ"; - break; case CMD_SET_LEDS: return "CMD_SET_LEDS"; - break; case CMD_TEST: return "CMD_TEST"; - break; default: return "CMD_UNKNOWN"; - break; } } @@ -1627,6 +1610,7 @@ int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd) if (ret != ERROR_OK) { free(tdi_buffer_start); + free(tdo_buffer_start); return ret; } } @@ -2209,14 +2193,17 @@ static int ulink_init(void) } ulink_clear_queue(ulink_handle); - ulink_append_get_signals_cmd(ulink_handle); - ulink_execute_queued_commands(ulink_handle, 200); + ret = ulink_append_get_signals_cmd(ulink_handle); + if (ret == ERROR_OK) + ret = ulink_execute_queued_commands(ulink_handle, 200); - /* Post-process the single CMD_GET_SIGNALS command */ - input_signals = ulink_handle->queue_start->payload_in[0]; - output_signals = ulink_handle->queue_start->payload_in[1]; + if (ret == ERROR_OK) { + /* Post-process the single CMD_GET_SIGNALS command */ + input_signals = ulink_handle->queue_start->payload_in[0]; + output_signals = ulink_handle->queue_start->payload_in[1]; - ulink_print_signal_states(input_signals, output_signals); + ulink_print_signal_states(input_signals, output_signals); + } ulink_clear_queue(ulink_handle); @@ -2272,17 +2259,20 @@ static const struct command_registration ulink_command_handlers[] = { COMMAND_REGISTRATION_DONE, }; -struct jtag_interface ulink_interface = { - .name = "ulink", +static struct jtag_interface ulink_interface = { + .execute_queue = ulink_execute_queue, +}; - .commands = ulink_command_handlers, +struct adapter_driver ulink_adapter_driver = { + .name = "ulink", .transports = jtag_only, + .commands = ulink_command_handlers, - .execute_queue = ulink_execute_queue, - .khz = ulink_khz, + .init = ulink_init, + .quit = ulink_quit, .speed = ulink_speed, + .khz = ulink_khz, .speed_div = ulink_speed_div, - .init = ulink_init, - .quit = ulink_quit + .jtag_ops = &ulink_interface, }; diff --git a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c index d991733..e2556ce 100644 --- a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c +++ b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c @@ -23,7 +23,7 @@ #endif #include <jtag/interface.h> #include <jtag/commands.h> -#include <libusb_common.h> +#include <libusb_helper.h> #include <target/image.h> #include "ublast_access.h" @@ -42,28 +42,37 @@ static int ublast2_libusb_read(struct ublast_lowlevel *low, uint8_t *buf, unsigned size, uint32_t *bytes_read) { - *bytes_read = jtag_libusb_bulk_read(low->libusb_dev, - USBBLASTER_EPIN | \ + int ret, tmp = 0; + + ret = jtag_libusb_bulk_read(low->libusb_dev, + USBBLASTER_EPIN | LIBUSB_ENDPOINT_IN, (char *)buf, size, - 100); - return ERROR_OK; + 100, &tmp); + *bytes_read = tmp; + + return ret; } static int ublast2_libusb_write(struct ublast_lowlevel *low, uint8_t *buf, int size, uint32_t *bytes_written) { - *bytes_written = jtag_libusb_bulk_write(low->libusb_dev, - USBBLASTER_EPOUT | \ + int ret, tmp = 0; + + ret = jtag_libusb_bulk_write(low->libusb_dev, + USBBLASTER_EPOUT | LIBUSB_ENDPOINT_OUT, (char *)buf, size, - 100); - return ERROR_OK; + 100, &tmp); + *bytes_written = tmp; + + return ret; + } -static int ublast2_write_firmware_section(struct jtag_libusb_device_handle *libusb_dev, +static int ublast2_write_firmware_section(struct libusb_device_handle *libusb_dev, struct image *firmware_image, int section_index) { uint16_t chunk_size; @@ -97,7 +106,7 @@ static int ublast2_write_firmware_section(struct jtag_libusb_device_handle *libu chunk_size = bytes_remaining; jtag_libusb_control_transfer(libusb_dev, - LIBUSB_REQUEST_TYPE_VENDOR | \ + LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT, USBBLASTER_CTRL_LOAD_FIRM, addr, @@ -114,7 +123,7 @@ static int ublast2_write_firmware_section(struct jtag_libusb_device_handle *libu return ERROR_OK; } -static int load_usb_blaster_firmware(struct jtag_libusb_device_handle *libusb_dev, +static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev, struct ublast_lowlevel *low) { struct image ublast2_firmware_image; @@ -143,7 +152,7 @@ static int load_usb_blaster_firmware(struct jtag_libusb_device_handle *libusb_de char value = CPU_RESET; jtag_libusb_control_transfer(libusb_dev, - LIBUSB_REQUEST_TYPE_VENDOR | \ + LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT, USBBLASTER_CTRL_LOAD_FIRM, EZUSB_CPUCS, @@ -164,7 +173,7 @@ static int load_usb_blaster_firmware(struct jtag_libusb_device_handle *libusb_de value = !CPU_RESET; jtag_libusb_control_transfer(libusb_dev, - LIBUSB_REQUEST_TYPE_VENDOR | \ + LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT, USBBLASTER_CTRL_LOAD_FIRM, EZUSB_CPUCS, @@ -182,11 +191,11 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low) { const uint16_t vids[] = { low->ublast_vid_uninit, 0 }; const uint16_t pids[] = { low->ublast_pid_uninit, 0 }; - struct jtag_libusb_device_handle *temp; + struct libusb_device_handle *temp; bool renumeration = false; int ret; - if (jtag_libusb_open(vids, pids, NULL, &temp) == ERROR_OK) { + if (jtag_libusb_open(vids, pids, NULL, &temp, NULL) == ERROR_OK) { LOG_INFO("Altera USB-Blaster II (uninitialized) found"); LOG_INFO("Loading firmware..."); ret = load_usb_blaster_firmware(temp, low); @@ -200,13 +209,15 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low) const uint16_t pids_renum[] = { low->ublast_pid, 0 }; if (renumeration == false) { - if (jtag_libusb_open(vids_renum, pids_renum, NULL, &low->libusb_dev) != ERROR_OK) { + if (jtag_libusb_open(vids_renum, pids_renum, NULL, + &low->libusb_dev, NULL) != ERROR_OK) { LOG_ERROR("Altera USB-Blaster II not found"); return ERROR_FAIL; } } else { int retry = 10; - while (jtag_libusb_open(vids_renum, pids_renum, NULL, &low->libusb_dev) != ERROR_OK && retry--) { + while (jtag_libusb_open(vids_renum, pids_renum, NULL, + &low->libusb_dev, NULL) != ERROR_OK && retry--) { usleep(1000000); LOG_INFO("Waiting for renumerate..."); } @@ -219,7 +230,7 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low) char buffer[5]; jtag_libusb_control_transfer(low->libusb_dev, - LIBUSB_REQUEST_TYPE_VENDOR | \ + LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN, USBBLASTER_CTRL_READ_REV, 0, diff --git a/src/jtag/drivers/usb_blaster/ublast_access.h b/src/jtag/drivers/usb_blaster/ublast_access.h index 252f003..ad20d65 100644 --- a/src/jtag/drivers/usb_blaster/ublast_access.h +++ b/src/jtag/drivers/usb_blaster/ublast_access.h @@ -28,8 +28,6 @@ #ifndef OPENOCD_JTAG_DRIVERS_USB_BLASTER_UBLAST_ACCESS_H #define OPENOCD_JTAG_DRIVERS_USB_BLASTER_UBLAST_ACCESS_H -#include <libusb_common.h> - /* Low level flags */ #define COPY_TDO_BUFFER (1 << 0) @@ -39,7 +37,7 @@ struct ublast_lowlevel { uint16_t ublast_vid_uninit; uint16_t ublast_pid_uninit; char *ublast_device_desc; - struct jtag_libusb_device_handle *libusb_dev; + struct libusb_device_handle *libusb_dev; char *firmware_path; int (*write)(struct ublast_lowlevel *low, uint8_t *buf, int size, diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c b/src/jtag/drivers/usb_blaster/usb_blaster.c index 165ebdc..d30483b 100644 --- a/src/jtag/drivers/usb_blaster/usb_blaster.c +++ b/src/jtag/drivers/usb_blaster/usb_blaster.c @@ -816,6 +816,11 @@ static int ublast_execute_queue(void) case JTAG_SCAN: ret = ublast_scan(cmd->cmd.scan); break; + default: + LOG_ERROR("BUG: unknown JTAG command type 0x%X", + cmd->type); + ret = ERROR_FAIL; + break; } } @@ -1037,8 +1042,8 @@ static const struct command_registration ublast_command_handlers[] = { .name = "usb_blaster_vid_pid", .handler = ublast_handle_vid_pid_command, .mode = COMMAND_CONFIG, - .help = "the vendor ID and product ID of the USB-Blaster and " \ - "vendor ID and product ID of the uninitialized device " \ + .help = "the vendor ID and product ID of the USB-Blaster and " + "vendor ID and product ID of the uninitialized device " "for USB-Blaster II", .usage = "vid pid vid_uninit pid_uninit", }, @@ -1066,13 +1071,18 @@ static const struct command_registration ublast_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct jtag_interface usb_blaster_interface = { +static struct jtag_interface usb_blaster_interface = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = ublast_execute_queue, +}; + +struct adapter_driver usb_blaster_adapter_driver = { .name = "usb_blaster", .transports = jtag_only, .commands = ublast_command_handlers, - .supported = DEBUG_CAP_TMS_SEQ, - .execute_queue = ublast_execute_queue, .init = ublast_init, .quit = ublast_quit, + + .jtag_ops = &usb_blaster_interface, }; diff --git a/src/jtag/drivers/usbprog.c b/src/jtag/drivers/usbprog.c index 35a9520..7b27eaf 100644 --- a/src/jtag/drivers/usbprog.c +++ b/src/jtag/drivers/usbprog.c @@ -381,7 +381,7 @@ static void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag) static unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen) { int res = usb_bulk_write(usbprog_jtag->usb_handle, 3, msg, msglen, 100); - if ((msg[0] == 2) || (msg[0] == 1) || (msg[0] == 4) || (msg[0] == 0) || \ + if ((msg[0] == 2) || (msg[0] == 1) || (msg[0] == 4) || (msg[0] == 0) || (msg[0] == 6) || (msg[0] == 0x0A) || (msg[0] == 9)) return 1; if (res == msglen) { @@ -596,11 +596,16 @@ static void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag) } } -struct jtag_interface usbprog_interface = { +static struct jtag_interface usbprog_interface = { + .execute_queue = usbprog_execute_queue, +}; + +struct adapter_driver usbprog_adapter_driver = { .name = "usbprog", .transports = jtag_only, - .execute_queue = usbprog_execute_queue, .init = usbprog_init, - .quit = usbprog_quit + .quit = usbprog_quit, + + .jtag_ops = &usbprog_interface, }; diff --git a/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c b/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c index 53a7e98..678b097 100644 --- a/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c +++ b/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c @@ -48,7 +48,7 @@ uint8_t usbtoxxx_abilities[USB_TO_XXX_ABILITIES_LEN]; #define usbtoxxx_get_type_name(type) \ types_name[((type) - VERSALOON_USB_TO_XXX_CMD_START) \ - % (sizeof(types_name) / sizeof(types_name[0]))] + % ARRAY_SIZE(types_name)] static uint8_t type_pre; static uint16_t usbtoxxx_buffer_index; diff --git a/src/jtag/drivers/versaloon/versaloon_internal.h b/src/jtag/drivers/versaloon/versaloon_internal.h index 497b6b9..8372970 100644 --- a/src/jtag/drivers/versaloon/versaloon_internal.h +++ b/src/jtag/drivers/versaloon/versaloon_internal.h @@ -91,7 +91,7 @@ struct versaloon_pending_t { void *extra_data; versaloon_callback_t callback; }; -extern struct versaloon_pending_t \ +extern struct versaloon_pending_t versaloon_pending[VERSALOON_MAX_PENDING_NUMBER]; extern uint16_t versaloon_pending_idx; void versaloon_set_pending_id(uint32_t id); diff --git a/src/jtag/drivers/vsllink.c b/src/jtag/drivers/vsllink.c index 4907ef0..5fb9bcd 100644 --- a/src/jtag/drivers/vsllink.c +++ b/src/jtag/drivers/vsllink.c @@ -59,7 +59,7 @@ static void vsllink_runtest(int num_cycles); static void vsllink_stableclocks(int num_cycles, int tms); static void vsllink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); -static void vsllink_reset(int trst, int srst); +static int vsllink_reset(int trst, int srst); /* VSLLink tap buffer functions */ static void vsllink_tap_append_step(int tms, int tdi); @@ -164,20 +164,6 @@ static int vsllink_execute_queue(void) cmd->cmd.scan); break; - case JTAG_RESET: - LOG_DEBUG_IO("reset trst: %i srst %i", - cmd->cmd.reset->trst, - cmd->cmd.reset->srst); - - vsllink_tap_execute(); - - if (cmd->cmd.reset->trst == 1) - tap_set_state(TAP_RESET); - - vsllink_reset(cmd->cmd.reset->trst, - cmd->cmd.reset->srst); - break; - case JTAG_SLEEP: LOG_DEBUG_IO("sleep %i", cmd->cmd.sleep->us); vsllink_tap_execute(); @@ -306,7 +292,7 @@ static int vsllink_interface_init(void) libusb_init(&vsllink_handle->libusb_ctx); if (ERROR_OK != vsllink_usb_open(vsllink_handle)) { - LOG_ERROR("Can't find USB JTAG Interface!" \ + LOG_ERROR("Can't find USB JTAG Interface!" "Please check connection and permissions."); return ERROR_JTAG_INIT_FAILED; } @@ -478,7 +464,7 @@ static void vsllink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, vsllink_state_move(); } -static void vsllink_reset(int trst, int srst) +static int vsllink_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); @@ -494,7 +480,7 @@ static void vsllink_reset(int trst, int srst) versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, 0); } - versaloon_interface.adaptors.peripheral_commit(); + return versaloon_interface.adaptors.peripheral_commit(); } COMMAND_HANDLER(vsllink_handle_usb_vid_command) @@ -962,17 +948,23 @@ static const struct swd_driver vsllink_swd_driver = { .run = vsllink_swd_run_queue, }; -struct jtag_interface vsllink_interface = { - .name = "vsllink", +static struct jtag_interface vsllink_interface = { .supported = DEBUG_CAP_TMS_SEQ, - .commands = vsllink_command_handlers, + .execute_queue = vsllink_execute_queue, +}; + +struct adapter_driver vsllink_adapter_driver = { + .name = "vsllink", .transports = vsllink_transports, - .swd = &vsllink_swd_driver, + .commands = vsllink_command_handlers, .init = vsllink_init, .quit = vsllink_quit, - .khz = vsllink_khz, + .reset = vsllink_reset, .speed = vsllink_speed, + .khz = vsllink_khz, .speed_div = vsllink_speed_div, - .execute_queue = vsllink_execute_queue, + + .jtag_ops = &vsllink_interface, + .swd_ops = &vsllink_swd_driver, }; diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c index f25023b..5e4df93 100644 --- a/src/jtag/drivers/xds110.c +++ b/src/jtag/drivers/xds110.c @@ -41,6 +41,12 @@ #define OCD_FIRMWARE_UPGRADE \ "XDS110: upgrade to version 2.3.0.11+ for improved support" +/* Firmware version that introduced improved TCK performance */ +#define FAST_TCK_FIRMWARE_VERSION 0x03000000 + +/* Firmware version that introduced 10 MHz and 12 MHz TCK support */ +#define FAST_TCK_PLUS_FIRMWARE_VERSION 0x03000003 + /*************************************************************************** * USB Connection Buffer Definitions * ***************************************************************************/ @@ -61,15 +67,6 @@ #define MAX_RESULT_QUEUE (MAX_DATA_BLOCK / 4) /*************************************************************************** - * USB Connection Endpoints * - ***************************************************************************/ - -/* Bulk endpoints used by the XDS110 debug interface */ -#define INTERFACE_DEBUG (2) -#define ENDPOINT_DEBUG_IN (3 | LIBUSB_ENDPOINT_IN) -#define ENDPOINT_DEBUG_OUT (2 | LIBUSB_ENDPOINT_OUT) - -/*************************************************************************** * XDS110 Firmware API Definitions * ***************************************************************************/ @@ -91,8 +88,17 @@ /* TCK frequency limits */ #define XDS110_MIN_TCK_SPEED 100 /* kHz */ -#define XDS110_MAX_TCK_SPEED 2500 /* kHz */ -#define XDS110_TCK_PULSE_INCREMENT 66.0 +#define XDS110_MAX_SLOW_TCK_SPEED 2500 /* kHz */ +#define XDS110_MAX_FAST_TCK_SPEED 14000 /* kHz */ +#define XDS110_DEFAULT_TCK_SPEED 2500 /* kHz */ + +/* Fixed TCK delay values for "Fast" TCK frequencies */ +#define FAST_TCK_DELAY_14000_KHZ 0 +#define FAST_TCK_DELAY_10000_KHZ 0xfffffffd +#define FAST_TCK_DELAY_12000_KHZ 0xfffffffe +#define FAST_TCK_DELAY_8500_KHZ 1 +#define FAST_TCK_DELAY_5500_KHZ 2 +/* For TCK frequencies below 5500 kHz, use calculated delay */ /* Scan mode on connect */ #define MODE_JTAG 1 @@ -212,6 +218,13 @@ struct xds110_info { unsigned char read_payload[USB_PAYLOAD_SIZE]; unsigned char write_packet[3]; unsigned char write_payload[USB_PAYLOAD_SIZE]; + /* Device vid/pid */ + uint16_t vid; + uint16_t pid; + /* Debug interface */ + uint8_t interface; + uint8_t endpoint_in; + uint8_t endpoint_out; /* Status flags */ bool is_connected; bool is_cmapi_connected; @@ -244,12 +257,17 @@ struct xds110_info { static struct xds110_info xds110 = { .ctx = NULL, .dev = NULL, + .vid = 0, + .pid = 0, + .interface = 0, + .endpoint_in = 0, + .endpoint_out = 0, .is_connected = false, .is_cmapi_connected = false, .is_cmapi_acquired = false, .is_swd_mode = false, .is_ap_dirty = false, - .speed = XDS110_MAX_TCK_SPEED, + .speed = XDS110_DEFAULT_TCK_SPEED, .delay_count = 0, .serial = {0}, .voltage = 0, @@ -305,12 +323,20 @@ static bool usb_connect(void) struct libusb_device_descriptor desc; - uint16_t vid = 0x0451; - uint16_t pid = 0xbef3; + /* The vid/pids of possible XDS110 configurations */ + uint16_t vids[] = { 0x0451, 0x0451, 0x1cbe }; + uint16_t pids[] = { 0xbef3, 0xbef4, 0x02a5 }; + /* Corresponding interface and endpoint numbers for configurations */ + uint8_t interfaces[] = { 2, 2, 0 }; + uint8_t endpoints_in[] = { 3, 3, 1 }; + uint8_t endpoints_out[] = { 2, 2, 1 }; + ssize_t count = 0; ssize_t i = 0; int result = 0; bool found = false; + uint32_t device = 0; + bool match = false; /* Initialize libusb context */ result = libusb_init(&ctx); @@ -327,13 +353,21 @@ static bool usb_connect(void) if (0 == result) { /* Scan through list of devices for any XDS110s */ for (i = 0; i < count; i++) { - /* Check for device VID/PID match */ + /* Check for device vid/pid match */ libusb_get_device_descriptor(list[i], &desc); - if (desc.idVendor == vid && desc.idProduct == pid) { + match = false; + for (device = 0; device < sizeof(vids)/sizeof(vids[0]); device++) { + if (desc.idVendor == vids[device] && + desc.idProduct == pids[device]) { + match = true; + break; + } + } + if (match) { result = libusb_open(list[i], &dev); if (0 == result) { - const int MAX_DATA = 256; - unsigned char data[MAX_DATA + 1]; + const int max_data = 256; + unsigned char data[max_data + 1]; *data = '\0'; /* May be the requested device if serial number matches */ @@ -344,7 +378,7 @@ static bool usb_connect(void) } else { /* Get the device's serial number string */ result = libusb_get_string_descriptor_ascii(dev, - desc.iSerialNumber, data, MAX_DATA); + desc.iSerialNumber, data, max_data); if (0 < result && 0 == strcmp((char *)data, (char *)xds110.serial)) { found = true; @@ -372,6 +406,15 @@ static bool usb_connect(void) } if (found) { + /* Save the vid/pid of the device we're using */ + xds110.vid = vids[device]; + xds110.pid = pids[device]; + + /* Save the debug interface and endpoints for the device */ + xds110.interface = interfaces[device]; + xds110.endpoint_in = endpoints_in[device] | LIBUSB_ENDPOINT_IN; + xds110.endpoint_out = endpoints_out[device] | LIBUSB_ENDPOINT_OUT; + /* Save the context and device handles */ xds110.ctx = ctx; xds110.dev = dev; @@ -380,7 +423,7 @@ static bool usb_connect(void) (void)libusb_set_auto_detach_kernel_driver(dev, 1); /* Claim the debug interface on the XDS110 */ - result = libusb_claim_interface(dev, INTERFACE_DEBUG); + result = libusb_claim_interface(dev, xds110.interface); } else { /* Couldn't find an XDS110, flag the error */ result = -1; @@ -390,7 +433,7 @@ static bool usb_connect(void) if (0 != result) { if (NULL != dev) { /* Release the debug and data interface on the XDS110 */ - (void)libusb_release_interface(dev, INTERFACE_DEBUG); + (void)libusb_release_interface(dev, xds110.interface); libusb_close(dev); } if (NULL != ctx) @@ -412,7 +455,7 @@ static void usb_disconnect(void) { if (NULL != xds110.dev) { /* Release the debug and data interface on the XDS110 */ - (void)libusb_release_interface(xds110.dev, INTERFACE_DEBUG); + (void)libusb_release_interface(xds110.dev, xds110.interface); libusb_close(xds110.dev); xds110.dev = NULL; } @@ -436,7 +479,7 @@ static bool usb_read(unsigned char *buffer, int size, int *bytes_read, if (0 == timeout) timeout = DEFAULT_TIMEOUT; - result = libusb_bulk_transfer(xds110.dev, ENDPOINT_DEBUG_IN, buffer, size, + result = libusb_bulk_transfer(xds110.dev, xds110.endpoint_in, buffer, size, bytes_read, timeout); return (0 == result) ? true : false; @@ -451,13 +494,13 @@ static bool usb_write(unsigned char *buffer, int size, int *written) if (NULL == xds110.dev || NULL == buffer) return false; - result = libusb_bulk_transfer(xds110.dev, ENDPOINT_DEBUG_OUT, buffer, + result = libusb_bulk_transfer(xds110.dev, xds110.endpoint_out, buffer, size, &bytes_written, 0); while (LIBUSB_ERROR_PIPE == result && retries < 3) { /* Try clearing the pipe stall and retry transfer */ - libusb_clear_halt(xds110.dev, ENDPOINT_DEBUG_OUT); - result = libusb_bulk_transfer(xds110.dev, ENDPOINT_DEBUG_OUT, buffer, + libusb_clear_halt(xds110.dev, xds110.endpoint_out); + result = libusb_bulk_transfer(xds110.dev, xds110.endpoint_out, buffer, size, &bytes_written, 0); retries++; } @@ -1345,6 +1388,7 @@ static void xds110_show_info(void) { uint32_t firmware = xds110.firmware; + LOG_INFO("XDS110: vid/pid = %04x/%04x", xds110.vid, xds110.pid); LOG_INFO("XDS110: firmware version = %d.%d.%d.%d", (((firmware >> 28) & 0xf) * 10) + ((firmware >> 24) & 0xf), (((firmware >> 20) & 0xf) * 10) + ((firmware >> 16) & 0xf), @@ -1592,48 +1636,58 @@ static void xds110_flush(void) xds110.txn_result_count = 0; } -static void xds110_execute_reset(struct jtag_command *cmd) +static int xds110_reset(int trst, int srst) { - char trst; - char srst; + uint8_t value; + bool success; + int retval = ERROR_OK; - if (cmd->cmd.reset->trst != -1) { - if (cmd->cmd.reset->trst == 0) { + if (trst != -1) { + if (trst == 0) { /* Deassert nTRST (active low) */ - trst = 1; + value = 1; } else { /* Assert nTRST (active low) */ - trst = 0; + value = 0; } - (void)xds_set_trst(trst); + success = xds_set_trst(value); + if (!success) + retval = ERROR_FAIL; } - if (cmd->cmd.reset->srst != -1) { - if (cmd->cmd.reset->srst == 0) { + if (srst != -1) { + if (srst == 0) { /* Deassert nSRST (active low) */ - srst = 1; + value = 1; } else { /* Assert nSRST (active low) */ - srst = 0; + value = 0; } - (void)xds_set_srst(srst); + success = xds_set_srst(value); + if (!success) + retval = ERROR_FAIL; /* Toggle TCK to trigger HIB on CC13x/CC26x devices */ - (void)xds_cycle_tck(60000); + if (success && !xds110.is_swd_mode) { + /* Toggle TCK for about 50 ms */ + success = xds_cycle_tck(xds110.speed * 50); + } + + if (!success) + retval = ERROR_FAIL; } + + return retval; } static void xds110_execute_sleep(struct jtag_command *cmd) { jtag_sleep(cmd->cmd.sleep->us); - return; } static void xds110_execute_tlr_reset(struct jtag_command *cmd) { (void)xds_goto_state(XDS_JTAG_STATE_RESET); - - return; } static void xds110_execute_pathmove(struct jtag_command *cmd) @@ -1669,8 +1723,6 @@ static void xds110_execute_pathmove(struct jtag_command *cmd) } free((void *)path); - - return; } static void xds110_queue_scan(struct jtag_command *cmd) @@ -1742,8 +1794,6 @@ static void xds110_queue_scan(struct jtag_command *cmd) } xds110.txn_request_size += total_bytes; xds110.txn_result_size += total_bytes; - - return; } static void xds110_queue_runtest(struct jtag_command *cmd) @@ -1763,8 +1813,6 @@ static void xds110_queue_runtest(struct jtag_command *cmd) xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 16) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 24) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = end_state; - - return; } static void xds110_queue_stableclocks(struct jtag_command *cmd) @@ -1781,17 +1829,11 @@ static void xds110_queue_stableclocks(struct jtag_command *cmd) xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 8) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 16) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 24) & 0xff; - - return; } static void xds110_execute_command(struct jtag_command *cmd) { switch (cmd->type) { - case JTAG_RESET: - xds110_flush(); - xds110_execute_reset(cmd); - break; case JTAG_SLEEP: xds110_flush(); xds110_execute_sleep(cmd); @@ -1837,6 +1879,8 @@ static int xds110_execute_queue(void) static int xds110_speed(int speed) { + double freq_to_use; + uint32_t delay_count; bool success; if (speed == 0) { @@ -1844,61 +1888,110 @@ static int xds110_speed(int speed) return ERROR_JTAG_NOT_IMPLEMENTED; } - if (speed > XDS110_MAX_TCK_SPEED) { - LOG_INFO("XDS110: reduce speed request: %dkHz to %dkHz maximum", - speed, XDS110_MAX_TCK_SPEED); - speed = XDS110_MAX_TCK_SPEED; - } - if (speed < XDS110_MIN_TCK_SPEED) { - LOG_INFO("XDS110: increase speed request: %dkHz to %dkHz minimum", + LOG_INFO("XDS110: increase speed request: %d kHz to %d kHz minimum", speed, XDS110_MIN_TCK_SPEED); speed = XDS110_MIN_TCK_SPEED; } - /* The default is the maximum frequency the XDS110 can support */ - uint32_t freq_to_use = XDS110_MAX_TCK_SPEED * 1000; /* Hz */ - uint32_t delay_count = 0; + /* Older XDS110 firmware had inefficient scan routines and could only */ + /* achieve a peak TCK frequency of about 2500 kHz */ + if (xds110.firmware < FAST_TCK_FIRMWARE_VERSION) { - if (XDS110_MAX_TCK_SPEED != speed) { - freq_to_use = speed * 1000; /* Hz */ + /* Check for request for top speed or higher */ + if (speed >= XDS110_MAX_SLOW_TCK_SPEED) { - /* Calculate the delay count value */ - double one_giga = 1000000000; - /* Get the pulse duration for the maximum frequency supported in ns */ - double max_freq_pulse_duration = one_giga / - (XDS110_MAX_TCK_SPEED * 1000); + /* Inform user that speed was adjusted down to max possible */ + if (speed > XDS110_MAX_SLOW_TCK_SPEED) { + LOG_INFO( + "XDS110: reduce speed request: %d kHz to %d kHz maximum", + speed, XDS110_MAX_SLOW_TCK_SPEED); + speed = XDS110_MAX_SLOW_TCK_SPEED; + } + delay_count = 0; - /* Convert frequency to pulse duration */ - double freq_to_pulse_width_in_ns = one_giga / freq_to_use; + } else { - /* - * Start with the pulse duration for the maximum frequency. Keep - * decrementing the time added by each count value till the requested - * frequency pulse is less than the calculated value. - */ - double current_value = max_freq_pulse_duration; + const double XDS110_TCK_PULSE_INCREMENT = 66.0; + freq_to_use = speed * 1000; /* Hz */ + delay_count = 0; + + /* Calculate the delay count value */ + double one_giga = 1000000000; + /* Get the pulse duration for the max frequency supported in ns */ + double max_freq_pulse_duration = one_giga / + (XDS110_MAX_SLOW_TCK_SPEED * 1000); - while (current_value < freq_to_pulse_width_in_ns) { - current_value += XDS110_TCK_PULSE_INCREMENT; - ++delay_count; + /* Convert frequency to pulse duration */ + double freq_to_pulse_width_in_ns = one_giga / freq_to_use; + + /* + * Start with the pulse duration for the maximum frequency. Keep + * decrementing time added by each count value till the requested + * frequency pulse is less than the calculated value. + */ + double current_value = max_freq_pulse_duration; + + while (current_value < freq_to_pulse_width_in_ns) { + current_value += XDS110_TCK_PULSE_INCREMENT; + ++delay_count; + } + + /* + * Determine which delay count yields the best match. + * The one obtained above or one less. + */ + if (delay_count) { + double diff_freq_1 = freq_to_use - + (one_giga / (max_freq_pulse_duration + + (XDS110_TCK_PULSE_INCREMENT * delay_count))); + double diff_freq_2 = (one_giga / (max_freq_pulse_duration + + (XDS110_TCK_PULSE_INCREMENT * (delay_count - 1)))) - + freq_to_use; + + /* One less count value yields a better match */ + if (diff_freq_1 > diff_freq_2) + --delay_count; + } } - /* - * Determine which delay count yields the best match. - * The one obtained above or one less. - */ - if (delay_count) { - double diff_freq_1 = freq_to_use - - (one_giga / (max_freq_pulse_duration + - (XDS110_TCK_PULSE_INCREMENT * delay_count))); - double diff_freq_2 = (one_giga / (max_freq_pulse_duration + - (XDS110_TCK_PULSE_INCREMENT * (delay_count - 1)))) - - freq_to_use; - - /* One less count value yields a better match */ - if (diff_freq_1 > diff_freq_2) - --delay_count; + /* Newer firmware has reworked TCK routines that are much more efficient */ + /* and can now achieve a peak TCK frequency of 14000 kHz */ + } else { + + if (speed >= XDS110_MAX_FAST_TCK_SPEED) { + if (speed > XDS110_MAX_FAST_TCK_SPEED) { + LOG_INFO( + "XDS110: reduce speed request: %d kHz to %d kHz maximum", + speed, XDS110_MAX_FAST_TCK_SPEED); + speed = XDS110_MAX_FAST_TCK_SPEED; + } + delay_count = 0; + } else if (speed >= 12000 && xds110.firmware >= + FAST_TCK_PLUS_FIRMWARE_VERSION) { + delay_count = FAST_TCK_DELAY_12000_KHZ; + } else if (speed >= 10000 && xds110.firmware >= + FAST_TCK_PLUS_FIRMWARE_VERSION) { + delay_count = FAST_TCK_DELAY_10000_KHZ; + } else if (speed >= 8500) { + delay_count = FAST_TCK_DELAY_8500_KHZ; + } else if (speed >= 5500) { + delay_count = FAST_TCK_DELAY_5500_KHZ; + } else { + /* Calculate the delay count to set the frequency */ + /* Formula determined by measuring the waveform on Saeleae logic */ + /* analyzer using known values for delay count */ + const double m = 17100000.0; /* slope */ + const double b = -1.02; /* y-intercept */ + + freq_to_use = speed * 1000; /* Hz */ + double period = 1.0/freq_to_use; + double delay = m * period + b; + + if (delay < 1.0) + delay_count = 1; + else + delay_count = (uint32_t)delay; } } @@ -1953,11 +2046,8 @@ COMMAND_HANDLER(xds110_handle_serial_command) xds110.serial[i] = (char)serial[i]; xds110.serial[len] = 0; - } else { - LOG_ERROR("XDS110: expected exactly one argument to xds110_serial " - "<serial-number>"); - return ERROR_FAIL; - } + } else + return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } @@ -1978,11 +2068,8 @@ COMMAND_HANDLER(xds110_handle_supply_voltage_command) return ERROR_FAIL; } xds110.voltage = voltage; - } else { - LOG_ERROR("XDS110: expected one argument to xds110_supply_voltage " - "<millivolts>"); - return ERROR_FAIL; - } + } else + return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } @@ -1992,33 +2079,33 @@ static const struct command_registration xds110_subcommand_handlers[] = { .name = "info", .handler = &xds110_handle_info_command, .mode = COMMAND_EXEC, - .usage = "", .help = "show XDS110 info", - }, - COMMAND_REGISTRATION_DONE -}; - -static const struct command_registration xds110_command_handlers[] = { - { - .name = "xds110", - .mode = COMMAND_ANY, - .help = "perform XDS110 management", - .usage = "<cmd>", - .chain = xds110_subcommand_handlers, + .usage = "", }, { - .name = "xds110_serial", + .name = "serial", .handler = &xds110_handle_serial_command, .mode = COMMAND_CONFIG, .help = "set the XDS110 probe serial number", .usage = "serial_string", }, { - .name = "xds110_supply_voltage", + .name = "supply", .handler = &xds110_handle_supply_voltage_command, .mode = COMMAND_CONFIG, .help = "set the XDS110 probe supply voltage", - .usage = "supply_voltage (millivolts)", + .usage = "voltage_in_millivolts", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration xds110_command_handlers[] = { + { + .name = "xds110", + .mode = COMMAND_ANY, + .help = "perform XDS110 management", + .usage = "", + .chain = xds110_subcommand_handlers, }, COMMAND_REGISTRATION_DONE }; @@ -2033,16 +2120,22 @@ static const struct swd_driver xds110_swd_driver = { static const char * const xds110_transport[] = { "swd", "jtag", NULL }; -struct jtag_interface xds110_interface = { +static struct jtag_interface xds110_interface = { + .execute_queue = xds110_execute_queue, +}; + +struct adapter_driver xds110_adapter_driver = { .name = "xds110", - .commands = xds110_command_handlers, - .swd = &xds110_swd_driver, .transports = xds110_transport, + .commands = xds110_command_handlers, - .execute_queue = xds110_execute_queue, - .speed = xds110_speed, - .speed_div = xds110_speed_div, - .khz = xds110_khz, .init = xds110_init, .quit = xds110_quit, + .reset = xds110_reset, + .speed = xds110_speed, + .khz = xds110_khz, + .speed_div = xds110_speed_div, + + .jtag_ops = &xds110_interface, + .swd_ops = &xds110_swd_driver, }; diff --git a/src/jtag/drivers/xlnx-pcie-xvc.c b/src/jtag/drivers/xlnx-pcie-xvc.c new file mode 100644 index 0000000..1743859 --- /dev/null +++ b/src/jtag/drivers/xlnx-pcie-xvc.c @@ -0,0 +1,487 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (c) 2019 Google, LLC. + * Author: Moritz Fischer <moritzf@google.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdint.h> +#include <stdlib.h> +#include <math.h> +#include <unistd.h> +#include <linux/pci.h> + +#include <jtag/interface.h> +#include <jtag/swd.h> +#include <jtag/commands.h> +#include <helper/replacements.h> +#include <helper/bits.h> + +/* Available only from kernel v4.10 */ +#ifndef PCI_CFG_SPACE_EXP_SIZE +#define PCI_CFG_SPACE_EXP_SIZE 4096 +#endif + +#define PCIE_EXT_CAP_LST 0x100 + +#define XLNX_XVC_EXT_CAP 0x00 +#define XLNX_XVC_VSEC_HDR 0x04 +#define XLNX_XVC_LEN_REG 0x0C +#define XLNX_XVC_TMS_REG 0x10 +#define XLNX_XVC_TDx_REG 0x14 + +#define XLNX_XVC_CAP_SIZE 0x20 +#define XLNX_XVC_VSEC_ID 0x8 +#define XLNX_XVC_MAX_BITS 0x20 + +struct xlnx_pcie_xvc { + int fd; + unsigned offset; + char *device; +}; + +static struct xlnx_pcie_xvc xlnx_pcie_xvc_state; +static struct xlnx_pcie_xvc *xlnx_pcie_xvc = &xlnx_pcie_xvc_state; + +static int xlnx_pcie_xvc_read_reg(const int offset, uint32_t *val) +{ + uint32_t res; + int err; + + /* Note: This should be ok endianess-wise because by going + * through sysfs the kernel does the conversion in the config + * space accessor functions + */ + err = pread(xlnx_pcie_xvc->fd, &res, sizeof(res), + xlnx_pcie_xvc->offset + offset); + if (err != sizeof(res)) { + LOG_ERROR("Failed to read offset %x", offset); + return ERROR_JTAG_DEVICE_ERROR; + } + + if (val) + *val = res; + + return ERROR_OK; +} + +static int xlnx_pcie_xvc_write_reg(const int offset, const uint32_t val) +{ + int err; + + /* Note: This should be ok endianess-wise because by going + * through sysfs the kernel does the conversion in the config + * space accessor functions + */ + err = pwrite(xlnx_pcie_xvc->fd, &val, sizeof(val), + xlnx_pcie_xvc->offset + offset); + if (err != sizeof(val)) { + LOG_ERROR("Failed to write offset: %x with value: %x", + offset, val); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +static int xlnx_pcie_xvc_transact(size_t num_bits, uint32_t tms, uint32_t tdi, + uint32_t *tdo) +{ + int err; + + err = xlnx_pcie_xvc_write_reg(XLNX_XVC_LEN_REG, num_bits); + if (err != ERROR_OK) + return err; + + err = xlnx_pcie_xvc_write_reg(XLNX_XVC_TMS_REG, tms); + if (err != ERROR_OK) + return err; + + err = xlnx_pcie_xvc_write_reg(XLNX_XVC_TDx_REG, tdi); + if (err != ERROR_OK) + return err; + + err = xlnx_pcie_xvc_read_reg(XLNX_XVC_TDx_REG, tdo); + if (err != ERROR_OK) + return err; + + if (tdo) + LOG_DEBUG_IO("Transact num_bits: %zu, tms: %x, tdi: %x, tdo: %x", + num_bits, tms, tdi, *tdo); + else + LOG_DEBUG_IO("Transact num_bits: %zu, tms: %x, tdi: %x, tdo: <null>", + num_bits, tms, tdi); + return ERROR_OK; +} + +int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd) +{ + int tms = tap_get_state() == TAP_RESET ? 1 : 0; + size_t left = cmd->cmd.stableclocks->num_cycles; + size_t write; + int err; + + LOG_DEBUG("stableclocks %i cycles", cmd->cmd.runtest->num_cycles); + + while (left) { + write = MIN(XLNX_XVC_MAX_BITS, left); + err = xlnx_pcie_xvc_transact(write, tms, 0, NULL); + if (err != ERROR_OK) + return err; + left -= write; + }; + + return ERROR_OK; +} + +static int xlnx_pcie_xvc_execute_statemove(size_t skip) +{ + uint8_t tms_scan = tap_get_tms_path(tap_get_state(), + tap_get_end_state()); + int tms_count = tap_get_tms_path_len(tap_get_state(), + tap_get_end_state()); + int err; + + LOG_DEBUG("statemove starting at (skip: %zu) %s end in %s", skip, + tap_state_name(tap_get_state()), + tap_state_name(tap_get_end_state())); + + + err = xlnx_pcie_xvc_transact(tms_count - skip, tms_scan >> skip, 0, NULL); + if (err != ERROR_OK) + return err; + + tap_set_state(tap_get_end_state()); + + return ERROR_OK; +} + +static int xlnx_pcie_xvc_execute_runtest(struct jtag_command *cmd) +{ + int err = ERROR_OK; + + LOG_DEBUG("runtest %i cycles, end in %i", + cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); + + tap_state_t tmp_state = tap_get_end_state(); + + if (tap_get_state() != TAP_IDLE) { + tap_set_end_state(TAP_IDLE); + err = xlnx_pcie_xvc_execute_statemove(0); + if (err != ERROR_OK) + return err; + }; + + size_t left = cmd->cmd.runtest->num_cycles; + size_t write; + + while (left) { + write = MIN(XLNX_XVC_MAX_BITS, left); + err = xlnx_pcie_xvc_transact(write, 0, 0, NULL); + if (err != ERROR_OK) + return err; + left -= write; + }; + + tap_set_end_state(tmp_state); + if (tap_get_state() != tap_get_end_state()) + err = xlnx_pcie_xvc_execute_statemove(0); + + return err; +} + +static int xlnx_pcie_xvc_execute_pathmove(struct jtag_command *cmd) +{ + size_t num_states = cmd->cmd.pathmove->num_states; + tap_state_t *path = cmd->cmd.pathmove->path; + int err = ERROR_OK; + size_t i; + + LOG_DEBUG("pathmove: %i states, end in %i", + cmd->cmd.pathmove->num_states, + cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); + + for (i = 0; i < num_states; i++) { + if (path[i] == tap_state_transition(tap_get_state(), false)) { + err = xlnx_pcie_xvc_transact(1, 1, 0, NULL); + } else if (path[i] == tap_state_transition(tap_get_state(), true)) { + err = xlnx_pcie_xvc_transact(1, 0, 0, NULL); + } else { + LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition.", + tap_state_name(tap_get_state()), + tap_state_name(path[i])); + err = ERROR_JTAG_QUEUE_FAILED; + } + if (err != ERROR_OK) + return err; + tap_set_state(path[i]); + } + + tap_set_end_state(tap_get_state()); + + return ERROR_OK; +} + +static int xlnx_pcie_xvc_execute_scan(struct jtag_command *cmd) +{ + enum scan_type type = jtag_scan_type(cmd->cmd.scan); + tap_state_t saved_end_state = cmd->cmd.scan->end_state; + bool ir_scan = cmd->cmd.scan->ir_scan; + uint32_t tdi, tms, tdo; + uint8_t *buf, *rd_ptr; + int err, scan_size; + size_t write; + size_t left; + + scan_size = jtag_build_buffer(cmd->cmd.scan, &buf); + rd_ptr = buf; + LOG_DEBUG("%s scan type %d %d bits; starts in %s end in %s", + (cmd->cmd.scan->ir_scan) ? "IR" : "DR", type, scan_size, + tap_state_name(tap_get_state()), + tap_state_name(cmd->cmd.scan->end_state)); + + /* If we're in TAP_DR_SHIFT state but need to do a IR_SCAN or + * vice-versa, do a statemove to corresponding other state, then restore + * end state + */ + if (ir_scan && tap_get_state() != TAP_IRSHIFT) { + tap_set_end_state(TAP_IRSHIFT); + err = xlnx_pcie_xvc_execute_statemove(0); + if (err != ERROR_OK) + goto out_err; + tap_set_end_state(saved_end_state); + } else if (!ir_scan && (tap_get_state() != TAP_DRSHIFT)) { + tap_set_end_state(TAP_DRSHIFT); + err = xlnx_pcie_xvc_execute_statemove(0); + if (err != ERROR_OK) + goto out_err; + tap_set_end_state(saved_end_state); + } + + left = scan_size; + while (left) { + write = MIN(XLNX_XVC_MAX_BITS, left); + /* the last TMS should be a 1, to leave the state */ + tms = left <= XLNX_XVC_MAX_BITS ? BIT(write - 1) : 0; + tdi = (type != SCAN_IN) ? buf_get_u32(rd_ptr, 0, write) : 0; + err = xlnx_pcie_xvc_transact(write, tms, tdi, type != SCAN_OUT ? + &tdo : NULL); + if (err != ERROR_OK) + goto out_err; + left -= write; + if (type != SCAN_OUT) + buf_set_u32(rd_ptr, 0, write, tdo); + rd_ptr += sizeof(uint32_t); + }; + + err = jtag_read_buffer(buf, cmd->cmd.scan); + if (buf) + free(buf); + + if (tap_get_state() != tap_get_end_state()) + err = xlnx_pcie_xvc_execute_statemove(1); + + return err; + +out_err: + if (buf) + free(buf); + return err; +} + +static void xlnx_pcie_xvc_execute_reset(struct jtag_command *cmd) +{ + LOG_DEBUG("reset trst: %i srst: %i", cmd->cmd.reset->trst, + cmd->cmd.reset->srst); +} + +static void xlnx_pcie_xvc_execute_sleep(struct jtag_command *cmd) +{ + LOG_DEBUG("sleep %" PRIi32 "", cmd->cmd.sleep->us); + usleep(cmd->cmd.sleep->us); +} + +static int xlnx_pcie_xvc_execute_tms(struct jtag_command *cmd) +{ + const size_t num_bits = cmd->cmd.tms->num_bits; + const uint8_t *bits = cmd->cmd.tms->bits; + size_t left, write; + uint32_t tms; + int err; + + LOG_DEBUG("execute tms %zu", num_bits); + + left = num_bits; + while (left) { + write = MIN(XLNX_XVC_MAX_BITS, left); + tms = buf_get_u32(bits, 0, write); + err = xlnx_pcie_xvc_transact(write, tms, 0, NULL); + if (err != ERROR_OK) + return err; + left -= write; + bits += 4; + }; + + return ERROR_OK; +} + +static int xlnx_pcie_xvc_execute_command(struct jtag_command *cmd) +{ + LOG_DEBUG("%s: cmd->type: %u", __func__, cmd->type); + switch (cmd->type) { + case JTAG_STABLECLOCKS: + return xlnx_pcie_xvc_execute_stableclocks(cmd); + case JTAG_RUNTEST: + return xlnx_pcie_xvc_execute_runtest(cmd); + case JTAG_TLR_RESET: + tap_set_end_state(cmd->cmd.statemove->end_state); + return xlnx_pcie_xvc_execute_statemove(0); + case JTAG_PATHMOVE: + return xlnx_pcie_xvc_execute_pathmove(cmd); + case JTAG_SCAN: + return xlnx_pcie_xvc_execute_scan(cmd); + case JTAG_RESET: + xlnx_pcie_xvc_execute_reset(cmd); + break; + case JTAG_SLEEP: + xlnx_pcie_xvc_execute_sleep(cmd); + break; + case JTAG_TMS: + return xlnx_pcie_xvc_execute_tms(cmd); + default: + LOG_ERROR("BUG: Unknown JTAG command type encountered."); + return ERROR_JTAG_QUEUE_FAILED; + } + + return ERROR_OK; +} + +static int xlnx_pcie_xvc_execute_queue(void) +{ + struct jtag_command *cmd = jtag_command_queue; + int ret; + + while (cmd) { + ret = xlnx_pcie_xvc_execute_command(cmd); + + if (ret != ERROR_OK) + return ret; + + cmd = cmd->next; + } + + return ERROR_OK; +} + + +static int xlnx_pcie_xvc_init(void) +{ + char filename[PATH_MAX]; + uint32_t cap, vh; + int err; + + snprintf(filename, PATH_MAX, "/sys/bus/pci/devices/%s/config", + xlnx_pcie_xvc->device); + xlnx_pcie_xvc->fd = open(filename, O_RDWR | O_SYNC); + if (xlnx_pcie_xvc->fd < 0) { + LOG_ERROR("Failed to open device: %s", filename); + return ERROR_JTAG_INIT_FAILED; + } + + LOG_INFO("Scanning PCIe device %s's for Xilinx XVC/PCIe ...", + xlnx_pcie_xvc->device); + /* Parse the PCIe extended capability list and try to find + * vendor specific header */ + xlnx_pcie_xvc->offset = PCIE_EXT_CAP_LST; + while (xlnx_pcie_xvc->offset <= PCI_CFG_SPACE_EXP_SIZE - sizeof(cap) && + xlnx_pcie_xvc->offset >= PCIE_EXT_CAP_LST) { + err = xlnx_pcie_xvc_read_reg(XLNX_XVC_EXT_CAP, &cap); + if (err != ERROR_OK) + return err; + LOG_DEBUG("Checking capability at 0x%x; id=0x%04x version=0x%x next=0x%x", + xlnx_pcie_xvc->offset, + PCI_EXT_CAP_ID(cap), + PCI_EXT_CAP_VER(cap), + PCI_EXT_CAP_NEXT(cap)); + if (PCI_EXT_CAP_ID(cap) == PCI_EXT_CAP_ID_VNDR) { + err = xlnx_pcie_xvc_read_reg(XLNX_XVC_VSEC_HDR, &vh); + if (err != ERROR_OK) + return err; + LOG_DEBUG("Checking possible match at 0x%x; id: 0x%x; rev: 0x%x; length: 0x%x", + xlnx_pcie_xvc->offset, + PCI_VNDR_HEADER_ID(vh), + PCI_VNDR_HEADER_REV(vh), + PCI_VNDR_HEADER_LEN(vh)); + if ((PCI_VNDR_HEADER_ID(vh) == XLNX_XVC_VSEC_ID) && + (PCI_VNDR_HEADER_LEN(vh) == XLNX_XVC_CAP_SIZE)) + break; + } + xlnx_pcie_xvc->offset = PCI_EXT_CAP_NEXT(cap); + } + if ((xlnx_pcie_xvc->offset > PCI_CFG_SPACE_EXP_SIZE - XLNX_XVC_CAP_SIZE) || + xlnx_pcie_xvc->offset < PCIE_EXT_CAP_LST) { + close(xlnx_pcie_xvc->fd); + return ERROR_JTAG_INIT_FAILED; + } + + LOG_INFO("Found Xilinx XVC/PCIe capability at offset: 0x%x", xlnx_pcie_xvc->offset); + + return ERROR_OK; +} + +static int xlnx_pcie_xvc_quit(void) +{ + int err; + + err = close(xlnx_pcie_xvc->fd); + if (err) + return err; + + return ERROR_OK; +} + +COMMAND_HANDLER(xlnx_pcie_xvc_handle_config_command) +{ + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* we can't really free this in a safe manner, so at least + * limit the memory we're leaking by freeing the old one first + * before allocating a new one ... + */ + if (xlnx_pcie_xvc->device) + free(xlnx_pcie_xvc->device); + + xlnx_pcie_xvc->device = strdup(CMD_ARGV[0]); + return ERROR_OK; +} + +static const struct command_registration xlnx_pcie_xvc_command_handlers[] = { + { + .name = "xlnx_pcie_xvc_config", + .handler = xlnx_pcie_xvc_handle_config_command, + .mode = COMMAND_CONFIG, + .help = "Configure XVC/PCIe JTAG adapter", + .usage = "device", + }, + COMMAND_REGISTRATION_DONE +}; + +static struct jtag_interface xlnx_pcie_xvc_interface = { + .execute_queue = &xlnx_pcie_xvc_execute_queue, +}; + +struct adapter_driver xlnx_pcie_xvc_adapter_driver = { + .name = "xlnx_pcie_xvc", + .transports = jtag_only, + .commands = xlnx_pcie_xvc_command_handlers, + + .init = &xlnx_pcie_xvc_init, + .quit = &xlnx_pcie_xvc_quit, + + .jtag_ops = &xlnx_pcie_xvc_interface, +}; diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c index 2abed21..6d5cdc5 100644 --- a/src/jtag/hla/hla_interface.c +++ b/src/jtag/hla/hla_interface.c @@ -35,7 +35,7 @@ #include <target/target.h> -static struct hl_interface_s hl_if = { {0, 0, { 0 }, { 0 }, 0, HL_TRANSPORT_UNKNOWN, false, -1}, 0, 0 }; +static struct hl_interface_s hl_if = { {0, 0, { 0 }, { 0 }, HL_TRANSPORT_UNKNOWN, false, -1}, 0, 0 }; int hl_interface_open(enum hl_transports tr) { @@ -127,22 +127,19 @@ static int hl_interface_quit(void) return ERROR_OK; } -static int hl_interface_execute_queue(void) +static int hl_interface_reset(int req_trst, int req_srst) { - LOG_DEBUG("hl_interface_execute_queue: ignored"); - - return ERROR_OK; + return hl_if.layout->api->assert_srst(hl_if.handle, req_srst ? 0 : 1); } int hl_interface_init_reset(void) { - /* incase the adapter has not already handled asserting srst + /* in case the adapter has not already handled asserting srst * we will attempt it again */ if (hl_if.param.connect_under_reset) { - jtag_add_reset(0, 1); - hl_if.layout->api->assert_srst(hl_if.handle, 0); + adapter_assert_reset(); } else { - jtag_add_reset(0, 0); + adapter_deassert_reset(); } return ERROR_OK; @@ -192,11 +189,12 @@ int hl_interface_override_target(const char **targetname) } int hl_interface_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, - uint32_t port_size, unsigned int *trace_freq) + uint32_t port_size, unsigned int *trace_freq, + unsigned int traceclkin_freq, uint16_t *prescaler) { if (hl_if.layout->api->config_trace) - return hl_if.layout->api->config_trace(hl_if.handle, enabled, pin_protocol, - port_size, trace_freq); + return hl_if.layout->api->config_trace(hl_if.handle, enabled, + pin_protocol, port_size, trace_freq, traceclkin_freq, prescaler); else if (enabled) { LOG_ERROR("The selected interface does not support tracing"); return ERROR_FAIL; @@ -348,17 +346,19 @@ static const struct command_registration hl_interface_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct jtag_interface hl_interface = { +struct adapter_driver hl_adapter_driver = { .name = "hla", - .supported = 0, - .commands = hl_interface_command_handlers, .transports = hl_transports, + .commands = hl_interface_command_handlers, + .init = hl_interface_init, .quit = hl_interface_quit, - .execute_queue = hl_interface_execute_queue, + .reset = hl_interface_reset, .speed = &hl_interface_speed, .khz = &hl_interface_khz, .speed_div = &hl_interface_speed_div, .config_trace = &hl_interface_config_trace, .poll_trace = &hl_interface_poll_trace, + + /* no ops for HLA, targets hla_target and stm8 intercept them all */ }; diff --git a/src/jtag/hla/hla_interface.h b/src/jtag/hla/hla_interface.h index 262025e..b6e4a8b 100644 --- a/src/jtag/hla/hla_interface.h +++ b/src/jtag/hla/hla_interface.h @@ -41,8 +41,6 @@ struct hl_interface_param_s { /** List of recognised PIDs */ uint16_t pid[HLA_MAX_USB_IDS + 1]; /** */ - unsigned api; - /** */ enum hl_transports transport; /** */ bool connect_under_reset; diff --git a/src/jtag/hla/hla_layout.h b/src/jtag/hla/hla_layout.h index 9f41b59..1d759e1 100644 --- a/src/jtag/hla/hla_layout.h +++ b/src/jtag/hla/hla_layout.h @@ -91,8 +91,10 @@ 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 tpiu_pin_protocol pin_protocol, - uint32_t port_size, unsigned int *trace_freq); + int (*config_trace)(void *handle, bool enabled, + enum tpiu_pin_protocol pin_protocol, uint32_t port_size, + unsigned int *trace_freq, unsigned int traceclkin_freq, + uint16_t *prescaler); /** * Poll for new trace data * diff --git a/src/jtag/hla/hla_transport.c b/src/jtag/hla/hla_transport.c index ddacea3..fbdddfd 100644 --- a/src/jtag/hla/hla_transport.c +++ b/src/jtag/hla/hla_transport.c @@ -175,8 +175,6 @@ static int hl_transport_init(struct command_context *cmd_ctx) tr = HL_TRANSPORT_SWD; else if (strcmp(transport->name, "hla_jtag") == 0) tr = HL_TRANSPORT_JTAG; - else if (strcmp(transport->name, "stlink_swim") == 0) - tr = HL_TRANSPORT_SWIM; int retval = hl_interface_open(tr); @@ -218,26 +216,18 @@ static struct transport hl_jtag_transport = { .override_target = hl_interface_override_target, }; -static struct transport stlink_swim_transport = { - .name = "stlink_swim", - .select = hl_transport_select, - .init = hl_transport_init, -}; - -const char *hl_transports[] = { "hla_swd", "hla_jtag", "stlink_swim", NULL }; +const char *hl_transports[] = { "hla_swd", "hla_jtag", NULL }; static void hl_constructor(void) __attribute__ ((constructor)); static void hl_constructor(void) { transport_register(&hl_swd_transport); transport_register(&hl_jtag_transport); - transport_register(&stlink_swim_transport); } bool transport_is_hla(void) { struct transport *t; t = get_current_transport(); - return t == &hl_swd_transport || t == &hl_jtag_transport - || t == &stlink_swim_transport; + return t == &hl_swd_transport || t == &hl_jtag_transport; } diff --git a/src/jtag/hla/hla_transport.h b/src/jtag/hla/hla_transport.h index 07eb751..0e0bea2 100644 --- a/src/jtag/hla/hla_transport.h +++ b/src/jtag/hla/hla_transport.h @@ -26,7 +26,6 @@ enum hl_transports { HL_TRANSPORT_UNKNOWN = 0, HL_TRANSPORT_SWD, HL_TRANSPORT_JTAG, - HL_TRANSPORT_SWIM }; #endif /* OPENOCD_JTAG_HLA_HLA_TRANSPORT_H */ diff --git a/src/jtag/interface.c b/src/jtag/interface.c index de132bb..56bbf6e 100644 --- a/src/jtag/interface.c +++ b/src/jtag/interface.c @@ -45,7 +45,7 @@ void tap_set_state_impl(tap_state_t new_state) state_follower = new_state; } -tap_state_t tap_get_state() +tap_state_t tap_get_state(void) { return state_follower; } @@ -64,7 +64,7 @@ void tap_set_end_state(tap_state_t new_end_state) end_state_follower = new_end_state; } -tap_state_t tap_get_end_state() +tap_state_t tap_get_end_state(void) { return end_state_follower; } diff --git a/src/jtag/interface.h b/src/jtag/interface.h index 905f1eb..42598c1 100644 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -26,6 +26,7 @@ #define OPENOCD_JTAG_INTERFACE_H #include <jtag/jtag.h> +#include <jtag/swim.h> #include <target/armv7m_trace.h> /* @file @@ -192,32 +193,34 @@ static inline tap_state_t jtag_debug_state_machine(const void *tms_buf, * debugging interface. */ struct jtag_interface { - /** The name of the JTAG interface driver. */ - const char * const name; - /** * Bit vector listing capabilities exposed by this driver. */ unsigned supported; #define DEBUG_CAP_TMS_SEQ (1 << 0) - /** transports supported in C code (NULL terminated vector) */ - const char * const *transports; - - const struct swd_driver *swd; - /** * Execute queued commands. * @returns ERROR_OK on success, or an error code on failure. */ int (*execute_queue)(void); +}; - /** - * Set the interface speed. - * @param speed The new interface speed setting. - * @returns ERROR_OK on success, or an error code on failure. - */ - int (*speed)(int speed); +/** + * Represents a driver for a debugging interface + * + * @todo We need a per-instance structure too, and changes to pass + * that structure to the driver. Instances can for example be in + * either SWD or JTAG modes. This will help remove globals, and + * eventually to cope with systems which have more than one such + * debugging interface. + */ +struct adapter_driver { + /** The name of the interface driver. */ + const char * const name; + + /** transports supported in C code (NULL terminated vector) */ + const char * const *transports; /** * The interface driver may register additional commands to expose @@ -247,6 +250,29 @@ struct jtag_interface { int (*quit)(void); /** + * Control (assert/deassert) the signals SRST and TRST on the interface. + * This function is synchronous and should be called after the adapter + * queue has been properly flushed. + * This function is optional. + * Adapters that don't support resets can either not define this function + * or return an error code. + * Adapters that don't support one of the two reset should ignore the + * request to assert the missing signal and eventually log an error. + * + * @param srst 1 to assert SRST, 0 to deassert SRST. + * @param trst 1 to assert TRST, 0 to deassert TRST. + * @returns ERROR_OK on success, or an error code on failure. + */ + int (*reset)(int srst, int trst); + + /** + * Set the interface speed. + * @param speed The new interface speed setting. + * @returns ERROR_OK on success, or an error code on failure. + */ + int (*speed)(int speed); + + /** * Returns JTAG maxium speed for KHz. 0 = RTCK. The function returns * a failure if it can't support the KHz/RTCK. * @@ -303,10 +329,14 @@ struct jtag_interface { * @param trace_freq A pointer to the configured trace * frequency; if it points to 0, the adapter driver must write * its maximum supported rate there + * @param traceclkin_freq TRACECLKIN frequency provided to the TPIU in Hz + * @param prescaler Pointer to the SWO prescaler calculated by the + * adapter * @returns ERROR_OK on success, an error code on failure. */ int (*config_trace)(bool enabled, enum tpiu_pin_protocol pin_protocol, - uint32_t port_size, unsigned int *trace_freq); + uint32_t port_size, unsigned int *trace_freq, + unsigned int traceclkin_freq, uint16_t *prescaler); /** * Poll for new trace data @@ -318,14 +348,31 @@ struct jtag_interface { * @returns ERROR_OK on success, an error code on failure. */ int (*poll_trace)(uint8_t *buf, size_t *size); + + /** Low-level JTAG APIs */ + struct jtag_interface *jtag_ops; + + /** Low-level SWD APIs */ + const struct swd_driver *swd_ops; + + /* DAP APIs over JTAG transport */ + const struct dap_ops *dap_jtag_ops; + + /* DAP APIs over SWD transport */ + const struct dap_ops *dap_swd_ops; + + /* SWIM APIs */ + const struct swim_driver *swim_ops; }; extern const char * const jtag_only[]; -void adapter_assert_reset(void); -void adapter_deassert_reset(void); +int adapter_resets(int assert_trst, int assert_srst); +int adapter_assert_reset(void); +int adapter_deassert_reset(void); int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, - uint32_t port_size, unsigned int *trace_freq); + uint32_t port_size, unsigned int *trace_freq, + unsigned int traceclkin_freq, uint16_t *prescaler); int adapter_poll_trace(uint8_t *buf, size_t *size); #endif /* OPENOCD_JTAG_INTERFACE_H */ diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index 286a73a..7d3f8a8 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -34,106 +34,115 @@ /** @file * This file includes declarations for all built-in jtag interfaces, - * which are then listed in the jtag_interfaces array. + * which are then listed in the adapter_drivers array. * * Dynamic loading can be implemented be searching for shared libraries - * that contain a jtag_interface structure that can added to this list. + * that contain an adapter_driver structure that can added to this list. */ #if BUILD_ZY1000 == 1 -extern struct jtag_interface zy1000_interface; +extern struct adapter_driver zy1000_adapter_driver; #elif defined(BUILD_MINIDRIVER_DUMMY) -extern struct jtag_interface minidummy_interface; +extern struct adapter_driver minidummy_adapter_driver; #else /* standard drivers */ #if BUILD_PARPORT == 1 -extern struct jtag_interface parport_interface; +extern struct adapter_driver parport_adapter_driver; #endif #if BUILD_DUMMY == 1 -extern struct jtag_interface dummy_interface; +extern struct adapter_driver dummy_adapter_driver; #endif #if BUILD_FTDI == 1 -extern struct jtag_interface ftdi_interface; +extern struct adapter_driver ftdi_adapter_driver; #endif #if BUILD_USB_BLASTER == 1 || BUILD_USB_BLASTER_2 == 1 -extern struct jtag_interface usb_blaster_interface; +extern struct adapter_driver usb_blaster_adapter_driver; #endif #if BUILD_JTAG_VPI == 1 -extern struct jtag_interface jtag_vpi_interface; +extern struct adapter_driver jtag_vpi_adapter_driver; #endif #if BUILD_FT232R == 1 -extern struct jtag_interface ft232r_interface; +extern struct adapter_driver ft232r_adapter_driver; #endif #if BUILD_AMTJTAGACCEL == 1 -extern struct jtag_interface amt_jtagaccel_interface; +extern struct adapter_driver amt_jtagaccel_adapter_driver; #endif #if BUILD_EP93XX == 1 -extern struct jtag_interface ep93xx_interface; +extern struct adapter_driver ep93xx_adapter_driver; #endif #if BUILD_AT91RM9200 == 1 -extern struct jtag_interface at91rm9200_interface; +extern struct adapter_driver at91rm9200_adapter_driver; #endif #if BUILD_GW16012 == 1 -extern struct jtag_interface gw16012_interface; +extern struct adapter_driver gw16012_adapter_driver; #endif #if BUILD_PRESTO -extern struct jtag_interface presto_interface; +extern struct adapter_driver presto_adapter_driver; #endif #if BUILD_USBPROG == 1 -extern struct jtag_interface usbprog_interface; +extern struct adapter_driver usbprog_adapter_driver; #endif #if BUILD_OPENJTAG == 1 -extern struct jtag_interface openjtag_interface; +extern struct adapter_driver openjtag_adapter_driver; #endif #if BUILD_JLINK == 1 -extern struct jtag_interface jlink_interface; +extern struct adapter_driver jlink_adapter_driver; #endif #if BUILD_VSLLINK == 1 -extern struct jtag_interface vsllink_interface; +extern struct adapter_driver vsllink_adapter_driver; #endif #if BUILD_RLINK == 1 -extern struct jtag_interface rlink_interface; +extern struct adapter_driver rlink_adapter_driver; #endif #if BUILD_ULINK == 1 -extern struct jtag_interface ulink_interface; +extern struct adapter_driver ulink_adapter_driver; #endif #if BUILD_ARMJTAGEW == 1 -extern struct jtag_interface armjtagew_interface; +extern struct adapter_driver armjtagew_adapter_driver; #endif #if BUILD_BUSPIRATE == 1 -extern struct jtag_interface buspirate_interface; +extern struct adapter_driver buspirate_adapter_driver; #endif #if BUILD_REMOTE_BITBANG == 1 -extern struct jtag_interface remote_bitbang_interface; +extern struct adapter_driver remote_bitbang_adapter_driver; #endif #if BUILD_HLADAPTER == 1 -extern struct jtag_interface hl_interface; +extern struct adapter_driver hl_adapter_driver; #endif #if BUILD_OSBDM == 1 -extern struct jtag_interface osbdm_interface; +extern struct adapter_driver osbdm_adapter_driver; #endif #if BUILD_OPENDOUS == 1 -extern struct jtag_interface opendous_interface; +extern struct adapter_driver opendous_adapter_driver; #endif #if BUILD_SYSFSGPIO == 1 -extern struct jtag_interface sysfsgpio_interface; +extern struct adapter_driver sysfsgpio_adapter_driver; +#endif +#if BUILD_XLNX_PCIE_XVC == 1 +extern struct adapter_driver xlnx_pcie_xvc_adapter_driver; #endif #if BUILD_AICE == 1 -extern struct jtag_interface aice_interface; +extern struct adapter_driver aice_adapter_driver; #endif #if BUILD_BCM2835GPIO == 1 -extern struct jtag_interface bcm2835gpio_interface; +extern struct adapter_driver bcm2835gpio_adapter_driver; #endif #if BUILD_CMSIS_DAP == 1 -extern struct jtag_interface cmsis_dap_interface; +extern struct adapter_driver cmsis_dap_adapter_driver; #endif #if BUILD_KITPROG == 1 -extern struct jtag_interface kitprog_interface; +extern struct adapter_driver kitprog_adapter_driver; #endif #if BUILD_IMX_GPIO == 1 -extern struct jtag_interface imx_gpio_interface; +extern struct adapter_driver imx_gpio_adapter_driver; #endif #if BUILD_XDS110 == 1 -extern struct jtag_interface xds110_interface; +extern struct adapter_driver xds110_adapter_driver; +#endif +#if BUILD_HLADAPTER == 1 +extern struct adapter_driver stlink_dap_adapter_driver; +#endif +#if BUILD_RSHIM == 1 +extern struct adapter_driver rshim_dap_adapter_driver; #endif #endif /* standard drivers */ @@ -144,107 +153,111 @@ extern struct jtag_interface xds110_interface; * The list should be defined to contain either one minidriver interface * or some number of standard driver interfaces, never both. */ -struct jtag_interface *jtag_interfaces[] = { +struct adapter_driver *adapter_drivers[] = { #if BUILD_ZY1000 == 1 - &zy1000_interface, + &zy1000_adapter_driver, #elif defined(BUILD_MINIDRIVER_DUMMY) - &minidummy_interface, + &minidummy_adapter_driver, #else /* standard drivers */ #if BUILD_PARPORT == 1 - &parport_interface, + &parport_adapter_driver, #endif #if BUILD_DUMMY == 1 - &dummy_interface, + &dummy_adapter_driver, #endif #if BUILD_FTDI == 1 - &ftdi_interface, + &ftdi_adapter_driver, #endif #if BUILD_USB_BLASTER || BUILD_USB_BLASTER_2 == 1 - &usb_blaster_interface, + &usb_blaster_adapter_driver, #endif #if BUILD_JTAG_VPI == 1 - &jtag_vpi_interface, + &jtag_vpi_adapter_driver, #endif #if BUILD_FT232R == 1 - &ft232r_interface, + &ft232r_adapter_driver, #endif #if BUILD_AMTJTAGACCEL == 1 - &amt_jtagaccel_interface, + &amt_jtagaccel_adapter_driver, #endif #if BUILD_EP93XX == 1 - &ep93xx_interface, + &ep93xx_adapter_driver, #endif #if BUILD_AT91RM9200 == 1 - &at91rm9200_interface, + &at91rm9200_adapter_driver, #endif #if BUILD_GW16012 == 1 - &gw16012_interface, + &gw16012_adapter_driver, #endif #if BUILD_PRESTO - &presto_interface, + &presto_adapter_driver, #endif #if BUILD_USBPROG == 1 - &usbprog_interface, + &usbprog_adapter_driver, #endif #if BUILD_OPENJTAG == 1 - &openjtag_interface, + &openjtag_adapter_driver, #endif #if BUILD_JLINK == 1 - &jlink_interface, + &jlink_adapter_driver, #endif #if BUILD_VSLLINK == 1 - &vsllink_interface, + &vsllink_adapter_driver, #endif #if BUILD_RLINK == 1 - &rlink_interface, + &rlink_adapter_driver, #endif #if BUILD_ULINK == 1 - &ulink_interface, + &ulink_adapter_driver, #endif #if BUILD_ARMJTAGEW == 1 - &armjtagew_interface, + &armjtagew_adapter_driver, #endif #if BUILD_BUSPIRATE == 1 - &buspirate_interface, + &buspirate_adapter_driver, #endif #if BUILD_REMOTE_BITBANG == 1 - &remote_bitbang_interface, + &remote_bitbang_adapter_driver, #endif #if BUILD_HLADAPTER == 1 - &hl_interface, + &hl_adapter_driver, #endif #if BUILD_OSBDM == 1 - &osbdm_interface, + &osbdm_adapter_driver, #endif #if BUILD_OPENDOUS == 1 - &opendous_interface, + &opendous_adapter_driver, #endif #if BUILD_SYSFSGPIO == 1 - &sysfsgpio_interface, + &sysfsgpio_adapter_driver, +#endif +#if BUILD_XLNX_PCIE_XVC == 1 + &xlnx_pcie_xvc_adapter_driver, #endif #if BUILD_AICE == 1 - &aice_interface, + &aice_adapter_driver, #endif #if BUILD_BCM2835GPIO == 1 - &bcm2835gpio_interface, + &bcm2835gpio_adapter_driver, #endif #if BUILD_CMSIS_DAP == 1 - &cmsis_dap_interface, + &cmsis_dap_adapter_driver, #endif #if BUILD_KITPROG == 1 - &kitprog_interface, + &kitprog_adapter_driver, #endif #if BUILD_IMX_GPIO == 1 - &imx_gpio_interface, + &imx_gpio_adapter_driver, #endif #if BUILD_XDS110 == 1 - &xds110_interface, + &xds110_adapter_driver, +#endif +#if BUILD_HLADAPTER == 1 + &stlink_dap_adapter_driver, +#endif +#if BUILD_RSHIM == 1 + &rshim_dap_adapter_driver, #endif #endif /* standard drivers */ NULL, }; - -void jtag_interface_modules_load(const char *path) -{ - /* @todo: implement dynamic module loading for JTAG interface drivers */ -} diff --git a/src/jtag/interfaces.h b/src/jtag/interfaces.h index 02d201b..ddbd735 100644 --- a/src/jtag/interfaces.h +++ b/src/jtag/interfaces.h @@ -36,9 +36,6 @@ #include <jtag/interface.h> -/** Dynamically load all JTAG interface modules from specified directory. */ -void jtag_interface_modules_load(const char *path); - -extern struct jtag_interface *jtag_interfaces[]; +extern struct adapter_driver *adapter_drivers[]; #endif /* OPENOCD_JTAG_INTERFACES_H */ diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index c93243c..7f033e0 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -77,6 +77,14 @@ typedef enum tap_state { } tap_state_t; /** + * Defines arguments for reset functions + */ +#define SRST_DEASSERT 0 +#define SRST_ASSERT 1 +#define TRST_DEASSERT 0 +#define TRST_ASSERT 1 + +/** * Function tap_state_name * Returns a string suitable for display representing the JTAG tap_state */ @@ -154,8 +162,8 @@ void jtag_tap_free(struct jtag_tap *tap); struct jtag_tap *jtag_all_taps(void); const char *jtag_tap_name(const struct jtag_tap *tap); -struct jtag_tap *jtag_tap_by_string(const char* dotted_name); -struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp* interp, Jim_Obj *obj); +struct jtag_tap *jtag_tap_by_string(const char *dotted_name); +struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *obj); struct jtag_tap *jtag_tap_by_position(unsigned abs_position); struct jtag_tap *jtag_tap_next_enabled(struct jtag_tap *p); unsigned jtag_tap_count_enabled(void); diff --git a/src/jtag/minidummy/minidummy.c b/src/jtag/minidummy/minidummy.c index 2f26004..7ee2067 100644 --- a/src/jtag/minidummy/minidummy.c +++ b/src/jtag/minidummy/minidummy.c @@ -24,18 +24,24 @@ #include <jtag/minidriver.h> #include <jtag/interface.h> -struct jtag_interface minidummy_interface = { - .name = "minidummy", +static struct jtag_interface minidummy_interface = { .execute_queue = NULL, - .speed = NULL, +}; + +struct adapter_driver minidummy_adapter_driver = { + .name = "minidummy", .transports = jtag_only, .commands = NULL, + .init = NULL, .quit = NULL, + .speed = NULL, .khz = NULL, .speed_div = NULL, .power_dropout = NULL, .srst_asserted = NULL, + + .jtag_ops = &minidummy_interface, }; int interface_jtag_execute_queue(void) @@ -77,7 +83,7 @@ int interface_jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits, return ERROR_OK; } -int interface_jtag_add_tlr() +int interface_jtag_add_tlr(void) { /* synchronously do the operation here */ @@ -164,7 +170,7 @@ void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, const uint8_t *bu int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, uint32_t opcode, uint32_t *data, size_t count) { - int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap, \ + int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap, uint32_t opcode, uint32_t *data, size_t count); return arm11_run_instr_data_to_core_noack_inner_default(tap, opcode, data, count); } diff --git a/src/jtag/startup.tcl b/src/jtag/startup.tcl index d57cafb..f8c4ca0 100644 --- a/src/jtag/startup.tcl +++ b/src/jtag/startup.tcl @@ -34,16 +34,16 @@ proc init_reset { mode } { proc power_restore {} { echo "Sensed power restore, running reset init and halting GDB." reset init - + # Halt GDB so user can deal with a detected power restore. # # After GDB is halted, then output is no longer forwarded # to the GDB console. - set targets [target names] + set targets [target names] foreach t $targets { # New event script. $t invoke-event arp_halt_gdb - } + } } add_help_text power_restore "Overridable procedure run when power restore is detected. Runs 'reset init' by default." @@ -65,11 +65,11 @@ proc srst_deasserted {} { # # After GDB is halted, then output is no longer forwarded # to the GDB console. - set targets [target names] + set targets [target names] foreach t $targets { # New event script. $t invoke-event arp_halt_gdb - } + } } add_help_text srst_deasserted "Overridable procedure run when srst deassert is detected. Runs 'reset init' by default." @@ -120,18 +120,34 @@ proc jtag_ntrst_assert_width args { # FIXME phase these aids out after about April 2011 # proc jtag_khz args { - echo "DEPRECATED! use 'adapter_khz' not 'jtag_khz'" - eval adapter_khz $args + echo "DEPRECATED! use 'adapter speed' not 'jtag_khz'" + eval adapter speed $args } proc jtag_nsrst_delay args { - echo "DEPRECATED! use 'adapter_nsrst_delay' not 'jtag_nsrst_delay'" - eval adapter_nsrst_delay $args + echo "DEPRECATED! use 'adapter srst delay' not 'jtag_nsrst_delay'" + eval adapter srst delay $args } proc jtag_nsrst_assert_width args { - echo "DEPRECATED! use 'adapter_nsrst_assert_width' not 'jtag_nsrst_assert_width'" - eval adapter_nsrst_assert_width $args + echo "DEPRECATED! use 'adapter srst pulse_width' not 'jtag_nsrst_assert_width'" + eval adapter srst pulse_width $args +} + +proc jtag_reset args { + echo "DEPRECATED! use 'adapter \[de\]assert' not 'jtag_reset'" + switch $args { + "0 0" + {eval adapter deassert trst deassert srst} + "0 1" + {eval adapter deassert trst assert srst} + "1 0" + {eval adapter assert trst deassert srst} + "1 1" + {eval adapter assert trst assert srst} + default + {return -code 1 -level 1 "jtag_reset: syntax error"} + } } # stlink migration helpers @@ -160,4 +176,54 @@ proc stlink args { eval hla $args } +proc adapter_khz args { + echo "DEPRECATED! use 'adapter speed' not 'adapter_khz'" + eval adapter speed $args +} + +proc adapter_name args { + echo "DEPRECATED! use 'adapter name' not 'adapter_name'" + eval adapter name $args +} + +proc adapter_nsrst_delay args { + echo "DEPRECATED! use 'adapter srst delay' not 'adapter_nsrst_delay'" + eval adapter srst delay $args +} + +proc adapter_nsrst_assert_width args { + echo "DEPRECATED! use 'adapter srst pulse_width' not 'adapter_nsrst_assert_width'" + eval adapter srst pulse_width $args +} + +proc interface args { + echo "DEPRECATED! use 'adapter driver' not 'interface'" + eval adapter driver $args +} + +proc interface_transports args { + echo "DEPRECATED! use 'adapter transports' not 'interface_transports'" + eval adapter transports $args +} + +proc interface_list args { + echo "DEPRECATED! use 'adapter list' not 'interface_list'" + eval adapter list $args +} + +proc ftdi_location args { + echo "DEPRECATED! use 'adapter usb location' not 'ftdi_location'" + eval adapter usb location $args +} + +proc xds110_serial args { + echo "DEPRECATED! use 'xds110 serial' not 'xds110_serial'" + eval xds110 serial $args +} + +proc xds110_supply_voltage args { + echo "DEPRECATED! use 'xds110 supply' not 'xds110_supply_voltage'" + eval xds110 supply $args +} + # END MIGRATION AIDS diff --git a/src/jtag/swd.h b/src/jtag/swd.h index 0b32105..487cb85 100644 --- a/src/jtag/swd.h +++ b/src/jtag/swd.h @@ -213,14 +213,6 @@ static const uint8_t swd_seq_dormant_to_jtag[] = { }; static const unsigned swd_seq_dormant_to_jtag_len = 160; -enum swd_special_seq { - LINE_RESET, - JTAG_TO_SWD, - SWD_TO_JTAG, - SWD_TO_DORMANT, - DORMANT_TO_SWD, -}; - struct swd_driver { /** * Initialize the debug link so it can perform SWD operations. @@ -285,6 +277,5 @@ struct swd_driver { }; int swd_init_reset(struct command_context *cmd_ctx); -void swd_add_reset(int req_srst); #endif /* OPENOCD_JTAG_SWD_H */ diff --git a/src/jtag/swim.c b/src/jtag/swim.c new file mode 100644 index 0000000..936268b --- /dev/null +++ b/src/jtag/swim.c @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2020 by Antonio Borneo <borneo.antonio@gmail.com + * + * SWIM (Single Wire Interface Module) is a low-pin-count debug protocol + * used by STMicroelectronics MCU family STM8 and documented in UM470 + * https://www.st.com/resource/en/user_manual/cd00173911.pdf + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "interface.h" +#include "swim.h" +#include <helper/command.h> +#include <transport/transport.h> + +extern struct adapter_driver *adapter_driver; + +int swim_system_reset(void) +{ + assert(adapter_driver->swim_ops); + + return adapter_driver->swim_ops->srst(); +} + +int swim_read_mem(uint32_t addr, uint32_t size, uint32_t count, + uint8_t *buffer) +{ + assert(adapter_driver->swim_ops); + + return adapter_driver->swim_ops->read_mem(addr, size, count, buffer); +} + +int swim_write_mem(uint32_t addr, uint32_t size, uint32_t count, + const uint8_t *buffer) +{ + assert(adapter_driver->swim_ops); + + return adapter_driver->swim_ops->write_mem(addr, size, count, buffer); +} + +int swim_reconnect(void) +{ + assert(adapter_driver->swim_ops); + + return adapter_driver->swim_ops->reconnect(); +} + +COMMAND_HANDLER(handle_swim_newtap_command) +{ + struct jtag_tap *tap; + + /* + * only need "basename" and "tap_type", but for backward compatibility + * ignore extra parameters + */ + if (CMD_ARGC < 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + tap = calloc(1, sizeof(*tap)); + if (!tap) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + tap->chip = strdup(CMD_ARGV[0]); + tap->tapname = strdup(CMD_ARGV[1]); + tap->dotted_name = alloc_printf("%s.%s", CMD_ARGV[0], CMD_ARGV[1]); + if (!tap->chip || !tap->tapname || !tap->dotted_name) { + LOG_ERROR("Out of memory"); + free(tap->dotted_name); + free(tap->tapname); + free(tap->chip); + free(tap); + return ERROR_FAIL; + } + + LOG_DEBUG("Creating new SWIM \"tap\", Chip: %s, Tap: %s, Dotted: %s", + tap->chip, tap->tapname, tap->dotted_name); + + /* default is enabled-after-reset */ + tap->enabled = true; + + jtag_tap_init(tap); + return ERROR_OK; +} + +static const struct command_registration swim_transport_subcommand_handlers[] = { + { + .name = "newtap", + .handler = handle_swim_newtap_command, + .mode = COMMAND_CONFIG, + .help = "Create a new TAP instance named basename.tap_type, " + "and appends it to the scan chain.", + .usage = "basename tap_type", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration swim_transport_command_handlers[] = { + { + .name = "swim", + .mode = COMMAND_ANY, + .help = "perform swim adapter actions", + .usage = "", + .chain = swim_transport_subcommand_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +static int swim_transport_select(struct command_context *cmd_ctx) +{ + LOG_DEBUG(__func__); + + return register_commands(cmd_ctx, NULL, swim_transport_command_handlers); +} + +static int swim_transport_init(struct command_context *cmd_ctx) +{ + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + LOG_DEBUG(__func__); + + if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { + if (jtag_reset_config & RESET_SRST_NO_GATING) + adapter_assert_reset(); + else + LOG_WARNING("\'srst_nogate\' reset_config option is required"); + } else + adapter_deassert_reset(); + + return ERROR_OK; +} + +static struct transport swim_transport = { + .name = "swim", + .select = swim_transport_select, + .init = swim_transport_init, +}; + +static void swim_constructor(void) __attribute__ ((constructor)); +static void swim_constructor(void) +{ + transport_register(&swim_transport); +} + +bool transport_is_swim(void) +{ + return get_current_transport() == &swim_transport; +} diff --git a/src/jtag/swim.h b/src/jtag/swim.h new file mode 100644 index 0000000..186e0cc --- /dev/null +++ b/src/jtag/swim.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2020 by Antonio Borneo <borneo.antonio@gmail.com + */ + +/** + * @file + * This file implements support for STMicroelectronics debug protocol SWIM + * (Single Wire Interface Module). + */ + +#ifndef OPENOCD_JTAG_SWIM_H +#define OPENOCD_JTAG_SWIM_H + +#define SWIM_FREQ_LOW 363 +#define SWIM_FREQ_HIGH 800 + +struct swim_driver { + /** + * Send SRST (system reset) command to target. + * + * @return ERROR_OK on success, else a fault code. + */ + int (*srst)(void); + + /** + * Read target memory through ROTF (read on-the-fly) command. + * + * @param addr Start address to read data from target memory. + * @param size Size in bytes of data units, 1, 2 or 4. + * @param count Number of units (size units, not bytes) to read. + * @param buffer Data buffer to receive data. + * @return ERROR_OK on success, else a fault code. + */ + int (*read_mem)(uint32_t addr, uint32_t size, uint32_t count, + uint8_t *buffer); + + /** + * Write target memory through WOTF (write on-the-fly) command. + * + * @param addr Start address to write data to target memory. + * @param size Size in bytes of data units, 1, 2 or 4. + * @param count Number of units (size units, not bytes) to write. + * @param buffer Data buffer to write. + * @return ERROR_OK on success, else a fault code. + */ + int (*write_mem)(uint32_t addr, uint32_t size, uint32_t count, + const uint8_t *buffer); + + /** + * Reconnect to the target. + * Should be reworked to be more generic and not linked to current + * implementation in stlink driver. + * + * @return ERROR_OK on success, else a fault code. + */ + int (*reconnect)(void); +}; + +int swim_system_reset(void); +int swim_read_mem(uint32_t addr, uint32_t size, uint32_t count, + uint8_t *buffer); +int swim_write_mem(uint32_t addr, uint32_t size, uint32_t count, + const uint8_t *buffer); +int swim_reconnect(void); + +#endif /* OPENOCD_JTAG_SWIM_H */ diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c index cbdf2ad..d2f1f0d 100644 --- a/src/jtag/tcl.c +++ b/src/jtag/tcl.c @@ -108,7 +108,7 @@ static int Jim_Command_drscan(Jim_Interp *interp, int argc, Jim_Obj *const *args endstate = TAP_IDLE; - script_debug(interp, "drscan", argc, args); + script_debug(interp, argc, args); /* validate arguments as numbers */ e = JIM_OK; @@ -229,7 +229,7 @@ static int Jim_Command_pathmove(Jim_Interp *interp, int argc, Jim_Obj *const *ar return JIM_ERR; } - script_debug(interp, "pathmove", argc, args); + script_debug(interp, argc, args); int i; for (i = 0; i < argc-1; i++) { @@ -261,7 +261,7 @@ static int Jim_Command_pathmove(Jim_Interp *interp, int argc, Jim_Obj *const *ar static int Jim_Command_flush_count(Jim_Interp *interp, int argc, Jim_Obj *const *args) { - script_debug(interp, "flush_count", argc, args); + script_debug(interp, argc, args); Jim_SetResult(interp, Jim_NewIntObj(interp, jtag_get_flush_queue_count())); @@ -965,7 +965,7 @@ COMMAND_HANDLER(handle_scan_chain_command) while (tap) { uint32_t expected, expected_mask, ii; - snprintf(expected_id, sizeof expected_id, "0x%08x", + snprintf(expected_id, sizeof(expected_id), "0x%08x", (unsigned)((tap->expected_ids_cnt > 0) ? tap->expected_ids[0] : 0)); @@ -987,7 +987,7 @@ COMMAND_HANDLER(handle_scan_chain_command) (unsigned int)(expected_mask)); for (ii = 1; ii < tap->expected_ids_cnt; ii++) { - snprintf(expected_id, sizeof expected_id, "0x%08x", + snprintf(expected_id, sizeof(expected_id), "0x%08x", (unsigned) tap->expected_ids[ii]); if (tap->ignore_version) expected_id[2] = '*'; @@ -1059,34 +1059,6 @@ COMMAND_HANDLER(handle_jtag_rclk_command) return retval; } -COMMAND_HANDLER(handle_jtag_reset_command) -{ - if (CMD_ARGC != 2) - return ERROR_COMMAND_SYNTAX_ERROR; - - int trst = -1; - if (CMD_ARGV[0][0] == '1') - trst = 1; - else if (CMD_ARGV[0][0] == '0') - trst = 0; - else - return ERROR_COMMAND_SYNTAX_ERROR; - - int srst = -1; - if (CMD_ARGV[1][0] == '1') - srst = 1; - else if (CMD_ARGV[1][0] == '0') - srst = 0; - else - return ERROR_COMMAND_SYNTAX_ERROR; - - if (adapter_init(CMD_CTX) != ERROR_OK) - return ERROR_JTAG_INIT_FAILED; - - jtag_add_reset(trst, srst); - return jtag_execute_queue(); -} - COMMAND_HANDLER(handle_runtest_command) { if (CMD_ARGC != 1) @@ -1157,14 +1129,19 @@ COMMAND_HANDLER(handle_irscan_command) return ERROR_FAIL; } - int field_size = tap->ir_length; - fields[i].num_bits = field_size; - uint8_t *v = malloc(DIV_ROUND_UP(field_size, 8)); - uint64_t value; retval = parse_u64(CMD_ARGV[i * 2 + 1], &value); if (ERROR_OK != retval) goto error_return; + + int field_size = tap->ir_length; + fields[i].num_bits = field_size; + uint8_t *v = calloc(1, DIV_ROUND_UP(field_size, 8)); + if (!v) { + LOG_ERROR("Out of memory"); + goto error_return; + } + buf_set_u64(v, 0, field_size, value); fields[i].out_value = v; fields[i].in_value = NULL; @@ -1332,14 +1309,6 @@ static const struct command_registration jtag_command_handlers[] = { .usage = "" }, { - .name = "jtag_reset", - .handler = handle_jtag_reset_command, - .mode = COMMAND_EXEC, - .help = "Set reset line values. Value '1' is active, " - "value '0' is inactive.", - .usage = "trst_active srst_active", - }, - { .name = "runtest", .handler = handle_runtest_command, .mode = COMMAND_EXEC, @@ -1350,7 +1319,7 @@ static const struct command_registration jtag_command_handlers[] = { .name = "irscan", .handler = handle_irscan_command, .mode = COMMAND_EXEC, - .help = "Execute Instruction Register (DR) scan. The " + .help = "Execute Instruction Register (IR) scan. The " "specified opcodes are put into each TAP's IR, " "and other TAPs are put in BYPASS.", .usage = "[tap_name instruction]* ['-endstate' state_name]", diff --git a/src/jtag/zy1000/zy1000.c b/src/jtag/zy1000/zy1000.c index 1734983..37af2f7 100644 --- a/src/jtag/zy1000/zy1000.c +++ b/src/jtag/zy1000/zy1000.c @@ -486,7 +486,7 @@ int interface_jtag_add_plain_dr_scan(int num_bits, return ERROR_OK; } -int interface_jtag_add_tlr() +int interface_jtag_add_tlr(void) { setCurrentState(TAP_RESET); return ERROR_OK; @@ -1237,17 +1237,23 @@ int zy1000_init(void) return ERROR_OK; } -struct jtag_interface zy1000_interface = { - .name = "ZY1000", +static struct jtag_interface zy1000_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = NULL, - .speed = zy1000_speed, +}; + +struct adapter_driver zy1000_adapter_driver = { + .name = "ZY1000", .transports = jtag_only, .commands = zy1000_commands, + .init = zy1000_init, .quit = zy1000_quit, + .speed = zy1000_speed, .khz = zy1000_khz, .speed_div = zy1000_speed_div, .power_dropout = zy1000_power_dropout, .srst_asserted = zy1000_srst_asserted, + + .jtag_ops = &zy1000_interface, }; diff --git a/src/openocd.c b/src/openocd.c index 2a9a0b3..8862284 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -345,6 +345,8 @@ int openocd_main(int argc, char *argv[]) command_context_mode(cmd_ctx, COMMAND_CONFIG); command_set_output_handler(cmd_ctx, configuration_output_handler, NULL); + server_host_os_entry(); + /* Start the executable meat that can evolve into thread in future. */ ret = openocd_thread(argc, argv, cmd_ctx); @@ -360,6 +362,8 @@ int openocd_main(int argc, char *argv[]) adapter_quit(); + server_host_os_close(); + /* Shutdown commandline interface */ command_exit(cmd_ctx); diff --git a/src/rtos/FreeRTOS.c b/src/rtos/FreeRTOS.c index 9d89974..c45d9d6 100644 --- a/src/rtos/FreeRTOS.c +++ b/src/rtos/FreeRTOS.c @@ -157,7 +157,6 @@ static const struct symbols FreeRTOS_symbol_list[] = { static int FreeRTOS_update_threads(struct rtos *rtos) { - int i = 0; int retval; int tasks_found = 0; const struct FreeRTOS_params *param; @@ -245,32 +244,40 @@ static int FreeRTOS_update_threads(struct rtos *rtos) LOG_ERROR("FreeRTOS: uxTopUsedPriority is not defined, consult the OpenOCD manual for a work-around"); return ERROR_FAIL; } - int64_t max_used_priority = 0; + uint64_t top_used_priority = 0; + /* FIXME: endianess error on almost all target_read_buffer(), see also + * other rtoses */ retval = target_read_buffer(rtos->target, rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address, param->pointer_width, - (uint8_t *)&max_used_priority); + (uint8_t *)&top_used_priority); if (retval != ERROR_OK) return retval; - LOG_DEBUG("FreeRTOS: Read uxTopUsedPriority at 0x%" PRIx64 ", value %" PRId64 "\r\n", + LOG_DEBUG("FreeRTOS: Read uxTopUsedPriority at 0x%" PRIx64 ", value %" PRIu64 "\r\n", rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address, - max_used_priority); - if (max_used_priority > FREERTOS_MAX_PRIORITIES) { - LOG_ERROR("FreeRTOS maximum used priority is unreasonably big, not proceeding: %" PRId64 "", - max_used_priority); + top_used_priority); + if (top_used_priority > FREERTOS_MAX_PRIORITIES) { + LOG_ERROR("FreeRTOS top used priority is unreasonably big, not proceeding: %" PRIu64, + top_used_priority); return ERROR_FAIL; } + /* uxTopUsedPriority was defined as configMAX_PRIORITIES - 1 + * in old FreeRTOS versions (before V7.5.3) + * Use contrib/rtos-helpers/FreeRTOS-openocd.c to get compatible symbol + * in newer FreeRTOS versions. + * Here we restore the original configMAX_PRIORITIES value */ + unsigned int config_max_priorities = top_used_priority + 1; + symbol_address_t *list_of_lists = - malloc(sizeof(symbol_address_t) * - (max_used_priority+1 + 5)); + malloc(sizeof(symbol_address_t) * (config_max_priorities + 5)); if (!list_of_lists) { - LOG_ERROR("Error allocating memory for %" PRId64 " priorities", max_used_priority); + LOG_ERROR("Error allocating memory for %u priorities", config_max_priorities); return ERROR_FAIL; } - int num_lists; - for (num_lists = 0; num_lists <= max_used_priority; num_lists++) + unsigned int num_lists; + for (num_lists = 0; num_lists < config_max_priorities; num_lists++) list_of_lists[num_lists] = rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address + num_lists * param->list_width; @@ -280,7 +287,7 @@ static int FreeRTOS_update_threads(struct rtos *rtos) list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xSuspendedTaskList].address; list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xTasksWaitingTermination].address; - for (i = 0; i < num_lists; i++) { + for (unsigned int i = 0; i < num_lists; i++) { if (list_of_lists[i] == 0) continue; @@ -295,7 +302,7 @@ static int FreeRTOS_update_threads(struct rtos *rtos) free(list_of_lists); return retval; } - LOG_DEBUG("FreeRTOS: Read thread count for list %d at 0x%" PRIx64 ", value %" PRId64 "\r\n", + LOG_DEBUG("FreeRTOS: Read thread count for list %u at 0x%" PRIx64 ", value %" PRId64 "\r\n", i, list_of_lists[i], list_thread_count); if (list_thread_count == 0) @@ -313,7 +320,7 @@ static int FreeRTOS_update_threads(struct rtos *rtos) free(list_of_lists); return retval; } - LOG_DEBUG("FreeRTOS: Read first item for list %d at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n", + LOG_DEBUG("FreeRTOS: Read first item for list %u at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n", i, list_of_lists[i] + param->list_next_offset, list_elem_ptr); while ((list_thread_count > 0) && (list_elem_ptr != 0) && diff --git a/src/rtos/Makefile.am b/src/rtos/Makefile.am index b3e14f8..8097c30 100644 --- a/src/rtos/Makefile.am +++ b/src/rtos/Makefile.am @@ -11,7 +11,7 @@ noinst_LTLIBRARIES += %D%/librtos.la %D%/ThreadX.c \ %D%/eCos.c \ %D%/linux.c \ - %D%/ChibiOS.c \ + %D%/chibios.c \ %D%/chromium-ec.c \ %D%/embKernel.c \ %D%/mqx.c \ diff --git a/src/rtos/ChibiOS.c b/src/rtos/chibios.c index 8839acc..4d2b1b2 100644 --- a/src/rtos/ChibiOS.c +++ b/src/rtos/chibios.c @@ -39,7 +39,7 @@ * * @details Definition copied from os/kernel/include/chregistry.h of ChibiOS/RT. */ -struct ChibiOS_chdebug { +struct chibios_chdebug { char ch_identifier[4]; /**< @brief Always set to "main". */ uint8_t ch_zero; /**< @brief Must be zero. */ uint8_t ch_size; /**< @brief Size of this structure. */ @@ -69,26 +69,26 @@ struct ChibiOS_chdebug { /** * @brief ChibiOS thread states. */ -static const char * const ChibiOS_thread_states[] = { "READY", "CURRENT", +static const char * const chibios_thread_states[] = { "READY", "CURRENT", "WTSTART", "SUSPENDED", "QUEUED", "WTSEM", "WTMTX", "WTCOND", "SLEEPING", "WTEXIT", "WTOREVT", "WTANDEVT", "SNDMSGQ", "SNDMSG", "WTMSG", "FINAL" }; -#define CHIBIOS_NUM_STATES (sizeof(ChibiOS_thread_states)/sizeof(char *)) +#define CHIBIOS_NUM_STATES (sizeof(chibios_thread_states)/sizeof(char *)) /* Maximum ChibiOS thread name. There is no real limit set by ChibiOS but 64 * chars ought to be enough. */ #define CHIBIOS_THREAD_NAME_STR_SIZE (64) -struct ChibiOS_params { +struct chibios_params { const char *target_name; - struct ChibiOS_chdebug *signature; + struct chibios_chdebug *signature; const struct rtos_register_stacking *stacking_info; }; -static struct ChibiOS_params ChibiOS_params_list[] = { +static struct chibios_params chibios_params_list[] = { { "cortex_m", /* target_name */ 0, @@ -100,23 +100,23 @@ static struct ChibiOS_params ChibiOS_params_list[] = { NULL, /* stacking_info */ } }; -#define CHIBIOS_NUM_PARAMS ((int)(sizeof(ChibiOS_params_list)/sizeof(struct ChibiOS_params))) +#define CHIBIOS_NUM_PARAMS ((int)(sizeof(chibios_params_list)/sizeof(struct chibios_params))) -static bool ChibiOS_detect_rtos(struct target *target); -static int ChibiOS_create(struct target *target); -static int ChibiOS_update_threads(struct rtos *rtos); -static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, +static bool chibios_detect_rtos(struct target *target); +static int chibios_create(struct target *target); +static int chibios_update_threads(struct rtos *rtos); +static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); -static int ChibiOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); +static int chibios_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); -struct rtos_type ChibiOS_rtos = { - .name = "ChibiOS", +struct rtos_type chibios_rtos = { + .name = "chibios", - .detect_rtos = ChibiOS_detect_rtos, - .create = ChibiOS_create, - .update_threads = ChibiOS_update_threads, - .get_thread_reg_list = ChibiOS_get_thread_reg_list, - .get_symbol_list_to_lookup = ChibiOS_get_symbol_list_to_lookup, + .detect_rtos = chibios_detect_rtos, + .create = chibios_create, + .update_threads = chibios_update_threads, + .get_thread_reg_list = chibios_get_thread_reg_list, + .get_symbol_list_to_lookup = chibios_get_symbol_list_to_lookup, }; @@ -125,13 +125,13 @@ struct rtos_type ChibiOS_rtos = { * use whatever is available. */ -enum ChibiOS_symbol_values { - ChibiOS_VAL_rlist = 0, - ChibiOS_VAL_ch = 1, - ChibiOS_VAL_ch_debug = 2 +enum chibios_symbol_values { + CHIBIOS_VAL_RLIST = 0, + CHIBIOS_VAL_CH = 1, + CHIBIOS_VAL_CH_DEBUG = 2 }; -static symbol_table_elem_t ChibiOS_symbol_list[] = { +static symbol_table_elem_t chibios_symbol_list[] = { { "rlist", 0, true}, /* Thread ready list */ { "ch", 0, true}, /* System data structure */ { "ch_debug", 0, false}, /* Memory Signature containing offsets of fields in rlist */ @@ -141,13 +141,13 @@ static symbol_table_elem_t ChibiOS_symbol_list[] = { /* Offset of the rlist structure within the system data structure (ch) */ #define CH_RLIST_OFFSET 0x00 -static int ChibiOS_update_memory_signature(struct rtos *rtos) +static int chibios_update_memory_signature(struct rtos *rtos) { int retval; - struct ChibiOS_params *param; - struct ChibiOS_chdebug *signature; + struct chibios_params *param; + struct chibios_chdebug *signature; - param = (struct ChibiOS_params *) rtos->rtos_specific_params; + param = (struct chibios_params *) rtos->rtos_specific_params; /* Free existing memory description.*/ if (param->signature) { @@ -162,7 +162,7 @@ static int ChibiOS_update_memory_signature(struct rtos *rtos) } retval = target_read_buffer(rtos->target, - rtos->symbols[ChibiOS_VAL_ch_debug].address, + rtos->symbols[CHIBIOS_VAL_CH_DEBUG].address, sizeof(*signature), (uint8_t *) signature); if (retval != ERROR_OK) { @@ -200,7 +200,7 @@ static int ChibiOS_update_memory_signature(struct rtos *rtos) /* Currently, we have the inherent assumption that all address pointers * are 32 bit wide. */ if (signature->ch_ptrsize != sizeof(uint32_t)) { - LOG_ERROR("ChibiOS/RT target memory signature claims an address" + LOG_ERROR("ChibiOS/RT target memory signature claims an address " "width unequal to 32 bits!"); free(signature); return -1; @@ -217,7 +217,7 @@ errfree: } -static int ChibiOS_update_stacking(struct rtos *rtos) +static int chibios_update_stacking(struct rtos *rtos) { /* Sometimes the stacking can not be determined only by looking at the * target name but only a runtime. @@ -234,15 +234,15 @@ static int ChibiOS_update_stacking(struct rtos *rtos) * - Since no threads are running during startup, the problem is solved * by delaying stacking detection until there are more threads * available than the current execution. In which case - * ChibiOS_get_thread_reg_list is called. + * chibios_get_thread_reg_list is called. */ int retval; if (!rtos->rtos_specific_params) return -1; - struct ChibiOS_params *param; - param = (struct ChibiOS_params *) rtos->rtos_specific_params; + struct chibios_params *param; + param = (struct chibios_params *) rtos->rtos_specific_params; /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4 */ struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target); @@ -274,10 +274,10 @@ static int ChibiOS_update_stacking(struct rtos *rtos) return -1; } -static int ChibiOS_update_threads(struct rtos *rtos) +static int chibios_update_threads(struct rtos *rtos) { int retval; - const struct ChibiOS_params *param; + const struct chibios_params *param; int tasks_found = 0; int rtos_valid = -1; @@ -289,10 +289,10 @@ static int ChibiOS_update_threads(struct rtos *rtos) return -3; } - param = (const struct ChibiOS_params *) rtos->rtos_specific_params; + param = (const struct chibios_params *) rtos->rtos_specific_params; /* Update the memory signature saved in the target memory */ if (!param->signature) { - retval = ChibiOS_update_memory_signature(rtos); + retval = chibios_update_memory_signature(rtos); if (retval != ERROR_OK) { LOG_ERROR("Reading the memory signature of ChibiOS/RT failed"); return retval; @@ -305,10 +305,10 @@ static int ChibiOS_update_threads(struct rtos *rtos) /* ChibiOS does not save the current thread count. We have to first * parse the double linked thread list to check for errors and the number of * threads. */ - const uint32_t rlist = rtos->symbols[ChibiOS_VAL_rlist].address ? - rtos->symbols[ChibiOS_VAL_rlist].address : - rtos->symbols[ChibiOS_VAL_ch].address + CH_RLIST_OFFSET /* ChibiOS3 */; - const struct ChibiOS_chdebug *signature = param->signature; + const uint32_t rlist = rtos->symbols[CHIBIOS_VAL_RLIST].address ? + rtos->symbols[CHIBIOS_VAL_RLIST].address : + rtos->symbols[CHIBIOS_VAL_CH].address + CH_RLIST_OFFSET /* ChibiOS3 */; + const struct chibios_chdebug *signature = param->signature; uint32_t current; uint32_t previous; uint32_t older; @@ -426,19 +426,19 @@ static int ChibiOS_update_threads(struct rtos *rtos) strcpy(curr_thrd_details->thread_name_str, tmp_str); /* State info */ - uint8_t threadState; + uint8_t thread_state; const char *state_desc; retval = target_read_u8(rtos->target, - current + signature->cf_off_state, &threadState); + current + signature->cf_off_state, &thread_state); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread state from ChibiOS target"); return retval; } - if (threadState < CHIBIOS_NUM_STATES) - state_desc = ChibiOS_thread_states[threadState]; + if (thread_state < CHIBIOS_NUM_STATES) + state_desc = chibios_thread_states[thread_state]; else state_desc = "Unknown"; @@ -465,25 +465,25 @@ static int ChibiOS_update_threads(struct rtos *rtos) return 0; } -static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, +static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { int retval; - const struct ChibiOS_params *param; + const struct chibios_params *param; uint32_t stack_ptr = 0; if ((rtos == NULL) || (thread_id == 0) || (rtos->rtos_specific_params == NULL)) return -1; - param = (const struct ChibiOS_params *) rtos->rtos_specific_params; + param = (const struct chibios_params *) rtos->rtos_specific_params; if (!param->signature) return -1; /* Update stacking if it can only be determined from runtime information */ if ((param->stacking_info == 0) && - (ChibiOS_update_stacking(rtos) != ERROR_OK)) { + (chibios_update_stacking(rtos) != ERROR_OK)) { LOG_ERROR("Failed to determine exact stacking for the target type %s", rtos->target->type->name); return -1; } @@ -499,24 +499,24 @@ static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs); } -static int ChibiOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +static int chibios_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) { - *symbol_list = malloc(sizeof(ChibiOS_symbol_list)); + *symbol_list = malloc(sizeof(chibios_symbol_list)); if (*symbol_list == NULL) return ERROR_FAIL; - memcpy(*symbol_list, ChibiOS_symbol_list, sizeof(ChibiOS_symbol_list)); + memcpy(*symbol_list, chibios_symbol_list, sizeof(chibios_symbol_list)); return 0; } -static bool ChibiOS_detect_rtos(struct target *target) +static bool chibios_detect_rtos(struct target *target) { if ((target->rtos->symbols != NULL) && - ((target->rtos->symbols[ChibiOS_VAL_rlist].address != 0) || - (target->rtos->symbols[ChibiOS_VAL_ch].address != 0))) { + ((target->rtos->symbols[CHIBIOS_VAL_RLIST].address != 0) || + (target->rtos->symbols[CHIBIOS_VAL_CH].address != 0))) { - if (target->rtos->symbols[ChibiOS_VAL_ch_debug].address == 0) { + if (target->rtos->symbols[CHIBIOS_VAL_CH_DEBUG].address == 0) { LOG_INFO("It looks like the target may be running ChibiOS " "without ch_debug."); return false; @@ -529,11 +529,11 @@ static bool ChibiOS_detect_rtos(struct target *target) return false; } -static int ChibiOS_create(struct target *target) +static int chibios_create(struct target *target) { int i = 0; while ((i < CHIBIOS_NUM_PARAMS) && - (0 != strcmp(ChibiOS_params_list[i].target_name, target->type->name))) { + (0 != strcmp(chibios_params_list[i].target_name, target->type->name))) { i++; } if (i >= CHIBIOS_NUM_PARAMS) { @@ -542,6 +542,6 @@ static int ChibiOS_create(struct target *target) return -1; } - target->rtos->rtos_specific_params = (void *) &ChibiOS_params_list[i]; + target->rtos->rtos_specific_params = (void *) &chibios_params_list[i]; return 0; } diff --git a/src/rtos/embKernel.c b/src/rtos/embKernel.c index 8a307f1..2f04963 100644 --- a/src/rtos/embKernel.c +++ b/src/rtos/embKernel.c @@ -135,7 +135,7 @@ static int embKernel_create(struct target *target) } static int embKernel_get_tasks_details(struct rtos *rtos, int64_t iterable, const struct embKernel_params *param, - struct thread_detail *details, const char* state_str) + struct thread_detail *details, const char *state_str) { int64_t task = 0; int retval = target_read_buffer(rtos->target, iterable + param->iterable_task_owner_offset, param->pointer_width, @@ -340,4 +340,3 @@ static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[ return 0; } - diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c index d363369..65b89c4 100644 --- a/src/rtos/hwthread.c +++ b/src/rtos/hwthread.c @@ -216,7 +216,7 @@ static int hwthread_smp_init(struct target *target) return hwthread_update_threads(target->rtos); } -static struct target *find_thread(struct target *target, int64_t thread_id) +static struct target *hwthread_find_thread(struct target *target, int64_t thread_id) { /* Find the thread with that thread_id */ if (target == NULL) @@ -240,7 +240,7 @@ static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct target *target = rtos->target; - struct target *curr = find_thread(target, thread_id); + struct target *curr = hwthread_find_thread(target, thread_id); if (curr == NULL) return ERROR_FAIL; @@ -278,7 +278,7 @@ static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id, struct target *target = rtos->target; - struct target *curr = find_thread(target, thread_id); + struct target *curr = hwthread_find_thread(target, thread_id); if (curr == NULL) { LOG_ERROR("Couldn't find RTOS thread for id %" PRId64 ".", thread_id); return ERROR_FAIL; @@ -315,7 +315,7 @@ int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value) struct target *target = rtos->target; - struct target *curr = find_thread(target, rtos->current_thread); + struct target *curr = hwthread_find_thread(target, rtos->current_thread); if (curr == NULL) return ERROR_FAIL; @@ -338,7 +338,7 @@ static int hwthread_target_for_threadid(struct connection *connection, int64_t t { struct target *target = get_target_from_connection(connection); - struct target *curr = find_thread(target, thread_id); + struct target *curr = hwthread_find_thread(target, thread_id); if (curr == NULL) return ERROR_FAIL; @@ -408,7 +408,7 @@ int hwthread_read_buffer(struct rtos *rtos, target_addr_t address, struct target *target = rtos->target; - struct target *curr = find_thread(target, rtos->current_thread); + struct target *curr = hwthread_find_thread(target, rtos->current_thread); if (curr == NULL) return ERROR_FAIL; @@ -423,7 +423,7 @@ int hwthread_write_buffer(struct rtos *rtos, target_addr_t address, struct target *target = rtos->target; - struct target *curr = find_thread(target, rtos->current_thread); + struct target *curr = hwthread_find_thread(target, rtos->current_thread); if (curr == NULL) return ERROR_FAIL; diff --git a/src/rtos/linux.c b/src/rtos/linux.c index 74172b7..63659bb 100644 --- a/src/rtos/linux.c +++ b/src/rtos/linux.c @@ -621,17 +621,17 @@ struct threads *liste_del_task(struct threads *task_list, struct threads **t, struct threads *prev) { LOG_INFO("del task %" PRId64, (*t)->threadid); - prev->next = (*t)->next; - - if (prev == task_list) - task_list = prev; + if (prev) + prev->next = (*t)->next; + else + task_list = (*t)->next; /* free content of threads */ if ((*t)->context) free((*t)->context); free(*t); - *t = prev; + *t = prev ? prev : task_list; return task_list; } @@ -725,6 +725,7 @@ int linux_get_tasks(struct target *target, int context) /* check that this thread is not one the current threads already * created */ + uint32_t base_addr; #ifdef PID_CHECK if (!current_pid(linux_os, t->pid)) { @@ -745,12 +746,13 @@ int linux_get_tasks(struct target *target, int context) t->context = cpu_context_read(target, t->base_addr, &t->thread_info_addr); + base_addr = next_task(target, t); } else { /*LOG_INFO("thread %s is a current thread already created",t->name); */ + base_addr = next_task(target, t); free(t); } - uint32_t base_addr = next_task(target, t); t = calloc(1, sizeof(struct threads)); t->base_addr = base_addr; } @@ -993,10 +995,8 @@ static int linux_task_update(struct target *target, int context) if (context) thread_list->context = cpu_context_read(target, - thread_list-> - base_addr, - &thread_list-> - thread_info_addr); + thread_list->base_addr, + &thread_list->thread_info_addr); } else { /* it is a current thread no need to read context */ } @@ -1178,7 +1178,7 @@ int linux_gdb_T_packet(struct connection *connection, if (linux_os->threads_needs_update == 0) { struct threads *temp = linux_os->thread_list; - struct threads *prev = linux_os->thread_list; + struct threads *prev = NULL; while (temp != NULL) { if (temp->threadid == threadid) { @@ -1188,9 +1188,8 @@ int linux_gdb_T_packet(struct connection *connection, } else { /* delete item in the list */ linux_os->thread_list = - liste_del_task(linux_os-> - thread_list, &temp, - prev); + liste_del_task(linux_os->thread_list, + &temp, prev); linux_os->thread_count--; gdb_put_packet(connection, "E01", 3); return ERROR_OK; @@ -1321,9 +1320,7 @@ static int linux_thread_packet(struct connection *connection, char const *packet if (strncmp(packet, "qSymbol", 7) == 0) { if (rtos_qsymbol(connection, packet, packet_size) == 1) { linux_compute_virt2phys(target, - target->rtos-> - symbols[INIT_TASK]. - address); + target->rtos->symbols[INIT_TASK].address); } break; @@ -1374,11 +1371,10 @@ static int linux_thread_packet(struct connection *connection, char const *packet } if ((ct != NULL) && (ct->threadid != - target->rtos-> - current_threadid) + target->rtos->current_threadid) && (target->rtos->current_threadid != -1)) - LOG_WARNING("WARNING! current GDB thread do not match" \ - "current thread running." \ + LOG_WARNING("WARNING! current GDB thread do not match " + "current thread running. " "Switch thread in GDB to threadid %d", (int)ct->threadid); @@ -1408,8 +1404,7 @@ static int linux_os_smp_init(struct target *target) while (head != (struct target_list *)NULL) { if (head->target->rtos != rtos) { struct linux_os *smp_os_linux = - (struct linux_os *)head->target->rtos-> - rtos_specific_params; + (struct linux_os *)head->target->rtos->rtos_specific_params; /* remap smp target on rtos */ free(head->target->rtos); head->target->rtos = rtos; diff --git a/src/rtos/mqx.c b/src/rtos/mqx.c index 6646ad4..f45c15d 100644 --- a/src/rtos/mqx.c +++ b/src/rtos/mqx.c @@ -106,7 +106,7 @@ static int mqx_valid_address_check( ) { enum mqx_arch arch_type = ((struct mqx_params *)rtos->rtos_specific_params)->target_arch; - const char * targetname = ((struct mqx_params *)rtos->rtos_specific_params)->target_name; + const char *targetname = ((struct mqx_params *)rtos->rtos_specific_params)->target_name; /* Cortex-M address range */ if (arch_type == mqx_arch_cortexm) { diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c index 8c3076e..322c7d1 100644 --- a/src/rtos/nuttx.c +++ b/src/rtos/nuttx.c @@ -401,4 +401,3 @@ struct rtos_type nuttx_rtos = { .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/rtos.c b/src/rtos/rtos.c index 6b7c9e2..8c84914 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -31,7 +31,7 @@ extern struct rtos_type FreeRTOS_rtos; extern struct rtos_type ThreadX_rtos; extern struct rtos_type eCos_rtos; extern struct rtos_type Linux_os; -extern struct rtos_type ChibiOS_rtos; +extern struct rtos_type chibios_rtos; extern struct rtos_type chromium_ec_rtos; extern struct rtos_type embKernel_rtos; extern struct rtos_type mqx_rtos; @@ -45,7 +45,7 @@ static struct rtos_type *rtos_types[] = { &FreeRTOS_rtos, &eCos_rtos, &Linux_os, - &ChibiOS_rtos, + &chibios_rtos, &chromium_ec_rtos, &embKernel_rtos, &mqx_rtos, @@ -124,7 +124,7 @@ int rtos_create(Jim_GetOptInfo *goi, struct target *target) { int x; const char *cp; - struct Jim_Obj *res; + Jim_Obj *res; int e; if (!goi->isconfigure && goi->argc != 0) { @@ -162,6 +162,11 @@ int rtos_create(Jim_GetOptInfo *goi, struct target *target) return JIM_ERR; } +void rtos_destroy(struct target *target) +{ + os_free(target); +} + int gdb_thread_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index ee9d4d4..9b43afb 100644 --- a/src/rtos/rtos.h +++ b/src/rtos/rtos.h @@ -126,6 +126,7 @@ struct rtos_register_stacking { #define GDB_THREAD_PACKET_NOT_CONSUMED (-40) int rtos_create(Jim_GetOptInfo *goi, struct target *target); +void rtos_destroy(struct target *target); int rtos_set_reg(struct connection *connection, int reg_num, uint8_t *reg_value); int rtos_generic_stack_read(struct target *target, diff --git a/src/rtos/rtos_embkernel_stackings.c b/src/rtos/rtos_embkernel_stackings.c index 4ee79af..543a8cd 100644 --- a/src/rtos/rtos_embkernel_stackings.c +++ b/src/rtos/rtos_embkernel_stackings.c @@ -51,5 +51,3 @@ const struct rtos_register_stacking rtos_embkernel_Cortex_M_stacking = { rtos_generic_stack_align8, /* stack_alignment */ rtos_embkernel_Cortex_M_stack_offsets /* register_offsets */ }; - - diff --git a/src/rtos/rtos_mqx_stackings.c b/src/rtos/rtos_mqx_stackings.c index 1a8bdfc..d18e591 100644 --- a/src/rtos/rtos_mqx_stackings.c +++ b/src/rtos/rtos_mqx_stackings.c @@ -77,4 +77,3 @@ const struct rtos_register_stacking rtos_mqx_arm_v7m_stacking = { NULL, /* stack_alignment */ rtos_mqx_arm_v7m_stack_offsets /* register_offsets */ }; - diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 755463c..4c5f32a 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -43,6 +43,7 @@ #include <target/register.h> #include <target/target.h> #include <target/target_type.h> +#include <target/semihosting_common.h> #include "server.h" #include <flash/nor/core.h> #include "gdb_server.h" @@ -70,7 +71,7 @@ struct gdb_connection { char buffer[GDB_BUFFER_SIZE + 1]; /* Extra byte for nul-termination */ char *buf_p; int buf_cnt; - int ctrl_c; + bool ctrl_c; enum target_state frontend_state; struct image *vflash_image; bool closed; @@ -90,6 +91,8 @@ struct gdb_connection { * normally we reply with a S reply via gdb_last_signal_packet. * as a side note this behaviour only effects gdb > 6.8 */ bool attached; + /* set when extended protocol is used */ + bool extended_protocol; /* temporarily used for target description support */ struct target_desc_format target_desc; /* temporarily used for thread list support */ @@ -274,9 +277,9 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char) gdb_con->buf_cnt--; *next_char = *(gdb_con->buf_p++); if (gdb_con->buf_cnt > 0) - connection->input_pending = 1; + connection->input_pending = true; else - connection->input_pending = 0; + connection->input_pending = false; #ifdef _DEBUG_GDB_IO_ LOG_DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char); #endif @@ -299,9 +302,9 @@ static inline int gdb_get_char_fast(struct connection *connection, *next_char = **buf_p; (*buf_p)++; if (*buf_cnt > 0) - connection->input_pending = 1; + connection->input_pending = true; else - connection->input_pending = 0; + connection->input_pending = false; #ifdef _DEBUG_GDB_IO_ LOG_DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char); @@ -439,7 +442,7 @@ static int gdb_put_packet_inner(struct connection *connection, log_remove_callback(gdb_log_callback, connection); LOG_WARNING("negative reply, retrying"); } else if (reply == 0x3) { - gdb_con->ctrl_c = 1; + gdb_con->ctrl_c = true; retval = gdb_get_char(connection, &reply); if (retval != ERROR_OK) return retval; @@ -644,7 +647,7 @@ static int gdb_get_packet_inner(struct connection *connection, LOG_WARNING("negative acknowledgment, but no packet pending"); break; case 0x3: - gdb_con->ctrl_c = 1; + gdb_con->ctrl_c = true; *len = 0; return ERROR_OK; default: @@ -780,7 +783,7 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s%s", signal_var, stop_reason, current_thread); - gdb_connection->ctrl_c = 0; + gdb_connection->ctrl_c = false; } gdb_put_packet(connection, sig_reply, sig_reply_len); @@ -797,7 +800,7 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio if (strcmp(target->fileio_info->identifier, "open") == 0) sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, - target->fileio_info->param_2, + target->fileio_info->param_2 + 1, /* len + trailing zero */ target->fileio_info->param_3, target->fileio_info->param_4); else if (strcmp(target->fileio_info->identifier, "close") == 0) @@ -821,13 +824,13 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio else if (strcmp(target->fileio_info->identifier, "rename") == 0) sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64 "/%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, - target->fileio_info->param_2, + target->fileio_info->param_2 + 1, /* len + trailing zero */ target->fileio_info->param_3, - target->fileio_info->param_4); + target->fileio_info->param_4 + 1); /* len + trailing zero */ else if (strcmp(target->fileio_info->identifier, "unlink") == 0) sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, - target->fileio_info->param_2); + target->fileio_info->param_2 + 1); /* len + trailing zero */ else if (strcmp(target->fileio_info->identifier, "stat") == 0) sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, @@ -847,7 +850,7 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio else if (strcmp(target->fileio_info->identifier, "system") == 0) sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, - target->fileio_info->param_2); + target->fileio_info->param_2 + 1); /* len + trailing zero */ else if (strcmp(target->fileio_info->identifier, "exit") == 0) { /* If target hits exit syscall, report to GDB the program is terminated. * In addition, let target run its own exit syscall handler. */ @@ -937,7 +940,7 @@ static int gdb_new_connection(struct connection *connection) /* initialize gdb connection information */ gdb_connection->buf_p = gdb_connection->buffer; gdb_connection->buf_cnt = 0; - gdb_connection->ctrl_c = 0; + gdb_connection->ctrl_c = false; gdb_connection->frontend_state = TARGET_HALTED; gdb_connection->vflash_image = NULL; gdb_connection->closed = false; @@ -946,6 +949,7 @@ static int gdb_new_connection(struct connection *connection) gdb_connection->sync = false; gdb_connection->mem_write_error = false; gdb_connection->attached = true; + gdb_connection->extended_protocol = false; gdb_connection->target_desc.tdesc = NULL; gdb_connection->target_desc.tdesc_length = 0; gdb_connection->thread_list = NULL; @@ -998,7 +1002,7 @@ static int gdb_new_connection(struct connection *connection) continue; retval = get_flash_bank_by_num(i, &p); if (retval != ERROR_OK) { - LOG_ERROR("Connect failed. Consider setting up a gdb-attach event for the target " \ + LOG_ERROR("Connect failed. Consider setting up a gdb-attach event for the target " "to prepare target for GDB connect, or use 'gdb_memory_map disable'."); return retval; } @@ -1739,8 +1743,8 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection, /* print out a string and allocate more space as needed, * mainly used for XML at this point */ -static void xml_printf(int *retval, char **xml, int *pos, int *size, - const char *fmt, ...) +static __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 5, 6))) void xml_printf(int *retval, + char **xml, int *pos, int *size, const char *fmt, ...) { if (*retval != ERROR_OK) return; @@ -1881,7 +1885,7 @@ static int gdb_memory_map(struct connection *connection, if (ram_start < p->base) xml_printf(&retval, &xml, &pos, &size, "<memory type=\"ram\" start=\"" TARGET_ADDR_FMT "\" " - "length=\"0x%x\"/>\n", + "length=\"" TARGET_ADDR_FMT "\"/>\n", ram_start, p->base - ram_start); /* Report adjacent groups of same-size sectors. So for @@ -2038,7 +2042,7 @@ static int lookup_add_arch_defined_types(char const **arch_defined_types_list[], static int gdb_generate_reg_type_description(struct target *target, char **tdesc, int *pos, int *size, struct reg_data_type *type, - char const **arch_defined_types_list[], int * num_arch_defined_types) + char const **arch_defined_types_list[], int *num_arch_defined_types) { int retval = ERROR_OK; @@ -2288,14 +2292,11 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o int reg_list_size; char const *architecture; char const **features = NULL; - char const **arch_defined_types = NULL; int feature_list_size = 0; - int num_arch_defined_types = 0; char *tdesc = NULL; int pos = 0; int size = 0; - arch_defined_types = calloc(1, sizeof(char *)); retval = smp_reg_list_noread(target, ®_list, ®_list_size, REG_CLASS_ALL); @@ -2337,7 +2338,10 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o /* generate target description according to register list */ if (features != NULL) { while (features[current_feature]) { + char const **arch_defined_types = NULL; + int num_arch_defined_types = 0; + arch_defined_types = calloc(1, sizeof(char *)); xml_printf(&retval, &tdesc, &pos, &size, "<feature name=\"%s\">\n", features[current_feature]); @@ -2402,6 +2406,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o "</feature>\n"); current_feature++; + free(arch_defined_types); } } @@ -2411,7 +2416,6 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o error: free(features); free(reg_list); - free(arch_defined_types); if (retval == ERROR_OK) *tdesc_out = tdesc; @@ -2552,7 +2556,7 @@ static int gdb_generate_thread_list(struct target *target, char **thread_list_ou xml_printf(&retval, &thread_list, &pos, &size, ", "); xml_printf(&retval, &thread_list, &pos, &size, - thread_detail->extra_info_str); + "%s", thread_detail->extra_info_str); } xml_printf(&retval, &thread_list, &pos, &size, @@ -2947,7 +2951,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p if (gdb_connection->sync) { gdb_connection->sync = false; if (ct->state == TARGET_HALTED) { - LOG_DEBUG("stepi ignored. GDB will now fetch the register state " \ + LOG_DEBUG("stepi ignored. GDB will now fetch the register state " "from the target."); gdb_sig_halted(connection); log_remove_callback(gdb_log_callback, connection); @@ -2981,6 +2985,96 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p return false; } +static char *next_hex_encoded_field(const char **str, char sep) +{ + size_t hexlen; + const char *hex = *str; + if (hex[0] == '\0') + return NULL; + + const char *end = strchr(hex, sep); + if (end == NULL) + hexlen = strlen(hex); + else + hexlen = end - hex; + *str = hex + hexlen + 1; + + if (hexlen % 2 != 0) { + /* Malformed hex data */ + return NULL; + } + + size_t count = hexlen / 2; + char *decoded = malloc(count + 1); + if (decoded == NULL) + return NULL; + + size_t converted = unhexify((void *)decoded, hex, count); + if (converted != count) { + free(decoded); + return NULL; + } + + decoded[count] = '\0'; + return decoded; +} + +/* handle extended restart packet */ +static void gdb_restart_inferior(struct connection *connection, const char *packet, int packet_size) +{ + struct gdb_connection *gdb_con = connection->priv; + struct target *target = get_target_from_connection(connection); + + breakpoint_clear_target(target); + watchpoint_clear_target(target); + command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %s", + target_name(target)); + /* set connection as attached after reset */ + gdb_con->attached = true; + /* info rtos parts */ + gdb_thread_packet(connection, packet, packet_size); +} + +static bool gdb_handle_vrun_packet(struct connection *connection, const char *packet, int packet_size) +{ + struct target *target = get_target_from_connection(connection); + const char *parse = packet; + + /* Skip "vRun" */ + parse += 4; + + if (parse[0] != ';') + return false; + parse++; + + /* Skip first field "filename"; don't know what to do with it. */ + free(next_hex_encoded_field(&parse, ';')); + + char *cmdline = next_hex_encoded_field(&parse, ';'); + char *arg; + while (cmdline != NULL && (arg = next_hex_encoded_field(&parse, ';')) != NULL) { + char *new_cmdline = alloc_printf("%s %s", cmdline, arg); + free(cmdline); + free(arg); + cmdline = new_cmdline; + } + + if (cmdline != NULL) { + if (target->semihosting != NULL) { + LOG_INFO("GDB set inferior command line to '%s'", cmdline); + free(target->semihosting->cmdline); + target->semihosting->cmdline = cmdline; + } else { + LOG_INFO("GDB set inferior command line to '%s' but semihosting is unavailable", cmdline); + free(cmdline); + } + } + + gdb_restart_inferior(connection, packet, packet_size); + gdb_put_packet(connection, "S00", 3); + return true; +} + static int gdb_v_packet(struct connection *connection, char const *packet, int packet_size) { @@ -3007,6 +3101,16 @@ static int gdb_v_packet(struct connection *connection, return ERROR_OK; } + if (strncmp(packet, "vRun", 4) == 0) { + bool handled; + + handled = gdb_handle_vrun_packet(connection, packet, packet_size); + if (!handled) + gdb_put_packet(connection, "", 0); + + return ERROR_OK; + } + /* if flash programming disabled - send a empty reply */ if (gdb_flash_program == 0) { @@ -3226,7 +3330,6 @@ static int gdb_input_inner(struct connection *connection) int packet_size; int retval; struct gdb_connection *gdb_con = connection->priv; - static int extended_protocol; target = get_target_from_connection(connection); @@ -3333,7 +3436,7 @@ static int gdb_input_inner(struct connection *connection) "Waiting for target to halt."); already_running = true; } else if (target->state != TARGET_HALTED) { - LOG_WARNING("The target is not in the halted nor running stated, " \ + LOG_WARNING("The target is not in the halted nor running stated, " "stepi/continue ignored."); nostep = true; } else if ((packet[0] == 's') && gdb_con->sync) { @@ -3342,7 +3445,7 @@ static int gdb_input_inner(struct connection *connection) * make only the single stepping have the sync feature... */ nostep = true; - LOG_DEBUG("stepi ignored. GDB will now fetch the register state " \ + LOG_DEBUG("stepi ignored. GDB will now fetch the register state " "from the target."); } gdb_con->sync = false; @@ -3385,7 +3488,6 @@ static int gdb_input_inner(struct connection *connection) break; case 'D': retval = gdb_detach(connection); - extended_protocol = 0; break; case 'X': retval = gdb_write_memory_binary_packet(connection, packet, packet_size); @@ -3393,7 +3495,7 @@ static int gdb_input_inner(struct connection *connection) return retval; break; case 'k': - if (extended_protocol != 0) { + if (gdb_con->extended_protocol) { gdb_con->attached = false; break; } @@ -3401,19 +3503,12 @@ static int gdb_input_inner(struct connection *connection) return ERROR_SERVER_REMOTE_CLOSED; case '!': /* handle extended remote protocol */ - extended_protocol = 1; + gdb_con->extended_protocol = true; gdb_put_packet(connection, "OK", 2); break; case 'R': /* handle extended restart packet */ - breakpoint_clear_target(target); - watchpoint_clear_target(target); - command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %s", - target_name(target)); - /* set connection as attached after reset */ - gdb_con->attached = true; - /* info rtos parts */ - gdb_thread_packet(connection, packet, packet_size); + gdb_restart_inferior(connection, packet, packet_size); break; case 'j': @@ -3464,7 +3559,7 @@ static int gdb_input_inner(struct connection *connection) retval = target_poll(t); if (retval != ERROR_OK) target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); - gdb_con->ctrl_c = 0; + gdb_con->ctrl_c = false; } else { LOG_INFO("The target is not running when halt was requested, stopping GDB."); target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); @@ -3500,7 +3595,7 @@ static int gdb_target_start(struct target *target, const char *port) if (NULL == gdb_service) return -ENOMEM; - LOG_DEBUG("starting gdb server for %s on %s", target_name(target), port); + LOG_INFO("starting gdb server for %s on %s", target_name(target), port); gdb_service->target = target; gdb_service->core[0] = -1; @@ -3567,7 +3662,7 @@ static int gdb_target_add_one(struct target *target) if (parse_long(gdb_port_next, &portnumber) == ERROR_OK) { free(gdb_port_next); if (portnumber) { - gdb_port_next = alloc_printf("%d", portnumber+1); + gdb_port_next = alloc_printf("%ld", portnumber+1); } else { /* Don't increment if gdb_port is 0, since we're just * trying to allocate an unused port. */ @@ -3750,7 +3845,7 @@ static const struct command_registration gdb_command_handlers[] = { { .name = "gdb_port", .handler = handle_gdb_port_command, - .mode = COMMAND_ANY, + .mode = COMMAND_CONFIG, .help = "Normally gdb listens to a TCP/IP port. Each subsequent GDB " "server listens for the next port number after the " "base port number specified. " diff --git a/src/server/server.c b/src/server/server.c index 9e63f74..23a15ef 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -76,7 +76,7 @@ static int add_connection(struct service *service, struct command_context *cmd_c memset(&c->sin, 0, sizeof(c->sin)); c->cmd_ctx = copy_command_context(cmd_ctx); c->service = service; - c->input_pending = 0; + c->input_pending = false; c->priv = NULL; c->next = NULL; @@ -562,7 +562,7 @@ int server_loop(struct command_context *command_context) struct connection *c; for (c = service->connections; c; ) { - if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending) { + if ((c->fd >= 0 && FD_ISSET(c->fd, &read_fds)) || c->input_pending) { retval = service->input(c); if (retval != ERROR_OK) { struct connection *next = c->next; @@ -631,7 +631,7 @@ static void sigkey_handler(int sig) #endif -int server_preinit(void) +int server_host_os_entry(void) { /* this currently only calls WSAStartup on native win32 systems * before any socket operations are performed. @@ -647,7 +647,21 @@ int server_preinit(void) LOG_ERROR("Failed to Open Winsock"); return ERROR_FAIL; } +#endif + return ERROR_OK; +} + +int server_host_os_close(void) +{ +#ifdef _WIN32 + WSACleanup(); +#endif + return ERROR_OK; +} +int server_preinit(void) +{ +#ifdef _WIN32 /* register ctrl-c handler */ SetConsoleCtrlHandler(ControlHandler, TRUE); @@ -688,7 +702,6 @@ int server_quit(void) target_quit(); #ifdef _WIN32 - WSACleanup(); SetConsoleCtrlHandler(ControlHandler, FALSE); return ERROR_OK; @@ -799,7 +812,7 @@ static const struct command_registration server_command_handlers[] = { { .name = "bindto", .handler = &handle_bindto_command, - .mode = COMMAND_ANY, + .mode = COMMAND_CONFIG, .usage = "[name]", .help = "Specify address by name on which to listen for " "incoming TCP/IP connections", diff --git a/src/server/server.h b/src/server/server.h index 96e0b48..f4cc39d 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -49,7 +49,7 @@ struct connection { struct sockaddr_in sin; struct command_context *cmd_ctx; struct service *service; - int input_pending; + bool input_pending; void *priv; struct connection *next; }; @@ -80,6 +80,9 @@ int add_service(char *name, const char *port, void *priv); int remove_service(const char *name, const char *port); +int server_host_os_entry(void); +int server_host_os_close(void); + int server_preinit(void); int server_init(struct command_context *cmd_ctx); int server_quit(void); diff --git a/src/server/startup.tcl b/src/server/startup.tcl index 64ace40..dd1b31e 100644 --- a/src/server/startup.tcl +++ b/src/server/startup.tcl @@ -8,3 +8,14 @@ proc ocd_gdb_restart {target_id} { # one target reset halt } + +proc prevent_cps {} { + echo "Possible SECURITY ATTACK detected." + echo "It looks like somebody is sending POST or Host: commands to OpenOCD." + echo "This is likely due to an attacker attempting to use Cross Protocol Scripting" + echo "to compromise your OpenOCD instance. Connection aborted." + exit +} + +proc POST {args} { prevent_cps } +proc Host: {args} { prevent_cps } diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c index 1ec45ff..1ecb827 100644 --- a/src/server/tcl_server.c +++ b/src/server/tcl_server.c @@ -199,7 +199,7 @@ static int tcl_input(struct connection *connection) for (i = 0; i < rlen; i++) { /* buffer the data */ tclc->tc_line[tclc->tc_lineoffset] = in[i]; - if (tclc->tc_lineoffset < tclc->tc_line_size) { + if (tclc->tc_lineoffset + 1 < tclc->tc_line_size) { tclc->tc_lineoffset++; } else if (tclc->tc_line_size >= TCL_LINE_MAX) { /* maximum line size reached, drop line */ @@ -331,7 +331,7 @@ static const struct command_registration tcl_command_handlers[] = { { .name = "tcl_port", .handler = handle_tcl_port_command, - .mode = COMMAND_ANY, + .mode = COMMAND_CONFIG, .help = "Specify port on which to listen " "for incoming Tcl syntax. " "Read help on 'gdb_port'.", diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index a864f5f..d0583a9 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -312,6 +312,36 @@ static void telnet_history_down(struct connection *connection) telnet_history_go(connection, next_history); } +static int telnet_history_print(struct connection *connection) +{ + struct telnet_connection *tc; + + tc = connection->priv; + + for (size_t i = 1; i < TELNET_LINE_HISTORY_SIZE; i++) { + char *line; + + /* + * The tc->next_history line contains empty string (unless NULL), thus + * it is not printed. + */ + line = tc->history[(tc->next_history + i) % TELNET_LINE_HISTORY_SIZE]; + + if (line) { + telnet_write(connection, line, strlen(line)); + telnet_write(connection, "\r\n\x00", 3); + } + } + + tc->line_size = 0; + tc->line_cursor = 0; + + /* The prompt is always placed at the line beginning. */ + telnet_write(connection, "\r", 1); + + return telnet_prompt(connection); +} + static void telnet_move_cursor(struct connection *connection, size_t pos) { struct telnet_connection *tc; @@ -407,21 +437,11 @@ static int telnet_input(struct connection *connection) telnet_write(connection, "\r\n\x00", 3); if (strcmp(t_con->line, "history") == 0) { - size_t i; - for (i = 1; i < TELNET_LINE_HISTORY_SIZE; i++) { - /* the t_con->next_history line contains empty string - * (unless NULL), thus it is not printed */ - char *history_line = t_con->history[(t_con-> - next_history + i) % - TELNET_LINE_HISTORY_SIZE]; - if (history_line) { - telnet_write(connection, history_line, - strlen(history_line)); - telnet_write(connection, "\r\n\x00", 3); - } - } - t_con->line_size = 0; - t_con->line_cursor = 0; + retval = telnet_history_print(connection); + + if (retval != ERROR_OK) + return retval; + continue; } @@ -705,7 +725,7 @@ static const struct command_registration telnet_command_handlers[] = { { .name = "telnet_port", .handler = handle_telnet_port_command, - .mode = COMMAND_ANY, + .mode = COMMAND_CONFIG, .help = "Specify port on which to listen " "for incoming telnet connections. " "Read help on 'gdb_port'.", diff --git a/src/svf/svf.c b/src/svf/svf.c index 759ba52..fd27417 100644 --- a/src/svf/svf.c +++ b/src/svf/svf.c @@ -990,7 +990,7 @@ static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str) /* TODO: set jtag speed to */ if (svf_para.frequency > 0) { command_run_linef(cmd_ctx, - "adapter_khz %d", + "adapter speed %d", (int)svf_para.frequency / 1000); LOG_DEBUG("\tfrequency = %f", svf_para.frequency); } @@ -1310,7 +1310,6 @@ XXR_common: case PIOMAP: LOG_ERROR("PIO and PIOMAP are not supported"); return ERROR_FAIL; - break; case RUNTEST: /* RUNTEST [run_state] run_count run_clk [min_time SEC [MAXIMUM max_time * SEC]] [ENDSTATE end_state] */ @@ -1532,7 +1531,6 @@ XXR_common: default: LOG_ERROR("invalid svf command: %s", argus[0]); return ERROR_FAIL; - break; } if (!svf_quiet) { @@ -1542,8 +1540,8 @@ XXR_common: if (debug_level >= LOG_LVL_DEBUG) { /* for convenient debugging, execute tap if possible */ - if ((svf_buffer_index > 0) && \ - (((command != STATE) && (command != RUNTEST)) || \ + if ((svf_buffer_index > 0) && + (((command != STATE) && (command != RUNTEST)) || ((command == STATE) && (num_of_argu == 2)))) { if (ERROR_OK != svf_execute_tap()) return ERROR_FAIL; @@ -1557,8 +1555,8 @@ XXR_common: /* for fast executing, execute tap if necessary */ /* half of the buffer is for the next command */ if (((svf_buffer_index >= SVF_MAX_BUFFER_SIZE_TO_COMMIT) || - (svf_check_tdo_para_index >= SVF_CHECK_TDO_PARA_SIZE / 2)) && \ - (((command != STATE) && (command != RUNTEST)) || \ + (svf_check_tdo_para_index >= SVF_CHECK_TDO_PARA_SIZE / 2)) && + (((command != STATE) && (command != RUNTEST)) || ((command == STATE) && (num_of_argu == 2)))) return svf_execute_tap(); } diff --git a/src/target/Makefile.am b/src/target/Makefile.am index afa5f49..42d809d 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -24,15 +24,14 @@ noinst_LTLIBRARIES += %D%/libtarget.la $(STM8_SRC) \ $(INTEL_IA32_SRC) \ $(ESIRISC_SRC) \ + $(ARC_SRC) \ %D%/avrt.c \ %D%/dsp563xx.c \ %D%/dsp563xx_once.c \ %D%/dsp5680xx.c \ - %D%/hla_target.c - -if TARGET64 -%C%_libtarget_la_SOURCES +=$(ARMV8_SRC) -endif + %D%/hla_target.c \ + $(ARMV8_SRC) \ + $(MIPS64_SRC) TARGET_CORE_SRC = \ %D%/algorithm.c \ @@ -97,6 +96,7 @@ ARM_DEBUG_SRC = \ %D%/arm_dap.c \ %D%/armv7a_cache.c \ %D%/armv7a_cache_l2x.c \ + %D%/adi_v5_dapdirect.c \ %D%/adi_v5_jtag.c \ %D%/adi_v5_swd.c \ %D%/embeddedice.c \ @@ -120,6 +120,14 @@ MIPS32_SRC = \ %D%/mips32_dmaacc.c \ %D%/mips_ejtag.c +MIPS64_SRC = \ + %D%/mips64.c \ + %D%/mips32_pracc.c \ + %D%/mips64_pracc.c \ + %D%/mips_mips64.c \ + %D%/trace.c \ + %D%/mips_ejtag.c + NDS32_SRC = \ %D%/nds32.c \ %D%/nds32_reg.c \ @@ -146,6 +154,12 @@ ESIRISC_SRC = \ %D%/esirisc_jtag.c \ %D%/esirisc_trace.c +ARC_SRC = \ + %D%/arc.c \ + %D%/arc_cmd.c \ + %D%/arc_jtag.c \ + %D%/arc_mem.c + %C%_libtarget_la_SOURCES += \ %D%/algorithm.h \ %D%/arm.h \ @@ -193,10 +207,13 @@ ESIRISC_SRC = \ %D%/etm_dummy.h \ %D%/image.h \ %D%/mips32.h \ + %D%/mips64.h \ %D%/mips_m4k.h \ + %D%/mips_mips64.h \ %D%/mips_ejtag.h \ %D%/mips32_pracc.h \ %D%/mips32_dmaacc.h \ + %D%/mips64_pracc.h \ %D%/oocd_trace.h \ %D%/register.h \ %D%/target.h \ @@ -230,7 +247,11 @@ ESIRISC_SRC = \ %D%/esirisc.h \ %D%/esirisc_jtag.h \ %D%/esirisc_regs.h \ - %D%/esirisc_trace.h + %D%/esirisc_trace.h \ + %D%/arc.h \ + %D%/arc_cmd.h \ + %D%/arc_jtag.h \ + %D%/arc_mem.h include %D%/openrisc/Makefile.am include %D%/riscv/Makefile.am diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 7acb472..87176f6 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -1176,7 +1176,7 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres if (saved_retval != ERROR_OK) return saved_retval; - return aarch64_poll(target); + return ERROR_OK; } static int aarch64_restore_context(struct target *target, bool bpwp) @@ -1263,9 +1263,32 @@ static int aarch64_set_breakpoint(struct target *target, brp_list[brp_i].value); } else if (breakpoint->type == BKPT_SOFT) { + uint32_t opcode; uint8_t code[4]; - buf_set_u32(code, 0, 32, armv8_opcode(armv8, ARMV8_OPC_HLT)); + if (armv8_dpm_get_core_state(&armv8->dpm) == ARM_STATE_AARCH64) { + opcode = ARMV8_HLT(11); + + if (breakpoint->length != 4) + LOG_ERROR("bug: breakpoint length should be 4 in AArch64 mode"); + } else { + /** + * core_state is ARM_STATE_ARM + * in that case the opcode depends on breakpoint length: + * - if length == 4 => A32 opcode + * - if length == 2 => T32 opcode + * - if length == 3 => T32 opcode (refer to gdb doc : ARM-Breakpoint-Kinds) + * in that case the length should be changed from 3 to 4 bytes + **/ + opcode = (breakpoint->length == 4) ? ARMV8_HLT_A1(11) : + (uint32_t) (ARMV8_HLT_T1(11) | ARMV8_HLT_T1(11) << 16); + + if (breakpoint->length == 3) + breakpoint->length = 4; + } + + buf_set_u32(code, 0, 32, opcode); + retval = target_read_memory(target, breakpoint->address & 0xFFFFFFFFFFFFFFFE, breakpoint->length, 1, @@ -2759,8 +2782,17 @@ static const struct command_registration aarch64_exec_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +extern const struct command_registration semihosting_common_handlers[]; + static const struct command_registration aarch64_command_handlers[] = { { + .name = "arm", + .mode = COMMAND_ANY, + .help = "ARM Command Group", + .usage = "", + .chain = semihosting_common_handlers + }, + { .chain = armv8_command_handlers, }, { diff --git a/src/target/adi_v5_dapdirect.c b/src/target/adi_v5_dapdirect.c new file mode 100644 index 0000000..c0deee1 --- /dev/null +++ b/src/target/adi_v5_dapdirect.c @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved + * Author(s): Antonio Borneo <borneo.antonio@gmail.com> for STMicroelectronics + * + * 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/>. + */ + +/** + * @file + * Utilities to support in-circuit debuggers that provide APIs to access + * directly ARM DAP, hiding the access to the underlining transport used + * for the physical connection (either JTAG or SWD). + * E.g. STMicroelectronics ST-Link/V2 (from version V2J24) and STLINK-V3. + * + * Single-DAP support only. + * + * For details, see "ARM IHI 0031A" + * ARM Debug Interface v5 Architecture Specification + * + * FIXME: in JTAG mode, trst is not managed + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <jtag/interface.h> +#include <jtag/tcl.h> +#include <transport/transport.h> + +COMMAND_HANDLER(dapdirect_jtag_empty_command) +{ + LOG_DEBUG("dapdirect_jtag_empty_command(\"%s\")", CMD_NAME); + + return ERROR_OK; +} + +COMMAND_HANDLER(dapdirect_jtag_reset_command) +{ + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + /* + * in case the adapter has not already handled asserting srst + * we will attempt it again + */ + if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { + if (jtag_reset_config & RESET_SRST_NO_GATING) { + adapter_assert_reset(); + return ERROR_OK; + } + LOG_WARNING("\'srst_nogate\' reset_config option is required"); + } + adapter_deassert_reset(); + return ERROR_OK; +} + +static const struct command_registration dapdirect_jtag_subcommand_handlers[] = { + { + .name = "newtap", + .mode = COMMAND_CONFIG, + .jim_handler = jim_jtag_newtap, + .help = "declare a new TAP" + }, + { + .name = "init", + .mode = COMMAND_ANY, + .handler = dapdirect_jtag_empty_command, + .usage = "" + }, + { + .name = "arp_init", + .mode = COMMAND_ANY, + .handler = dapdirect_jtag_empty_command, + .usage = "" + }, + { + .name = "arp_init-reset", + .mode = COMMAND_ANY, + .handler = dapdirect_jtag_reset_command, + .usage = "" + }, + { + .name = "tapisenabled", + .mode = COMMAND_EXEC, + .jim_handler = jim_jtag_tap_enabler, + }, + { + .name = "tapenable", + .mode = COMMAND_EXEC, + .jim_handler = jim_jtag_tap_enabler, + }, + { + .name = "tapdisable", + .mode = COMMAND_EXEC, + .handler = dapdirect_jtag_empty_command, + .usage = "", + }, + { + .name = "configure", + .mode = COMMAND_ANY, + .handler = dapdirect_jtag_empty_command, + .usage = "", + }, + { + .name = "cget", + .mode = COMMAND_EXEC, + .jim_handler = jim_jtag_configure, + }, + { + .name = "names", + .mode = COMMAND_ANY, + .handler = dapdirect_jtag_empty_command, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration dapdirect_jtag_handlers[] = { + { + .name = "jtag", + .mode = COMMAND_ANY, + .chain = dapdirect_jtag_subcommand_handlers, + .usage = "", + }, + { + .name = "jtag_ntrst_delay", + .mode = COMMAND_ANY, + .handler = dapdirect_jtag_empty_command, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration dapdirect_swd_subcommand_handlers[] = { + { + .name = "newdap", + .mode = COMMAND_CONFIG, + .jim_handler = jim_jtag_newtap, + .help = "declare a new SWD DAP", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration dapdirect_swd_handlers[] = { + { + .name = "swd", + .mode = COMMAND_ANY, + .help = "SWD command group", + .usage = "", + .chain = dapdirect_swd_subcommand_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +static int dapdirect_jtag_select(struct command_context *ctx) +{ + LOG_DEBUG("dapdirect_jtag_select()"); + + return register_commands(ctx, NULL, dapdirect_jtag_handlers); +} + +static int dapdirect_swd_select(struct command_context *ctx) +{ + LOG_DEBUG("dapdirect_swd_select()"); + + return register_commands(ctx, NULL, dapdirect_swd_handlers); +} + +static int dapdirect_init(struct command_context *ctx) +{ + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + LOG_DEBUG("dapdirect_init()"); + + if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { + if (jtag_reset_config & RESET_SRST_NO_GATING) + adapter_assert_reset(); + else + LOG_WARNING("\'srst_nogate\' reset_config option is required"); + } else + adapter_deassert_reset(); + + return ERROR_OK; +} + +static struct transport dapdirect_jtag_transport = { + .name = "dapdirect_jtag", + .select = dapdirect_jtag_select, + .init = dapdirect_init, +}; + +static struct transport dapdirect_swd_transport = { + .name = "dapdirect_swd", + .select = dapdirect_swd_select, + .init = dapdirect_init, +}; + +static void dapdirect_constructor(void) __attribute__((constructor)); +static void dapdirect_constructor(void) +{ + transport_register(&dapdirect_jtag_transport); + transport_register(&dapdirect_swd_transport); +} + +/** + * Returns true if the current debug session + * is using JTAG as its transport. + */ +bool transport_is_dapdirect_jtag(void) +{ + return get_current_transport() == &dapdirect_jtag_transport; +} + +/** + * Returns true if the current debug session + * is using SWD as its transport. + */ +bool transport_is_dapdirect_swd(void) +{ + return get_current_transport() == &dapdirect_swd_transport; +} diff --git a/src/target/adi_v5_jtag.c b/src/target/adi_v5_jtag.c index a3867e1..c2100eb 100644 --- a/src/target/adi_v5_jtag.c +++ b/src/target/adi_v5_jtag.c @@ -38,6 +38,7 @@ #include "arm_adi_v5.h" #include <helper/time_support.h> #include <helper/list.h> +#include <jtag/swd.h> /*#define DEBUG_WAIT*/ @@ -139,6 +140,13 @@ struct dap_cmd { uint8_t outvalue_buf[4]; }; +#define MAX_DAP_COMMAND_NUM 65536 + +struct dap_cmd_pool { + struct list_head lh; + struct dap_cmd cmd; +} dap_cmd_pool; + static void log_dap_cmd(const char *header, struct dap_cmd *el) { #ifdef DEBUG_WAIT @@ -153,34 +161,75 @@ static void log_dap_cmd(const char *header, struct dap_cmd *el) #endif } -static struct dap_cmd *dap_cmd_new(uint8_t instr, +static int jtag_limit_queue_size(struct adiv5_dap *dap) +{ + if (dap->cmd_pool_size < MAX_DAP_COMMAND_NUM) + return ERROR_OK; + + return dap_run(dap); +} + +static struct dap_cmd *dap_cmd_new(struct adiv5_dap *dap, uint8_t instr, uint8_t reg_addr, uint8_t RnW, uint8_t *outvalue, uint8_t *invalue, uint32_t memaccess_tck) { - struct dap_cmd *cmd; - cmd = (struct dap_cmd *)calloc(1, sizeof(struct dap_cmd)); - if (cmd != NULL) { - INIT_LIST_HEAD(&cmd->lh); - cmd->instr = instr; - cmd->reg_addr = reg_addr; - cmd->RnW = RnW; - if (outvalue != NULL) - memcpy(cmd->outvalue_buf, outvalue, 4); - cmd->invalue = (invalue != NULL) ? invalue : cmd->invalue_buf; - cmd->memaccess_tck = memaccess_tck; + struct dap_cmd_pool *pool = NULL; + + if (list_empty(&dap->cmd_pool)) { + pool = calloc(1, sizeof(struct dap_cmd_pool)); + if (pool == NULL) + return NULL; + } else { + pool = list_first_entry(&dap->cmd_pool, struct dap_cmd_pool, lh); + list_del(&pool->lh); } + INIT_LIST_HEAD(&pool->lh); + dap->cmd_pool_size++; + + struct dap_cmd *cmd = &pool->cmd; + INIT_LIST_HEAD(&cmd->lh); + cmd->instr = instr; + cmd->reg_addr = reg_addr; + cmd->RnW = RnW; + if (outvalue != NULL) + memcpy(cmd->outvalue_buf, outvalue, 4); + cmd->invalue = (invalue != NULL) ? invalue : cmd->invalue_buf; + cmd->memaccess_tck = memaccess_tck; + return cmd; } -static void flush_journal(struct list_head *lh) +static void dap_cmd_release(struct adiv5_dap *dap, struct dap_cmd *cmd) +{ + struct dap_cmd_pool *pool = container_of(cmd, struct dap_cmd_pool, cmd); + if (dap->cmd_pool_size > MAX_DAP_COMMAND_NUM) + free(pool); + else + list_add(&pool->lh, &dap->cmd_pool); + + dap->cmd_pool_size--; +} + +static void flush_journal(struct adiv5_dap *dap, struct list_head *lh) { struct dap_cmd *el, *tmp; list_for_each_entry_safe(el, tmp, lh, lh) { list_del(&el->lh); + dap_cmd_release(dap, el); + } +} + +static void jtag_quit(struct adiv5_dap *dap) +{ + struct dap_cmd_pool *el, *tmp; + struct list_head *lh = &dap->cmd_pool; + + list_for_each_entry_safe(el, tmp, lh, lh) { + list_del(&el->lh); free(el); } } @@ -273,7 +322,7 @@ static int adi_jtag_dp_scan(struct adiv5_dap *dap, struct dap_cmd *cmd; int retval; - cmd = dap_cmd_new(instr, reg_addr, RnW, outvalue, invalue, memaccess_tck); + cmd = dap_cmd_new(dap, instr, reg_addr, RnW, outvalue, invalue, memaccess_tck); if (cmd != NULL) cmd->dp_select = dap->select; else @@ -415,7 +464,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) * To complete the READ, we just keep polling RDBUFF * until the WAIT condition clears */ - tmp = dap_cmd_new(JTAG_DP_DPACC, + tmp = dap_cmd_new(dap, JTAG_DP_DPACC, DP_RDBUFF, DPAP_READ, NULL, NULL, 0); if (tmp == NULL) { retval = ERROR_JTAG_DEVICE_ERROR; @@ -459,7 +508,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) } /* we're done with this command, release it */ - free(tmp); + dap_cmd_release(dap, tmp); if (retval != ERROR_OK) goto done; @@ -479,7 +528,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) } /* we're done with the journal, flush it */ - flush_journal(&dap->cmd_journal); + flush_journal(dap, &dap->cmd_journal); /* check for overrun condition in the last batch of transactions */ if (found_wait) { @@ -494,7 +543,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) /* restore SELECT register first */ if (!list_empty(&replay_list)) { el = list_first_entry(&replay_list, struct dap_cmd, lh); - tmp = dap_cmd_new(JTAG_DP_DPACC, + tmp = dap_cmd_new(dap, JTAG_DP_DPACC, DP_SELECT, DPAP_WRITE, (uint8_t *)&el->dp_select, NULL, 0); if (tmp == NULL) { retval = ERROR_JTAG_DEVICE_ERROR; @@ -545,8 +594,8 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) } done: - flush_journal(&replay_list); - flush_journal(&dap->cmd_journal); + flush_journal(dap, &replay_list); + flush_journal(dap, &dap->cmd_journal); return retval; } @@ -595,7 +644,7 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap) } done: - flush_journal(&dap->cmd_journal); + flush_journal(dap, &dap->cmd_journal); return retval; } @@ -615,10 +664,36 @@ static int jtag_check_reconnect(struct adiv5_dap *dap) return ERROR_OK; } +static int jtag_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq) +{ + int retval; + + switch (seq) { + case JTAG_TO_SWD: + retval = jtag_add_tms_seq(swd_seq_jtag_to_swd_len, + swd_seq_jtag_to_swd, TAP_INVALID); + break; + case SWD_TO_JTAG: + retval = jtag_add_tms_seq(swd_seq_swd_to_jtag_len, + swd_seq_swd_to_jtag, TAP_RESET); + break; + default: + LOG_ERROR("Sequence %d not supported", seq); + return ERROR_FAIL; + } + if (retval == ERROR_OK) + retval = jtag_execute_queue(); + return retval; +} + static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { - int retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC, reg, + int retval = jtag_limit_queue_size(dap); + if (retval != ERROR_OK) + return retval; + + retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC, reg, DPAP_READ, 0, dap->last_read, 0, NULL); dap->last_read = data; return retval; @@ -627,7 +702,11 @@ static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg, static int jtag_dp_q_write(struct adiv5_dap *dap, unsigned reg, uint32_t data) { - int retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC, + int retval = jtag_limit_queue_size(dap); + if (retval != ERROR_OK) + return retval; + + retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC, reg, DPAP_WRITE, data, dap->last_read, 0, NULL); dap->last_read = NULL; return retval; @@ -650,7 +729,11 @@ static int jtag_ap_q_bankselect(struct adiv5_ap *ap, unsigned reg) static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned reg, uint32_t *data) { - int retval = jtag_check_reconnect(ap->dap); + int retval = jtag_limit_queue_size(ap->dap); + if (retval != ERROR_OK) + return retval; + + retval = jtag_check_reconnect(ap->dap); if (retval != ERROR_OK) return retval; @@ -668,7 +751,11 @@ static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned reg, static int jtag_ap_q_write(struct adiv5_ap *ap, unsigned reg, uint32_t data) { - int retval = jtag_check_reconnect(ap->dap); + int retval = jtag_limit_queue_size(ap->dap); + if (retval != ERROR_OK) + return retval; + + retval = jtag_check_reconnect(ap->dap); if (retval != ERROR_OK) return retval; @@ -718,6 +805,7 @@ static int jtag_dp_sync(struct adiv5_dap *dap) */ const struct dap_ops jtag_dp_ops = { .connect = jtag_connect, + .send_sequence = jtag_send_sequence, .queue_dp_read = jtag_dp_q_read, .queue_dp_write = jtag_dp_q_write, .queue_ap_read = jtag_ap_q_read, @@ -725,4 +813,5 @@ const struct dap_ops jtag_dp_ops = { .queue_ap_abort = jtag_ap_q_abort, .run = jtag_dp_run, .sync = jtag_dp_sync, + .quit = jtag_quit, }; diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index 594b508..ee30ff7 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -96,7 +96,7 @@ static int swd_run_inner(struct adiv5_dap *dap) static int swd_connect(struct adiv5_dap *dap) { const struct swd_driver *swd = adiv5_dap_swd_driver(dap); - uint32_t dpidr; + uint32_t dpidr = 0xdeadbeef; int status; /* FIXME validate transport config ... is the @@ -112,7 +112,7 @@ static int swd_connect(struct adiv5_dap *dap) if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { if (jtag_reset_config & RESET_SRST_NO_GATING) - swd_add_reset(1); + adapter_assert_reset(); else LOG_WARNING("\'srst_nogate\' reset_config option is required"); } @@ -142,6 +142,14 @@ static int swd_connect(struct adiv5_dap *dap) return status; } +static int swd_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq) +{ + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); + assert(swd); + + return swd->switch_seq(seq); +} + static inline int check_sync(struct adiv5_dap *dap) { return do_sync ? swd_run_inner(dap) : ERROR_OK; @@ -320,6 +328,7 @@ static void swd_quit(struct adiv5_dap *dap) const struct dap_ops swd_dap_ops = { .connect = swd_connect, + .send_sequence = swd_send_sequence, .queue_dp_read = swd_queue_dp_read, .queue_dp_write = swd_queue_dp_write, .queue_ap_read = swd_queue_ap_read, @@ -359,9 +368,9 @@ static const struct command_registration swd_handlers[] = { static int swd_select(struct command_context *ctx) { - /* FIXME: only place where global 'jtag_interface' is still needed */ - extern struct jtag_interface *jtag_interface; - const struct swd_driver *swd = jtag_interface->swd; + /* FIXME: only place where global 'adapter_driver' is still needed */ + extern struct adapter_driver *adapter_driver; + const struct swd_driver *swd = adapter_driver->swd_ops; int retval; retval = register_commands(ctx, NULL, swd_handlers); diff --git a/src/target/arc.c b/src/target/arc.c new file mode 100644 index 0000000..6cf0ec7 --- /dev/null +++ b/src/target/arc.c @@ -0,0 +1,1652 @@ +/*************************************************************************** + * Copyright (C) 2013-2015,2019-2020 Synopsys, Inc. * + * Frank Dols <frank.dols@synopsys.com> * + * Mischa Jonker <mischa.jonker@synopsys.com> * + * Anton Kolesov <anton.kolesov@synopsys.com> * + * Evgeniy Didin <didin@synopsys.com> * + * * + * SPDX-License-Identifier: GPL-2.0-or-later * + ***************************************************************************/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arc.h" + + + +/* + * ARC architecture specific details. + * + * ARC has two types of registers: + * 1) core registers(e.g. r0,r1..) [is_core = true] + * 2) Auxiliary registers [is_core = false].. + * + * Auxiliary registers at the same time can be divided into + * read-only BCR(build configuration regs, e.g. isa_config, mpu_build) and + * R/RW non-BCR ("control" register, e.g. pc, status32_t, debug). + * + * The way of accessing to Core and AUX registers differs on Jtag level. + * BCR/non-BCR describes if the register is immutable and that reading + * unexisting register is safe RAZ, rather then an error. + * Note, core registers cannot be BCR. + * + * In arc/cpu/ tcl files all regiters are defined as core, non-BCR aux + * and BCR aux, in "add-reg" command they are passed to three lists + * respectively: core_reg_descriptions, aux_reg_descriptions, + * bcr_reg_descriptions. + * + * Due to the specifics of accessing to BCR/non-BCR registers there are two + * register caches: + * 1) core_and_aux_cache - includes registers described in + * core_reg_descriptions and aux_reg_descriptions lists. + * Used during save/restore context step. + * 2) bcr_cache - includes registers described bcr_reg_descriptions. + * Currently used internally during configure step. + */ + + + +void arc_reg_data_type_add(struct target *target, + struct arc_reg_data_type *data_type) +{ + LOG_DEBUG("Adding %s reg_data_type", data_type->data_type.id); + struct arc_common *arc = target_to_arc(target); + assert(arc); + + list_add_tail(&data_type->list, &arc->reg_data_types); +} + +/** + * Private implementation of register_get_by_name() for ARC that + * doesn't skip not [yet] existing registers. Used in many places + * for iteration through registers and even for marking required registers as + * existing. + */ +struct reg *arc_reg_get_by_name(struct reg_cache *first, + const char *name, bool search_all) +{ + unsigned int i; + struct reg_cache *cache = first; + + while (cache) { + for (i = 0; i < cache->num_regs; i++) { + if (!strcmp(cache->reg_list[i].name, name)) + return &(cache->reg_list[i]); + } + + if (search_all) + cache = cache->next; + else + break; + } + + return NULL; +} + + +/* Initialize arc_common structure, which passes to openocd target instance */ +static int arc_init_arch_info(struct target *target, struct arc_common *arc, + struct jtag_tap *tap) +{ + arc->common_magic = ARC_COMMON_MAGIC; + target->arch_info = arc; + + arc->jtag_info.tap = tap; + + /* The only allowed ir_length is 4 for ARC jtag. */ + if (tap->ir_length != 4) { + LOG_ERROR("ARC jtag instruction length should be equal to 4"); + return ERROR_FAIL; + } + + /* Add standard GDB data types */ + INIT_LIST_HEAD(&arc->reg_data_types); + struct arc_reg_data_type *std_types = calloc(ARRAY_SIZE(standard_gdb_types), + sizeof(*std_types)); + + if (!std_types) { + LOG_ERROR("Unable to allocate memory"); + return ERROR_FAIL; + } + + for (unsigned int i = 0; i < ARRAY_SIZE(standard_gdb_types); i++) { + std_types[i].data_type.type = standard_gdb_types[i].type; + std_types[i].data_type.id = standard_gdb_types[i].id; + arc_reg_data_type_add(target, &(std_types[i])); + } + + /* Fields related to target descriptions */ + INIT_LIST_HEAD(&arc->core_reg_descriptions); + INIT_LIST_HEAD(&arc->aux_reg_descriptions); + INIT_LIST_HEAD(&arc->bcr_reg_descriptions); + arc->num_regs = 0; + arc->num_core_regs = 0; + arc->num_aux_regs = 0; + arc->num_bcr_regs = 0; + arc->last_general_reg = ULONG_MAX; + arc->pc_index_in_cache = ULONG_MAX; + arc->debug_index_in_cache = ULONG_MAX; + + return ERROR_OK; +} + +int arc_reg_add(struct target *target, struct arc_reg_desc *arc_reg, + const char * const type_name, const size_t type_name_len) +{ + assert(target); + assert(arc_reg); + + struct arc_common *arc = target_to_arc(target); + assert(arc); + + /* Find register type */ + { + struct arc_reg_data_type *type; + list_for_each_entry(type, &arc->reg_data_types, list) + if (!strncmp(type->data_type.id, type_name, type_name_len)) { + arc_reg->data_type = &(type->data_type); + break; + } + + if (!arc_reg->data_type) + return ERROR_ARC_REGTYPE_NOT_FOUND; + } + + if (arc_reg->is_core) { + list_add_tail(&arc_reg->list, &arc->core_reg_descriptions); + arc->num_core_regs += 1; + } else if (arc_reg->is_bcr) { + list_add_tail(&arc_reg->list, &arc->bcr_reg_descriptions); + arc->num_bcr_regs += 1; + } else { + list_add_tail(&arc_reg->list, &arc->aux_reg_descriptions); + arc->num_aux_regs += 1; + } + arc->num_regs += 1; + + LOG_DEBUG( + "added register {name=%s, num=0x%x, type=%s%s%s%s}", + arc_reg->name, arc_reg->arch_num, arc_reg->data_type->id, + arc_reg->is_core ? ", core" : "", arc_reg->is_bcr ? ", bcr" : "", + arc_reg->is_general ? ", general" : "" + ); + + return ERROR_OK; +} + +/* Reading core or aux register */ +static int arc_get_register(struct reg *reg) +{ + assert(reg); + + struct arc_reg_desc *desc = reg->arch_info; + struct target *target = desc->target; + struct arc_common *arc = target_to_arc(target); + + uint32_t value; + + if (reg->valid) { + LOG_DEBUG("Get register (cached) gdb_num=%" PRIu32 ", name=%s, value=0x%" PRIx32, + reg->number, desc->name, target_buffer_get_u32(target, reg->value)); + return ERROR_OK; + } + + if (desc->is_core) { + /* Accessing to R61/R62 registers causes Jtag hang */ + if (desc->arch_num == CORE_R61_NUM || desc->arch_num == CORE_R62_NUM) { + LOG_ERROR("It is forbidden to read core registers 61 and 62."); + return ERROR_FAIL; + } + CHECK_RETVAL(arc_jtag_read_core_reg_one(&arc->jtag_info, desc->arch_num, + &value)); + } else { + CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, desc->arch_num, + &value)); + } + + target_buffer_set_u32(target, reg->value, value); + + /* If target is unhalted all register reads should be uncached. */ + if (target->state == TARGET_HALTED) + reg->valid = true; + else + reg->valid = false; + + reg->dirty = false; + + LOG_DEBUG("Get register gdb_num=%" PRIu32 ", name=%s, value=0x%" PRIx32, + reg->number , desc->name, value); + + + return ERROR_OK; +} + +/* Writing core or aux register */ +static int arc_set_register(struct reg *reg, uint8_t *buf) +{ + struct arc_reg_desc *desc = reg->arch_info; + struct target *target = desc->target; + uint32_t value = target_buffer_get_u32(target, buf); + /* Unlike "get" function "set" is supported only if target + * is in halt mode. Async writes are not supported yet. */ + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + /* Accessing to R61/R62 registers causes Jtag hang */ + if (desc->is_core && (desc->arch_num == CORE_R61_NUM || + desc->arch_num == CORE_R62_NUM)) { + LOG_ERROR("It is forbidden to write core registers 61 and 62."); + return ERROR_FAIL; + } + target_buffer_set_u32(target, reg->value, value); + + LOG_DEBUG("Set register gdb_num=%" PRIu32 ", name=%s, value=0x%08" PRIx32, + reg->number, desc->name, value); + + reg->valid = true; + reg->dirty = true; + + return ERROR_OK; +} + +const struct reg_arch_type arc_reg_type = { + .get = arc_get_register, + .set = arc_set_register, +}; + +/* GDB register groups. For now we suport only general and "empty" */ +static const char * const reg_group_general = "general"; +static const char * const reg_group_other = ""; + +/* Common code to initialize `struct reg` for different registers: core, aux, bcr. */ +static int arc_init_reg(struct target *target, struct reg *reg, + struct arc_reg_desc *reg_desc, unsigned long number) +{ + assert(target); + assert(reg); + assert(reg_desc); + + struct arc_common *arc = target_to_arc(target); + + /* Initialize struct reg */ + reg->name = reg_desc->name; + reg->size = 32; /* All register in ARC are 32-bit */ + reg->value = ®_desc->reg_value; + reg->type = &arc_reg_type; + reg->arch_info = reg_desc; + reg->caller_save = true; /* @todo should be configurable. */ + reg->reg_data_type = reg_desc->data_type; + reg->feature = ®_desc->feature; + + reg->feature->name = reg_desc->gdb_xml_feature; + + /* reg->number is used by OpenOCD as value for @regnum. Thus when setting + * value of a register GDB will use it as a number of register in + * P-packet. OpenOCD gdbserver will then use number of register in + * P-packet as an array index in the reg_list returned by + * arc_regs_get_gdb_reg_list. So to ensure that registers are assigned + * correctly it would be required to either sort registers in + * arc_regs_get_gdb_reg_list or to assign numbers sequentially here and + * according to how registers will be sorted in + * arc_regs_get_gdb_reg_list. Second options is much more simpler. */ + reg->number = number; + + if (reg_desc->is_general) { + arc->last_general_reg = reg->number; + reg->group = reg_group_general; + } else { + reg->group = reg_group_other; + } + + return ERROR_OK; +} + +/* Building aux/core reg_cache */ +static int arc_build_reg_cache(struct target *target) +{ + unsigned long i = 0; + struct arc_reg_desc *reg_desc; + /* get pointers to arch-specific information */ + struct arc_common *arc = target_to_arc(target); + const unsigned long num_regs = arc->num_core_regs + arc->num_aux_regs; + struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); + struct reg_cache *cache = calloc(1, sizeof(*cache)); + struct reg *reg_list = calloc(num_regs, sizeof(*reg_list)); + + if (!cache || !reg_list) { + LOG_ERROR("Not enough memory"); + goto fail; + } + + /* Build the process context cache */ + cache->name = "arc registers"; + cache->next = NULL; + cache->reg_list = reg_list; + cache->num_regs = num_regs; + arc->core_and_aux_cache = cache; + (*cache_p) = cache; + + if (list_empty(&arc->core_reg_descriptions)) { + LOG_ERROR("No core registers were defined"); + goto fail; + } + + list_for_each_entry(reg_desc, &arc->core_reg_descriptions, list) { + CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, i)); + + LOG_DEBUG("reg n=%3li name=%3s group=%s feature=%s", i, + reg_list[i].name, reg_list[i].group, + reg_list[i].feature->name); + + i += 1; + } + + if (list_empty(&arc->aux_reg_descriptions)) { + LOG_ERROR("No aux registers were defined"); + goto fail; + } + + list_for_each_entry(reg_desc, &arc->aux_reg_descriptions, list) { + CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, i)); + + LOG_DEBUG("reg n=%3li name=%3s group=%s feature=%s", i, + reg_list[i].name, reg_list[i].group, + reg_list[i].feature->name); + + /* PC and DEBUG are essential so we search for them. */ + if (!strcmp("pc", reg_desc->name)) { + if (arc->pc_index_in_cache != ULONG_MAX) { + LOG_ERROR("Double definition of PC in configuration"); + goto fail; + } + arc->pc_index_in_cache = i; + } else if (!strcmp("debug", reg_desc->name)) { + if (arc->debug_index_in_cache != ULONG_MAX) { + LOG_ERROR("Double definition of DEBUG in configuration"); + goto fail; + } + arc->debug_index_in_cache = i; + } + i += 1; + } + + if (arc->pc_index_in_cache == ULONG_MAX + || arc->debug_index_in_cache == ULONG_MAX) { + LOG_ERROR("`pc' and `debug' registers must be present in target description."); + goto fail; + } + + assert(i == (arc->num_core_regs + arc->num_aux_regs)); + + arc->core_aux_cache_built = true; + + return ERROR_OK; + +fail: + free(cache); + free(reg_list); + + return ERROR_FAIL; +} + +/* Build bcr reg_cache. + * This function must be called only after arc_build_reg_cache */ +static int arc_build_bcr_reg_cache(struct target *target) +{ + /* get pointers to arch-specific information */ + struct arc_common *arc = target_to_arc(target); + const unsigned long num_regs = arc->num_bcr_regs; + struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); + struct reg_cache *cache = malloc(sizeof(*cache)); + struct reg *reg_list = calloc(num_regs, sizeof(*reg_list)); + + struct arc_reg_desc *reg_desc; + unsigned long i = 0; + unsigned long gdb_regnum = arc->core_and_aux_cache->num_regs; + + if (!cache || !reg_list) { + LOG_ERROR("Unable to allocate memory"); + goto fail; + } + + /* Build the process context cache */ + cache->name = "arc.bcr"; + cache->next = NULL; + cache->reg_list = reg_list; + cache->num_regs = num_regs; + arc->bcr_cache = cache; + (*cache_p) = cache; + + if (list_empty(&arc->bcr_reg_descriptions)) { + LOG_ERROR("No BCR registers are defined"); + goto fail; + } + + list_for_each_entry(reg_desc, &arc->bcr_reg_descriptions, list) { + CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, gdb_regnum)); + /* BCRs always semantically, they are just read-as-zero, if there is + * not real register. */ + reg_list[i].exist = true; + + LOG_DEBUG("reg n=%3li name=%3s group=%s feature=%s", i, + reg_list[i].name, reg_list[i].group, + reg_list[i].feature->name); + i += 1; + gdb_regnum += 1; + } + + assert(i == arc->num_bcr_regs); + + arc->bcr_cache_built = true; + + + return ERROR_OK; +fail: + free(cache); + free(reg_list); + + return ERROR_FAIL; +} + + +static int arc_get_gdb_reg_list(struct target *target, struct reg **reg_list[], + int *reg_list_size, enum target_register_class reg_class) +{ + assert(target->reg_cache); + struct arc_common *arc = target_to_arc(target); + + /* get pointers to arch-specific information storage */ + *reg_list_size = arc->num_regs; + *reg_list = calloc(*reg_list_size, sizeof(struct reg *)); + + if (!*reg_list) { + LOG_ERROR("Unable to allocate memory"); + return ERROR_FAIL; + } + + /* OpenOCD gdb_server API seems to be inconsistent here: when it generates + * XML tdesc it filters out !exist registers, however when creating a + * g-packet it doesn't do so. REG_CLASS_ALL is used in first case, and + * REG_CLASS_GENERAL used in the latter one. Due to this we had to filter + * out !exist register for "general", but not for "all". Attempts to filter out + * !exist for "all" as well will cause a failed check in OpenOCD GDB + * server. */ + if (reg_class == REG_CLASS_ALL) { + unsigned long i = 0; + struct reg_cache *reg_cache = target->reg_cache; + while (reg_cache) { + for (unsigned j = 0; j < reg_cache->num_regs; j++, i++) + (*reg_list)[i] = ®_cache->reg_list[j]; + reg_cache = reg_cache->next; + } + assert(i == arc->num_regs); + LOG_DEBUG("REG_CLASS_ALL: number of regs=%i", *reg_list_size); + } else { + unsigned long i = 0; + unsigned long gdb_reg_number = 0; + struct reg_cache *reg_cache = target->reg_cache; + while (reg_cache) { + for (unsigned j = 0; + j < reg_cache->num_regs && gdb_reg_number <= arc->last_general_reg; + j++) { + if (reg_cache->reg_list[j].exist) { + (*reg_list)[i] = ®_cache->reg_list[j]; + i++; + } + gdb_reg_number += 1; + } + reg_cache = reg_cache->next; + } + *reg_list_size = i; + LOG_DEBUG("REG_CLASS_GENERAL: number of regs=%i", *reg_list_size); + } + + return ERROR_OK; +} + +/* Reading field of struct_type register */ +int arc_reg_get_field(struct target *target, const char *reg_name, + const char *field_name, uint32_t *value_ptr) +{ + struct reg_data_type_struct_field *field; + + LOG_DEBUG("getting register field (reg_name=%s, field_name=%s)", reg_name, field_name); + + /* Get register */ + struct reg *reg = arc_reg_get_by_name(target->reg_cache, reg_name, true); + + if (!reg) { + LOG_ERROR("Requested register `%s' doens't exist.", reg_name); + return ERROR_ARC_REGISTER_NOT_FOUND; + } + + if (reg->reg_data_type->type != REG_TYPE_ARCH_DEFINED + || reg->reg_data_type->type_class != REG_TYPE_CLASS_STRUCT) + return ERROR_ARC_REGISTER_IS_NOT_STRUCT; + + /* Get field in a register */ + struct reg_data_type_struct *reg_struct = + reg->reg_data_type->reg_type_struct; + for (field = reg_struct->fields; + field; + field = field->next) { + if (!strcmp(field->name, field_name)) + break; + } + + if (!field) + return ERROR_ARC_REGISTER_FIELD_NOT_FOUND; + + if (!field->use_bitfields) + return ERROR_ARC_FIELD_IS_NOT_BITFIELD; + + if (!reg->valid) + CHECK_RETVAL(reg->type->get(reg)); + + /* First do endiannes-safe read of register value + * then convert it to binary buffer for further + * field extraction */ + + *value_ptr = buf_get_u32(reg->value, field->bitfield->start, + field->bitfield->end - field->bitfield->start + 1); + + return ERROR_OK; +} + +static int arc_get_register_value(struct target *target, const char *reg_name, + uint32_t *value_ptr) +{ + LOG_DEBUG("reg_name=%s", reg_name); + + struct reg *reg = arc_reg_get_by_name(target->reg_cache, reg_name, true); + + if (!reg) + return ERROR_ARC_REGISTER_NOT_FOUND; + + if (!reg->valid) + CHECK_RETVAL(reg->type->get(reg)); + + *value_ptr = target_buffer_get_u32(target, reg->value); + + return ERROR_OK; +} + + +/* Configure DCCM's */ +static int arc_configure_dccm(struct target *target) +{ + struct arc_common *arc = target_to_arc(target); + + uint32_t dccm_build_version, dccm_build_size0, dccm_build_size1; + CHECK_RETVAL(arc_reg_get_field(target, "dccm_build", "version", + &dccm_build_version)); + CHECK_RETVAL(arc_reg_get_field(target, "dccm_build", "size0", + &dccm_build_size0)); + CHECK_RETVAL(arc_reg_get_field(target, "dccm_build", "size1", + &dccm_build_size1)); + /* There is no yet support of configurable number of cycles, + * So there is no difference between v3 and v4 */ + if ((dccm_build_version == 3 || dccm_build_version == 4) && dccm_build_size0 > 0) { + CHECK_RETVAL(arc_get_register_value(target, "aux_dccm", &(arc->dccm_start))); + uint32_t dccm_size = 0x100; + dccm_size <<= dccm_build_size0; + if (dccm_build_size0 == 0xF) + dccm_size <<= dccm_build_size1; + arc->dccm_end = arc->dccm_start + dccm_size; + LOG_DEBUG("DCCM detected start=0x%" PRIx32 " end=0x%" PRIx32, + arc->dccm_start, arc->dccm_end); + + } + return ERROR_OK; +} + + +/* Configure ICCM's */ + +static int arc_configure_iccm(struct target *target) +{ + struct arc_common *arc = target_to_arc(target); + + /* ICCM0 */ + uint32_t iccm_build_version, iccm_build_size00, iccm_build_size01; + uint32_t aux_iccm = 0; + CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "version", + &iccm_build_version)); + CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "iccm0_size0", + &iccm_build_size00)); + CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "iccm0_size1", + &iccm_build_size01)); + if (iccm_build_version == 4 && iccm_build_size00 > 0) { + CHECK_RETVAL(arc_get_register_value(target, "aux_iccm", &aux_iccm)); + uint32_t iccm0_size = 0x100; + iccm0_size <<= iccm_build_size00; + if (iccm_build_size00 == 0xF) + iccm0_size <<= iccm_build_size01; + /* iccm0 start is located in highest 4 bits of aux_iccm */ + arc->iccm0_start = aux_iccm & 0xF0000000; + arc->iccm0_end = arc->iccm0_start + iccm0_size; + LOG_DEBUG("ICCM0 detected start=0x%" PRIx32 " end=0x%" PRIx32, + arc->iccm0_start, arc->iccm0_end); + } + + /* ICCM1 */ + uint32_t iccm_build_size10, iccm_build_size11; + CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "iccm1_size0", + &iccm_build_size10)); + CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "iccm1_size1", + &iccm_build_size11)); + if (iccm_build_version == 4 && iccm_build_size10 > 0) { + /* Use value read for ICCM0 */ + if (!aux_iccm) + CHECK_RETVAL(arc_get_register_value(target, "aux_iccm", &aux_iccm)); + uint32_t iccm1_size = 0x100; + iccm1_size <<= iccm_build_size10; + if (iccm_build_size10 == 0xF) + iccm1_size <<= iccm_build_size11; + arc->iccm1_start = aux_iccm & 0x0F000000; + arc->iccm1_end = arc->iccm1_start + iccm1_size; + LOG_DEBUG("ICCM1 detected start=0x%" PRIx32 " end=0x%" PRIx32, + arc->iccm1_start, arc->iccm1_end); + } + return ERROR_OK; +} + +/* Configure some core features, depending on BCRs. */ +static int arc_configure(struct target *target) +{ + LOG_DEBUG("Configuring ARC ICCM and DCCM"); + + /* Configuring DCCM if DCCM_BUILD and AUX_DCCM are known registers. */ + if (arc_reg_get_by_name(target->reg_cache, "dccm_build", true) && + arc_reg_get_by_name(target->reg_cache, "aux_dccm", true)) + CHECK_RETVAL(arc_configure_dccm(target)); + + /* Configuring ICCM if ICCM_BUILD and AUX_ICCM are known registers. */ + if (arc_reg_get_by_name(target->reg_cache, "iccm_build", true) && + arc_reg_get_by_name(target->reg_cache, "aux_iccm", true)) + CHECK_RETVAL(arc_configure_iccm(target)); + + return ERROR_OK; +} + +/* arc_examine is function, which is used for all arc targets*/ +static int arc_examine(struct target *target) +{ + uint32_t status; + struct arc_common *arc = target_to_arc(target); + + CHECK_RETVAL(arc_jtag_startup(&arc->jtag_info)); + + if (!target_was_examined(target)) { + CHECK_RETVAL(arc_jtag_status(&arc->jtag_info, &status)); + if (status & ARC_JTAG_STAT_RU) + target->state = TARGET_RUNNING; + else + target->state = TARGET_HALTED; + + /* Read BCRs and configure optional registers. */ + CHECK_RETVAL(arc_configure(target)); + + target_set_examined(target); + } + + return ERROR_OK; +} + +static int arc_halt(struct target *target) +{ + uint32_t value, irq_state; + struct arc_common *arc = target_to_arc(target); + + LOG_DEBUG("target->state: %s", target_state_name(target)); + + if (target->state == TARGET_HALTED) { + LOG_DEBUG("target was already halted"); + return ERROR_OK; + } + + if (target->state == TARGET_UNKNOWN) + LOG_WARNING("target was in unknown state when halt was requested"); + + if (target->state == TARGET_RESET) { + if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) { + LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST"); + return ERROR_TARGET_FAILURE; + } else { + target->debug_reason = DBG_REASON_DBGRQ; + } + } + + /* Break (stop) processor. + * Do read-modify-write sequence, or DEBUG.UB will be reset unintentionally. + * We do not use here arc_get/set_core_reg functions here because they imply + * that the processor is already halted. */ + CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, &value)); + value |= SET_CORE_FORCE_HALT; /* set the HALT bit */ + CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, value)); + alive_sleep(1); + + /* Save current IRQ state */ + CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &irq_state)); + + if (irq_state & AUX_STATUS32_REG_IE_BIT) + arc->irq_state = 1; + else + arc->irq_state = 0; + + /* update state and notify gdb*/ + target->state = TARGET_HALTED; + CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); + + /* some more debug information */ + if (debug_level >= LOG_LVL_DEBUG) { + LOG_DEBUG("core stopped (halted) DEGUB-REG: 0x%08" PRIx32, value); + CHECK_RETVAL(arc_get_register_value(target, "status32", &value)); + LOG_DEBUG("core STATUS32: 0x%08" PRIx32, value); + } + + return ERROR_OK; +} + +/** + * Read registers that are used in GDB g-packet. We don't read them one-by-one, + * but do that in one batch operation to improve speed. Calls to JTAG layer are + * expensive so it is better to make one big call that reads all necessary + * registers, instead of many calls, one for one register. + */ +static int arc_save_context(struct target *target) +{ + int retval = ERROR_OK; + unsigned int i; + struct arc_common *arc = target_to_arc(target); + struct reg *reg_list = arc->core_and_aux_cache->reg_list; + + LOG_DEBUG("Saving aux and core registers values"); + assert(reg_list); + + /* It is assumed that there is at least one AUX register in the list, for + * example PC. */ + const uint32_t core_regs_size = arc->num_core_regs * sizeof(uint32_t); + /* last_general_reg is inclusive number. To get count of registers it is + * required to do +1. */ + const uint32_t regs_to_scan = + MIN(arc->last_general_reg + 1, arc->num_regs); + const uint32_t aux_regs_size = arc->num_aux_regs * sizeof(uint32_t); + uint32_t *core_values = malloc(core_regs_size); + uint32_t *aux_values = malloc(aux_regs_size); + uint32_t *core_addrs = malloc(core_regs_size); + uint32_t *aux_addrs = malloc(aux_regs_size); + unsigned int core_cnt = 0; + unsigned int aux_cnt = 0; + + if (!core_values || !core_addrs || !aux_values || !aux_addrs) { + LOG_ERROR("Unable to allocate memory"); + retval = ERROR_FAIL; + goto exit; + } + + memset(core_values, 0xff, core_regs_size); + memset(core_addrs, 0xff, core_regs_size); + memset(aux_values, 0xff, aux_regs_size); + memset(aux_addrs, 0xff, aux_regs_size); + + for (i = 0; i < MIN(arc->num_core_regs, regs_to_scan); i++) { + struct reg *reg = &(reg_list[i]); + struct arc_reg_desc *arc_reg = reg->arch_info; + if (!reg->valid && reg->exist) { + core_addrs[core_cnt] = arc_reg->arch_num; + core_cnt += 1; + } + } + + for (i = arc->num_core_regs; i < regs_to_scan; i++) { + struct reg *reg = &(reg_list[i]); + struct arc_reg_desc *arc_reg = reg->arch_info; + if (!reg->valid && reg->exist) { + aux_addrs[aux_cnt] = arc_reg->arch_num; + aux_cnt += 1; + } + } + + /* Read data from target. */ + if (core_cnt > 0) { + retval = arc_jtag_read_core_reg(&arc->jtag_info, core_addrs, core_cnt, core_values); + if (ERROR_OK != retval) { + LOG_ERROR("Attempt to read core registers failed."); + retval = ERROR_FAIL; + goto exit; + } + } + if (aux_cnt > 0) { + retval = arc_jtag_read_aux_reg(&arc->jtag_info, aux_addrs, aux_cnt, aux_values); + if (ERROR_OK != retval) { + LOG_ERROR("Attempt to read aux registers failed."); + retval = ERROR_FAIL; + goto exit; + } + } + + /* Parse core regs */ + core_cnt = 0; + for (i = 0; i < MIN(arc->num_core_regs, regs_to_scan); i++) { + struct reg *reg = &(reg_list[i]); + struct arc_reg_desc *arc_reg = reg->arch_info; + if (!reg->valid && reg->exist) { + target_buffer_set_u32(target, reg->value, core_values[core_cnt]); + core_cnt += 1; + reg->valid = true; + reg->dirty = false; + LOG_DEBUG("Get core register regnum=%" PRIu32 ", name=%s, value=0x%08" PRIx32, + i, arc_reg->name, core_values[core_cnt]); + } + } + + /* Parse aux regs */ + aux_cnt = 0; + for (i = arc->num_core_regs; i < regs_to_scan; i++) { + struct reg *reg = &(reg_list[i]); + struct arc_reg_desc *arc_reg = reg->arch_info; + if (!reg->valid && reg->exist) { + target_buffer_set_u32(target, reg->value, aux_values[aux_cnt]); + aux_cnt += 1; + reg->valid = true; + reg->dirty = false; + LOG_DEBUG("Get aux register regnum=%" PRIu32 ", name=%s, value=0x%08" PRIx32, + i , arc_reg->name, aux_values[aux_cnt]); + } + } + +exit: + free(core_values); + free(core_addrs); + free(aux_values); + free(aux_addrs); + + return retval; +} + +static int arc_examine_debug_reason(struct target *target) +{ + uint32_t debug_bh; + + /* Only check for reason if don't know it already. */ + /* BTW After singlestep at this point core is not marked as halted, so + * reading from memory to get current instruction wouldn't work anyway. */ + if (target->debug_reason == DBG_REASON_DBGRQ || + target->debug_reason == DBG_REASON_SINGLESTEP) { + return ERROR_OK; + } + + CHECK_RETVAL(arc_reg_get_field(target, "debug", "bh", + &debug_bh)); + + if (debug_bh) { + /* DEBUG.BH is set if core halted due to BRK instruction. */ + target->debug_reason = DBG_REASON_BREAKPOINT; + } else { + /* TODO: Add Actionpoint check when AP support will be introduced*/ + LOG_WARNING("Unknown debug reason"); + } + + return ERROR_OK; +} + +static int arc_debug_entry(struct target *target) +{ + CHECK_RETVAL(arc_save_context(target)); + + /* TODO: reset internal indicators of caches states, otherwise D$/I$ + * will not be flushed/invalidated when required. */ + CHECK_RETVAL(arc_examine_debug_reason(target)); + + return ERROR_OK; +} + +static int arc_poll(struct target *target) +{ + uint32_t status, value; + struct arc_common *arc = target_to_arc(target); + + /* gdb calls continuously through this arc_poll() function */ + CHECK_RETVAL(arc_jtag_status(&arc->jtag_info, &status)); + + /* check for processor halted */ + if (status & ARC_JTAG_STAT_RU) { + if (target->state != TARGET_RUNNING) { + LOG_WARNING("target is still running!"); + target->state = TARGET_RUNNING; + } + return ERROR_OK; + } + /* In some cases JTAG status register indicates that + * processor is in halt mode, but processor is still running. + * We check halt bit of AUX STATUS32 register for setting correct state. */ + if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) { + CHECK_RETVAL(arc_get_register_value(target, "status32", &value)); + if (value & AUX_STATUS32_REG_HALT_BIT) { + LOG_DEBUG("ARC core in halt or reset state."); + /* Save context if target was not in reset state */ + if (target->state == TARGET_RUNNING) + CHECK_RETVAL(arc_debug_entry(target)); + target->state = TARGET_HALTED; + CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); + } else { + LOG_DEBUG("Discrepancy of STATUS32[0] HALT bit and ARC_JTAG_STAT_RU, " + "target is still running"); + } + + } else if (target->state == TARGET_DEBUG_RUNNING) { + + target->state = TARGET_HALTED; + LOG_DEBUG("ARC core is in debug running mode"); + + CHECK_RETVAL(arc_debug_entry(target)); + + CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED)); + } + + return ERROR_OK; +} + +static int arc_assert_reset(struct target *target) +{ + struct arc_common *arc = target_to_arc(target); + enum reset_types jtag_reset_config = jtag_get_reset_config(); + bool srst_asserted = false; + + LOG_DEBUG("target->state: %s", target_state_name(target)); + + if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) { + /* allow scripts to override the reset event */ + + target_handle_event(target, TARGET_EVENT_RESET_ASSERT); + register_cache_invalidate(arc->core_and_aux_cache); + /* An ARC target might be in halt state after reset, so + * if script requested processor to resume, then it must + * be manually started to ensure that this request + * is satisfied. */ + if (target->state == TARGET_HALTED && !target->reset_halt) { + /* Resume the target and continue from the current + * PC register value. */ + LOG_DEBUG("Starting CPU execution after reset"); + CHECK_RETVAL(target_resume(target, 1, 0, 0, 0)); + } + target->state = TARGET_RESET; + + return ERROR_OK; + } + + /* some cores support connecting while srst is asserted + * use that mode if it has been configured */ + if (!(jtag_reset_config & RESET_SRST_PULLS_TRST) && + (jtag_reset_config & RESET_SRST_NO_GATING)) { + jtag_add_reset(0, 1); + srst_asserted = true; + } + + if (jtag_reset_config & RESET_HAS_SRST) { + /* should issue a srst only, but we may have to assert trst as well */ + if (jtag_reset_config & RESET_SRST_PULLS_TRST) + jtag_add_reset(1, 1); + else if (!srst_asserted) + jtag_add_reset(0, 1); + } + + target->state = TARGET_RESET; + jtag_add_sleep(50000); + + register_cache_invalidate(arc->core_and_aux_cache); + + if (target->reset_halt) + CHECK_RETVAL(target_halt(target)); + + return ERROR_OK; +} + +static int arc_deassert_reset(struct target *target) +{ + LOG_DEBUG("target->state: %s", target_state_name(target)); + + /* deassert reset lines */ + jtag_add_reset(0, 0); + + return ERROR_OK; +} + +static int arc_arch_state(struct target *target) +{ + uint32_t pc_value; + + if (debug_level < LOG_LVL_DEBUG) + return ERROR_OK; + + CHECK_RETVAL(arc_get_register_value(target, "pc", &pc_value)); + + LOG_DEBUG("target state: %s; PC at: 0x%08" PRIx32, + target_state_name(target), + pc_value); + + return ERROR_OK; +} + +/** + * See arc_save_context() for reason why we want to dump all regs at once. + * This however means that if there are dependencies between registers they + * will not be observable until target will be resumed. + */ +static int arc_restore_context(struct target *target) +{ + int retval = ERROR_OK; + unsigned int i; + struct arc_common *arc = target_to_arc(target); + struct reg *reg_list = arc->core_and_aux_cache->reg_list; + + LOG_DEBUG("Restoring registers values"); + assert(reg_list); + + const uint32_t core_regs_size = arc->num_core_regs * sizeof(uint32_t); + const uint32_t aux_regs_size = arc->num_aux_regs * sizeof(uint32_t); + uint32_t *core_values = malloc(core_regs_size); + uint32_t *aux_values = malloc(aux_regs_size); + uint32_t *core_addrs = malloc(core_regs_size); + uint32_t *aux_addrs = malloc(aux_regs_size); + unsigned int core_cnt = 0; + unsigned int aux_cnt = 0; + + if (!core_values || !core_addrs || !aux_values || !aux_addrs) { + LOG_ERROR("Unable to allocate memory"); + retval = ERROR_FAIL; + goto exit; + } + + memset(core_values, 0xff, core_regs_size); + memset(core_addrs, 0xff, core_regs_size); + memset(aux_values, 0xff, aux_regs_size); + memset(aux_addrs, 0xff, aux_regs_size); + + for (i = 0; i < arc->num_core_regs; i++) { + struct reg *reg = &(reg_list[i]); + struct arc_reg_desc *arc_reg = reg->arch_info; + if (reg->valid && reg->exist && reg->dirty) { + LOG_DEBUG("Will write regnum=%u", i); + core_addrs[core_cnt] = arc_reg->arch_num; + core_values[core_cnt] = target_buffer_get_u32(target, reg->value); + core_cnt += 1; + } + } + + for (i = 0; i < arc->num_aux_regs; i++) { + struct reg *reg = &(reg_list[arc->num_core_regs + i]); + struct arc_reg_desc *arc_reg = reg->arch_info; + if (reg->valid && reg->exist && reg->dirty) { + LOG_DEBUG("Will write regnum=%lu", arc->num_core_regs + i); + aux_addrs[aux_cnt] = arc_reg->arch_num; + aux_values[aux_cnt] = target_buffer_get_u32(target, reg->value); + aux_cnt += 1; + } + } + + /* Write data to target. + * Check before write, if aux and core count is greater than 0. */ + if (core_cnt > 0) { + retval = arc_jtag_write_core_reg(&arc->jtag_info, core_addrs, core_cnt, core_values); + if (ERROR_OK != retval) { + LOG_ERROR("Attempt to write to core registers failed."); + retval = ERROR_FAIL; + goto exit; + } + } + + if (aux_cnt > 0) { + retval = arc_jtag_write_aux_reg(&arc->jtag_info, aux_addrs, aux_cnt, aux_values); + if (ERROR_OK != retval) { + LOG_ERROR("Attempt to write to aux registers failed."); + retval = ERROR_FAIL; + goto exit; + } + } + +exit: + free(core_values); + free(core_addrs); + free(aux_values); + free(aux_addrs); + + return retval; +} + +static int arc_enable_interrupts(struct target *target, int enable) +{ + uint32_t value; + + struct arc_common *arc = target_to_arc(target); + + CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &value)); + + if (enable) { + /* enable interrupts */ + value |= SET_CORE_ENABLE_INTERRUPTS; + CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value)); + LOG_DEBUG("interrupts enabled"); + } else { + /* disable interrupts */ + value &= ~SET_CORE_ENABLE_INTERRUPTS; + CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value)); + LOG_DEBUG("interrupts disabled"); + } + + return ERROR_OK; +} + +static int arc_resume(struct target *target, int current, target_addr_t address, + int handle_breakpoints, int debug_execution) +{ + struct arc_common *arc = target_to_arc(target); + uint32_t resume_pc = 0; + uint32_t value; + struct reg *pc = &arc->core_and_aux_cache->reg_list[arc->pc_index_in_cache]; + + LOG_DEBUG("current:%i, address:0x%08" TARGET_PRIxADDR ", handle_breakpoints(not supported yet):%i," + " debug_execution:%i", current, address, handle_breakpoints, debug_execution); + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* current = 1: continue on current PC, otherwise continue at <address> */ + if (!current) { + target_buffer_set_u32(target, pc->value, address); + pc->dirty = 1; + pc->valid = 1; + LOG_DEBUG("Changing the value of current PC to 0x%08" TARGET_PRIxADDR, address); + } + + if (!current) + resume_pc = address; + else + resume_pc = target_buffer_get_u32(target, pc->value); + + CHECK_RETVAL(arc_restore_context(target)); + + LOG_DEBUG("Target resumes from PC=0x%" PRIx32 ", pc.dirty=%i, pc.valid=%i", + resume_pc, pc->dirty, pc->valid); + + /* check if GDB tells to set our PC where to continue from */ + if ((pc->valid == 1) && (resume_pc == target_buffer_get_u32(target, pc->value))) { + value = target_buffer_get_u32(target, pc->value); + LOG_DEBUG("resume Core (when start-core) with PC @:0x%08" PRIx32, value); + CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_PC_REG, value)); + } + + /* Restore IRQ state if not in debug_execution*/ + if (!debug_execution) + CHECK_RETVAL(arc_enable_interrupts(target, arc->irq_state)); + else + CHECK_RETVAL(arc_enable_interrupts(target, !debug_execution)); + + target->debug_reason = DBG_REASON_NOTHALTED; + + /* ready to get us going again */ + target->state = TARGET_RUNNING; + CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &value)); + value &= ~SET_CORE_HALT_BIT; /* clear the HALT bit */ + CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value)); + LOG_DEBUG("Core started to run"); + + /* registers are now invalid */ + register_cache_invalidate(arc->core_and_aux_cache); + + if (!debug_execution) { + target->state = TARGET_RUNNING; + CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED)); + LOG_DEBUG("target resumed at 0x%08" PRIx32, resume_pc); + } else { + target->state = TARGET_DEBUG_RUNNING; + CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED)); + LOG_DEBUG("target debug resumed at 0x%08" PRIx32, resume_pc); + } + + return ERROR_OK; +} + +static int arc_init_target(struct command_context *cmd_ctx, struct target *target) +{ + CHECK_RETVAL(arc_build_reg_cache(target)); + CHECK_RETVAL(arc_build_bcr_reg_cache(target)); + target->debug_reason = DBG_REASON_DBGRQ; + return ERROR_OK; +} + +static void arc_free_reg_cache(struct reg_cache *cache) +{ + free(cache->reg_list); + free(cache); +} + +static void arc_deinit_target(struct target *target) +{ + struct arc_common *arc = target_to_arc(target); + + LOG_DEBUG("deinitialization of target"); + if (arc->core_aux_cache_built) + arc_free_reg_cache(arc->core_and_aux_cache); + if (arc->bcr_cache_built) + arc_free_reg_cache(arc->bcr_cache); + + struct arc_reg_data_type *type, *n; + struct arc_reg_desc *desc, *k; + + /* Free arc-specific reg_data_types allocations*/ + list_for_each_entry_safe_reverse(type, n, &arc->reg_data_types, list) { + if (type->data_type.type_class == REG_TYPE_CLASS_STRUCT) { + free(type->reg_type_struct_field); + free(type->bitfields); + free(type); + } else if (type->data_type.type_class == REG_TYPE_CLASS_FLAGS) { + free(type->reg_type_flags_field); + free(type->bitfields); + free(type); + } + } + + /* Free standard_gdb_types reg_data_types allocations */ + type = list_first_entry(&arc->reg_data_types, struct arc_reg_data_type, list); + free(type); + + list_for_each_entry_safe(desc, k, &arc->aux_reg_descriptions, list) + free_reg_desc(desc); + + list_for_each_entry_safe(desc, k, &arc->core_reg_descriptions, list) + free_reg_desc(desc); + + list_for_each_entry_safe(desc, k, &arc->bcr_reg_descriptions, list) + free_reg_desc(desc); + + free(arc); +} + + +static int arc_target_create(struct target *target, Jim_Interp *interp) +{ + struct arc_common *arc = calloc(1, sizeof(*arc)); + + if (!arc) { + LOG_ERROR("Unable to allocate memory"); + return ERROR_FAIL; + } + + LOG_DEBUG("Entering"); + CHECK_RETVAL(arc_init_arch_info(target, arc, target->tap)); + + return ERROR_OK; +} + +/** + * Write 4-byte instruction to memory. This is like target_write_u32, however + * in case of little endian ARC instructions are in middle endian format, not + * little endian, so different type of conversion should be done. + * Middle endinan: instruction "aabbccdd", stored as "bbaaddcc" + */ +int arc_write_instruction_u32(struct target *target, uint32_t address, + uint32_t instr) +{ + uint8_t value_buf[4]; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_FAIL; + } + + LOG_DEBUG("Address: 0x%08" PRIx32 ", value: 0x%08" PRIx32, address, + instr); + + if (target->endianness == TARGET_LITTLE_ENDIAN) + arc_h_u32_to_me(value_buf, instr); + else + h_u32_to_be(value_buf, instr); + + CHECK_RETVAL(target_write_buffer(target, address, 4, value_buf)); + + return ERROR_OK; +} + +/** + * Read 32-bit instruction from memory. It is like target_read_u32, however in + * case of little endian ARC instructions are in middle endian format, so + * different type of conversion should be done. + */ +int arc_read_instruction_u32(struct target *target, uint32_t address, + uint32_t *value) +{ + uint8_t value_buf[4]; + + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_FAIL; + } + + *value = 0; + CHECK_RETVAL(target_read_buffer(target, address, 4, value_buf)); + + if (target->endianness == TARGET_LITTLE_ENDIAN) + *value = arc_me_to_h_u32(value_buf); + else + *value = be_to_h_u32(value_buf); + + LOG_DEBUG("Address: 0x%08" PRIx32 ", value: 0x%08" PRIx32, address, + *value); + + return ERROR_OK; +} + +static int arc_set_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + + if (breakpoint->set) { + LOG_WARNING("breakpoint already set"); + return ERROR_OK; + } + + if (breakpoint->type == BKPT_SOFT) { + LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); + + if (breakpoint->length == 4) { + uint32_t verify = 0xffffffff; + + CHECK_RETVAL(target_read_buffer(target, breakpoint->address, breakpoint->length, + breakpoint->orig_instr)); + + CHECK_RETVAL(arc_write_instruction_u32(target, breakpoint->address, + ARC_SDBBP_32)); + + CHECK_RETVAL(arc_read_instruction_u32(target, breakpoint->address, &verify)); + + if (verify != ARC_SDBBP_32) { + LOG_ERROR("Unable to set 32bit breakpoint at address @0x%" TARGET_PRIxADDR + " - check that memory is read/writable", breakpoint->address); + return ERROR_FAIL; + } + } else if (breakpoint->length == 2) { + uint16_t verify = 0xffff; + + CHECK_RETVAL(target_read_buffer(target, breakpoint->address, breakpoint->length, + breakpoint->orig_instr)); + CHECK_RETVAL(target_write_u16(target, breakpoint->address, ARC_SDBBP_16)); + + CHECK_RETVAL(target_read_u16(target, breakpoint->address, &verify)); + if (verify != ARC_SDBBP_16) { + LOG_ERROR("Unable to set 16bit breakpoint at address @0x%" TARGET_PRIxADDR + " - check that memory is read/writable", breakpoint->address); + return ERROR_FAIL; + } + } else { + LOG_ERROR("Invalid breakpoint length: target supports only 2 or 4"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + breakpoint->set = 64; /* Any nice value but 0 */ + } else if (breakpoint->type == BKPT_HARD) { + LOG_DEBUG("Hardware breakpoints are not supported yet!"); + return ERROR_FAIL; + } else { + LOG_DEBUG("ERROR: setting unknown breakpoint type"); + return ERROR_FAIL; + } + /* core instruction cache is now invalid, + * TODO: add cache invalidation function here (when implemented). */ + + return ERROR_OK; +} + +static int arc_unset_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + int retval = ERROR_OK; + + if (!breakpoint->set) { + LOG_WARNING("breakpoint not set"); + return ERROR_OK; + } + + if (breakpoint->type == BKPT_SOFT) { + /* restore original instruction (kept in target endianness) */ + LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); + if (breakpoint->length == 4) { + uint32_t current_instr; + + /* check that user program has not modified breakpoint instruction */ + CHECK_RETVAL(arc_read_instruction_u32(target, breakpoint->address, ¤t_instr)); + + if (current_instr == ARC_SDBBP_32) { + retval = target_write_buffer(target, breakpoint->address, + breakpoint->length, breakpoint->orig_instr); + if (retval != ERROR_OK) + return retval; + } else { + LOG_WARNING("Software breakpoint @0x%" TARGET_PRIxADDR + " has been overwritten outside of debugger." + "Expected: @0x%" PRIx32 ", got: @0x%" PRIx32, + breakpoint->address, ARC_SDBBP_32, current_instr); + } + } else if (breakpoint->length == 2) { + uint16_t current_instr; + + /* check that user program has not modified breakpoint instruction */ + CHECK_RETVAL(target_read_u16(target, breakpoint->address, ¤t_instr)); + if (current_instr == ARC_SDBBP_16) { + retval = target_write_buffer(target, breakpoint->address, + breakpoint->length, breakpoint->orig_instr); + if (retval != ERROR_OK) + return retval; + } else { + LOG_WARNING("Software breakpoint @0x%" TARGET_PRIxADDR + " has been overwritten outside of debugger. " + "Expected: 0x%04x, got: 0x%04" PRIx16, + breakpoint->address, ARC_SDBBP_16, current_instr); + } + } else { + LOG_ERROR("Invalid breakpoint length: target supports only 2 or 4"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + breakpoint->set = 0; + + } else if (breakpoint->type == BKPT_HARD) { + LOG_WARNING("Hardware breakpoints are not supported yet!"); + return ERROR_FAIL; + } else { + LOG_DEBUG("ERROR: unsetting unknown breakpoint type"); + return ERROR_FAIL; + } + + /* core instruction cache is now invalid. + * TODO: Add cache invalidation function */ + + return retval; +} + + +static int arc_add_breakpoint(struct target *target, struct breakpoint *breakpoint) +{ + if (target->state == TARGET_HALTED) { + return arc_set_breakpoint(target, breakpoint); + + } else { + LOG_WARNING(" > core was not halted, please try again."); + return ERROR_TARGET_NOT_HALTED; + } +} + +static int arc_remove_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + if (target->state == TARGET_HALTED) { + if (breakpoint->set) + CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint)); + } else { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + return ERROR_OK; +} + +/* Helper function which swiches core to single_step mode by + * doing aux r/w operations. */ +int arc_config_step(struct target *target, int enable_step) +{ + uint32_t value; + + struct arc_common *arc = target_to_arc(target); + + /* enable core debug step mode */ + if (enable_step) { + CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, + &value)); + value &= ~SET_CORE_AE_BIT; /* clear the AE bit */ + CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, + value)); + LOG_DEBUG(" [status32:0x%08" PRIx32 "]", value); + + /* Doing read-modify-write, because DEBUG might contain manually set + * bits like UB or ED, which should be preserved. */ + CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, + AUX_DEBUG_REG, &value)); + value |= SET_CORE_SINGLE_INSTR_STEP; /* set the IS bit */ + CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, + value)); + LOG_DEBUG("core debug step mode enabled [debug-reg:0x%08" PRIx32 "]", value); + + } else { /* disable core debug step mode */ + CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, + &value)); + value &= ~SET_CORE_SINGLE_INSTR_STEP; /* clear the IS bit */ + CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, + value)); + LOG_DEBUG("core debug step mode disabled"); + } + + return ERROR_OK; +} + +int arc_step(struct target *target, int current, target_addr_t address, + int handle_breakpoints) +{ + /* get pointers to arch-specific information */ + struct arc_common *arc = target_to_arc(target); + struct breakpoint *breakpoint = NULL; + struct reg *pc = &(arc->core_and_aux_cache->reg_list[arc->pc_index_in_cache]); + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* current = 1: continue on current pc, otherwise continue at <address> */ + if (!current) { + buf_set_u32(pc->value, 0, 32, address); + pc->dirty = 1; + pc->valid = 1; + } + + LOG_DEBUG("Target steps one instruction from PC=0x%" PRIx32, + buf_get_u32(pc->value, 0, 32)); + + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) { + breakpoint = breakpoint_find(target, buf_get_u32(pc->value, 0, 32)); + if (breakpoint) + CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint)); + } + + /* restore context */ + CHECK_RETVAL(arc_restore_context(target)); + + target->debug_reason = DBG_REASON_SINGLESTEP; + + CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED)); + + /* disable interrupts while stepping */ + CHECK_RETVAL(arc_enable_interrupts(target, 0)); + + /* do a single step */ + CHECK_RETVAL(arc_config_step(target, 1)); + + /* make sure we done our step */ + alive_sleep(1); + + /* registers are now invalid */ + register_cache_invalidate(arc->core_and_aux_cache); + + if (breakpoint) + CHECK_RETVAL(arc_set_breakpoint(target, breakpoint)); + + LOG_DEBUG("target stepped "); + + target->state = TARGET_HALTED; + + /* Saving context */ + CHECK_RETVAL(arc_debug_entry(target)); + CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); + + return ERROR_OK; +} + + + +/* ARC v2 target */ +struct target_type arcv2_target = { + .name = "arcv2", + + .poll = arc_poll, + + .arch_state = arc_arch_state, + + /* TODO That seems like something similiar to metaware hostlink, so perhaps + * we can exploit this in the future. */ + .target_request_data = NULL, + + .halt = arc_halt, + .resume = arc_resume, + .step = arc_step, + + .assert_reset = arc_assert_reset, + .deassert_reset = arc_deassert_reset, + + /* TODO Implement soft_reset_halt */ + .soft_reset_halt = NULL, + + .get_gdb_reg_list = arc_get_gdb_reg_list, + + .read_memory = arc_mem_read, + .write_memory = arc_mem_write, + .checksum_memory = NULL, + .blank_check_memory = NULL, + + .add_breakpoint = arc_add_breakpoint, + .add_context_breakpoint = NULL, + .add_hybrid_breakpoint = NULL, + .remove_breakpoint = arc_remove_breakpoint, + .add_watchpoint = NULL, + .remove_watchpoint = NULL, + .hit_watchpoint = NULL, + + .run_algorithm = NULL, + .start_algorithm = NULL, + .wait_algorithm = NULL, + + .commands = arc_monitor_command_handlers, + + .target_create = arc_target_create, + .init_target = arc_init_target, + .deinit_target = arc_deinit_target, + .examine = arc_examine, + + .virt2phys = NULL, + .read_phys_memory = NULL, + .write_phys_memory = NULL, + .mmu = NULL, +}; diff --git a/src/target/arc.h b/src/target/arc.h new file mode 100644 index 0000000..defa3fa --- /dev/null +++ b/src/target/arc.h @@ -0,0 +1,250 @@ +/*************************************************************************** + * Copyright (C) 2013-2015,2019-2020 Synopsys, Inc. * + * Frank Dols <frank.dols@synopsys.com> * + * Mischa Jonker <mischa.jonker@synopsys.com> * + * Anton Kolesov <anton.kolesov@synopsys.com> * + * Evgeniy Didin <didin@synopsys.com> * + * * + * SPDX-License-Identifier: GPL-2.0-or-later * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ARC_H +#define OPENOCD_TARGET_ARC_H + +#include <helper/time_support.h> +#include <jtag/jtag.h> + +#include "algorithm.h" +#include "breakpoints.h" +#include "jtag/interface.h" +#include "register.h" +#include "target.h" +#include "target_request.h" +#include "target_type.h" +#include "helper/bits.h" + +#include "arc_jtag.h" +#include "arc_cmd.h" +#include "arc_mem.h" + +#define ARC_COMMON_MAGIC 0xB32EB324 /* just a unique number */ + +#define AUX_DEBUG_REG 0x5 +#define AUX_PC_REG 0x6 +#define AUX_STATUS32_REG 0xA + + +#define SET_CORE_FORCE_HALT BIT(1) +#define SET_CORE_HALT_BIT BIT(0) /* STATUS32[0] = H field */ +#define SET_CORE_ENABLE_INTERRUPTS BIT(31) +/* STATUS32[5] or AE bit indicates if the processor is in exception state */ +#define SET_CORE_AE_BIT BIT(5) +/* Single instruction step bit in Debug register */ +#define SET_CORE_SINGLE_INSTR_STEP BIT(11) + +#define AUX_STATUS32_REG_HALT_BIT BIT(0) +#define AUX_STATUS32_REG_IE_BIT BIT(31) /* STATUS32[31] = IE field */ + +/* Reserved core registers */ +#define CORE_R61_NUM (61) +#define CORE_R62_NUM (62) + +#define CORE_REG_MAX_NUMBER (63) + +/* Limit reg_type/reg_type_field name to 20 symbols */ +#define REG_TYPE_MAX_NAME_LENGTH 20 + +/* ARC 32bits opcodes */ +#define ARC_SDBBP_32 0x256F003F /* BRK */ + +/* ARC 16bits opcodes */ +#define ARC_SDBBP_16 0x7FFF /* BRK_S */ + +struct arc_reg_bitfield { + struct reg_data_type_bitfield bitfield; + char name[REG_TYPE_MAX_NAME_LENGTH]; +}; +/* Register data type */ +struct arc_reg_data_type { + struct list_head list; + struct reg_data_type data_type; + struct reg_data_type_flags data_type_flags; + struct reg_data_type_struct data_type_struct; + char data_type_id[REG_TYPE_MAX_NAME_LENGTH]; + struct arc_reg_bitfield *bitfields; + union { + struct reg_data_type_struct_field *reg_type_struct_field; + struct reg_data_type_flags_field *reg_type_flags_field; + }; +}; + + + +/* Standard GDB register types */ +static const struct reg_data_type standard_gdb_types[] = { + { .type = REG_TYPE_INT, .id = "int" }, + { .type = REG_TYPE_INT8, .id = "int8" }, + { .type = REG_TYPE_INT16, .id = "int16" }, + { .type = REG_TYPE_INT32, .id = "int32" }, + { .type = REG_TYPE_INT64, .id = "int64" }, + { .type = REG_TYPE_INT128, .id = "int128" }, + { .type = REG_TYPE_UINT8, .id = "uint8" }, + { .type = REG_TYPE_UINT16, .id = "uint16" }, + { .type = REG_TYPE_UINT32, .id = "uint32" }, + { .type = REG_TYPE_UINT64, .id = "uint64" }, + { .type = REG_TYPE_UINT128, .id = "uint128" }, + { .type = REG_TYPE_CODE_PTR, .id = "code_ptr" }, + { .type = REG_TYPE_DATA_PTR, .id = "data_ptr" }, + { .type = REG_TYPE_FLOAT, .id = "float" }, + { .type = REG_TYPE_IEEE_SINGLE, .id = "ieee_single" }, + { .type = REG_TYPE_IEEE_DOUBLE, .id = "ieee_double" }, +}; + + +struct arc_common { + uint32_t common_magic; + + struct arc_jtag jtag_info; + + struct reg_cache *core_and_aux_cache; + struct reg_cache *bcr_cache; + + /* Indicate if cach was built (for deinit function) */ + bool core_aux_cache_built; + bool bcr_cache_built; + /* Closely Coupled memory(CCM) regions for performance-critical + * code (optional). */ + uint32_t iccm0_start; + uint32_t iccm0_end; + uint32_t iccm1_start; + uint32_t iccm1_end; + uint32_t dccm_start; + uint32_t dccm_end; + + int irq_state; + + /* Register descriptions */ + struct list_head reg_data_types; + struct list_head core_reg_descriptions; + struct list_head aux_reg_descriptions; + struct list_head bcr_reg_descriptions; + unsigned long num_regs; + unsigned long num_core_regs; + unsigned long num_aux_regs; + unsigned long num_bcr_regs; + unsigned long last_general_reg; + + /* PC register location in register cache. */ + unsigned long pc_index_in_cache; + /* DEBUG register location in register cache. */ + unsigned long debug_index_in_cache; +}; + +/* Borrowed from nds32.h */ +#define CHECK_RETVAL(action) \ + do { \ + int __retval = (action); \ + if (__retval != ERROR_OK) { \ + LOG_DEBUG("error while calling \"%s\"", \ + # action); \ + return __retval; \ + } \ + } while (0) + +#define JIM_CHECK_RETVAL(action) \ + do { \ + int __retval = (action); \ + if (__retval != JIM_OK) { \ + LOG_DEBUG("error while calling \"%s\"", \ + # action); \ + return __retval; \ + } \ + } while (0) + +static inline struct arc_common *target_to_arc(struct target *target) +{ + return target->arch_info; +} + +/* ----- Inlined functions ------------------------------------------------- */ + +/** + * Convert data in host endianness to the middle endian. This is required to + * write 4-byte instructions. + */ +static inline void arc_h_u32_to_me(uint8_t *buf, int val) +{ + buf[1] = (uint8_t) (val >> 24); + buf[0] = (uint8_t) (val >> 16); + buf[3] = (uint8_t) (val >> 8); + buf[2] = (uint8_t) (val >> 0); +} + +/** + * Convert data in middle endian to host endian. This is required to read 32-bit + * instruction from little endian ARCs. + */ +static inline uint32_t arc_me_to_h_u32(const uint8_t *buf) +{ + return (uint32_t)(buf[2] | buf[3] << 8 | buf[0] << 16 | buf[1] << 24); +} + + +/* ARC Register description */ +struct arc_reg_desc { + + struct target *target; + + /* Register name */ + char *name; + + /* Actual place of storing reg_value */ + uint8_t reg_value[4]; + + /* Actual place of storing register feature */ + struct reg_feature feature; + + /* GDB XML feature */ + char *gdb_xml_feature; + + /* Is this a register in g/G-packet? */ + bool is_general; + + /* Architectural number: core reg num or AUX reg num */ + uint32_t arch_num; + + /* Core or AUX register? */ + bool is_core; + + /* Build configuration register? */ + bool is_bcr; + + /* Data type */ + struct reg_data_type *data_type; + + struct list_head list; +}; + +/* Error codes */ +#define ERROR_ARC_REGISTER_NOT_FOUND (-700) +#define ERROR_ARC_REGISTER_FIELD_NOT_FOUND (-701) +#define ERROR_ARC_REGISTER_IS_NOT_STRUCT (-702) +#define ERROR_ARC_FIELD_IS_NOT_BITFIELD (-703) +#define ERROR_ARC_REGTYPE_NOT_FOUND (-704) + +void free_reg_desc(struct arc_reg_desc *r); + + +void arc_reg_data_type_add(struct target *target, + struct arc_reg_data_type *data_type); + +int arc_reg_add(struct target *target, struct arc_reg_desc *arc_reg, + const char * const type_name, const size_t type_name_len); + +struct reg *arc_reg_get_by_name(struct reg_cache *first, + const char *name, bool search_all); + +int arc_reg_get_field(struct target *target, const char *reg_name, + const char *field_name, uint32_t *value_ptr); + +#endif /* OPENOCD_TARGET_ARC_H */ diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c new file mode 100644 index 0000000..fad8ca9 --- /dev/null +++ b/src/target/arc_cmd.c @@ -0,0 +1,982 @@ +/*************************************************************************** + * Copyright (C) 2013-2015,2019-2020 Synopsys, Inc. * + * Frank Dols <frank.dols@synopsys.com> * + * Mischa Jonker <mischa.jonker@synopsys.com> * + * Anton Kolesov <anton.kolesov@synopsys.com> * + * Evgeniy Didin <didin@synopsys.com> * + * * + * SPDX-License-Identifier: GPL-2.0-or-later * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arc.h" + +/* -------------------------------------------------------------------------- + * + * ARC targets expose command interface. + * It can be accessed via GDB through the (gdb) monitor command. + * + * ------------------------------------------------------------------------- */ + + +static int arc_cmd_jim_get_uint32(Jim_GetOptInfo *goi, uint32_t *value) +{ + jim_wide value_wide; + JIM_CHECK_RETVAL(Jim_GetOpt_Wide(goi, &value_wide)); + *value = (uint32_t)value_wide; + return JIM_OK; +} + +enum add_reg_types { + CFG_ADD_REG_TYPE_FLAG, + CFG_ADD_REG_TYPE_STRUCT, +}; +/* Add flags register data type */ +enum add_reg_type_flags { + CFG_ADD_REG_TYPE_FLAGS_NAME, + CFG_ADD_REG_TYPE_FLAGS_FLAG, +}; + +static Jim_Nvp nvp_add_reg_type_flags_opts[] = { + { .name = "-name", .value = CFG_ADD_REG_TYPE_FLAGS_NAME }, + { .name = "-flag", .value = CFG_ADD_REG_TYPE_FLAGS_FLAG }, + { .name = NULL, .value = -1 } +}; + +/* Helper function to check if all field required for register + * are set up */ +static const char *validate_register(const struct arc_reg_desc * const reg, bool arch_num_set) +{ + /* Check that required fields are set */ + if (!reg->name) + return "-name option is required"; + if (!reg->gdb_xml_feature) + return "-feature option is required"; + if (!arch_num_set) + return "-num option is required"; + if (reg->is_bcr && reg->is_core) + return "Register cannot be both -core and -bcr."; + return NULL; +} + +/* Helper function to read the name of register type or register from + * configure files */ +static int jim_arc_read_reg_name_field(Jim_GetOptInfo *goi, + const char **name, int *name_len) +{ + int e = JIM_OK; + + if (!goi->argc) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-name <name> ..."); + return JIM_ERR; + } + e = Jim_GetOpt_String(goi, name, name_len); + return e; +} + +/* Helper function to read bitfields/flags of register type. */ +static int jim_arc_read_reg_type_field(Jim_GetOptInfo *goi, const char **field_name, int *field_name_len, + struct arc_reg_bitfield *bitfields, int cur_field, int type) +{ + jim_wide start_pos, end_pos; + + int e = JIM_OK; + if ((type == CFG_ADD_REG_TYPE_STRUCT && goi->argc < 3) || + (type == CFG_ADD_REG_TYPE_FLAG && goi->argc < 2)) { + Jim_SetResultFormatted(goi->interp, "Not enough argmunets after -flag/-bitfield"); + return JIM_ERR; + } + + e = Jim_GetOpt_String(goi, field_name, field_name_len); + if (e != JIM_OK) + return e; + + /* read start position of bitfield/flag */ + e = Jim_GetOpt_Wide(goi, &start_pos); + if (e != JIM_OK) + return e; + + end_pos = start_pos; + + /* Check if any argnuments remain, + * set bitfields[cur_field].end if flag is multibit */ + if (goi->argc > 0) + /* Check current argv[0], if it is equal to "-flag", + * than bitfields[cur_field].end remains start */ + if ((strcmp(Jim_String(goi->argv[0]), "-flag") && type == CFG_ADD_REG_TYPE_FLAG) + || (type == CFG_ADD_REG_TYPE_STRUCT)) { + e = Jim_GetOpt_Wide(goi, &end_pos); + if (e != JIM_OK) { + Jim_SetResultFormatted(goi->interp, "Error reading end position"); + return e; + } + } + + bitfields[cur_field].bitfield.start = start_pos; + bitfields[cur_field].bitfield.end = end_pos; + if ((end_pos != start_pos) || (type == CFG_ADD_REG_TYPE_STRUCT)) + bitfields[cur_field].bitfield.type = REG_TYPE_INT; + return e; +} + +static int jim_arc_add_reg_type_flags(Jim_Interp *interp, int argc, + Jim_Obj * const *argv) +{ + Jim_GetOptInfo goi; + JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1)); + + LOG_DEBUG("-"); + + struct command_context *ctx; + struct target *target; + + ctx = current_command_context(interp); + assert(ctx); + target = get_current_target(ctx); + if (!target) { + Jim_SetResultFormatted(goi.interp, "No current target"); + return JIM_ERR; + } + + int e = JIM_OK; + + /* Check if the amount of argnuments is not zero */ + if (goi.argc <= 0) { + Jim_SetResultFormatted(goi.interp, "The command has no argnuments"); + return JIM_ERR; + } + + /* Estimate number of registers as (argc - 2)/3 as each -flag option has 2 + * arguments while -name is required. */ + unsigned int fields_sz = (goi.argc - 2) / 3; + unsigned int cur_field = 0; + + /* Tha maximum amount of bitfilds is 32 */ + if (fields_sz > 32) { + Jim_SetResultFormatted(goi.interp, "The amount of bitfields exceed 32"); + return JIM_ERR; + } + + struct arc_reg_data_type *type = calloc(1, sizeof(*type)); + struct reg_data_type_flags *flags = &type->data_type_flags; + struct reg_data_type_flags_field *fields = calloc(fields_sz, sizeof(*fields)); + type->reg_type_flags_field = fields; + struct arc_reg_bitfield *bitfields = calloc(fields_sz, sizeof(*bitfields)); + if (!(type && fields && bitfields)) { + Jim_SetResultFormatted(goi.interp, "Failed to allocate memory."); + goto fail; + } + + /* Initialize type */ + type->bitfields = bitfields; + type->data_type.id = type->data_type_id; + type->data_type.type = REG_TYPE_ARCH_DEFINED; + type->data_type.type_class = REG_TYPE_CLASS_FLAGS; + type->data_type.reg_type_flags = flags; + flags->size = 4; /* For now ARC has only 32-bit registers */ + + while (goi.argc > 0 && e == JIM_OK) { + Jim_Nvp *n; + e = Jim_GetOpt_Nvp(&goi, nvp_add_reg_type_flags_opts, &n); + if (e != JIM_OK) { + Jim_GetOpt_NvpUnknown(&goi, nvp_add_reg_type_flags_opts, 0); + continue; + } + + switch (n->value) { + case CFG_ADD_REG_TYPE_FLAGS_NAME: + { + const char *name = NULL; + int name_len = 0; + + e = jim_arc_read_reg_name_field(&goi, &name, &name_len); + if (e != JIM_OK) { + Jim_SetResultFormatted(goi.interp, "Unable to read reg name."); + goto fail; + } + + if (name_len > REG_TYPE_MAX_NAME_LENGTH) { + Jim_SetResultFormatted(goi.interp, "Reg type name is too big."); + goto fail; + } + + strncpy((void *)type->data_type.id, name, name_len); + if (!type->data_type.id) { + Jim_SetResultFormatted(goi.interp, "Unable to setup reg type name."); + goto fail; + } + + break; + } + + case CFG_ADD_REG_TYPE_FLAGS_FLAG: + { + const char *field_name = NULL; + int field_name_len = 0; + + e = jim_arc_read_reg_type_field(&goi, &field_name, &field_name_len, bitfields, + cur_field, CFG_ADD_REG_TYPE_FLAG); + if (e != JIM_OK) { + Jim_SetResultFormatted(goi.interp, "Unable to add reg_type_flag field."); + goto fail; + } + + if (field_name_len > REG_TYPE_MAX_NAME_LENGTH) { + Jim_SetResultFormatted(goi.interp, "Reg type field_name_len is too big."); + goto fail; + } + + fields[cur_field].name = bitfields[cur_field].name; + strncpy(bitfields[cur_field].name, field_name, field_name_len); + if (!fields[cur_field].name) { + Jim_SetResultFormatted(goi.interp, "Unable to setup field name. "); + goto fail; + } + + fields[cur_field].bitfield = &(bitfields[cur_field].bitfield); + if (cur_field > 0) + fields[cur_field - 1].next = &(fields[cur_field]); + else + flags->fields = fields; + + cur_field += 1; + break; + } + } + } + + if (!type->data_type.id) { + Jim_SetResultFormatted(goi.interp, "-name is a required option"); + goto fail; + } + + arc_reg_data_type_add(target, type); + + LOG_DEBUG("added flags type {name=%s}", type->data_type.id); + + return JIM_OK; +fail: + free(type); + free(fields); + free(bitfields); + + return JIM_ERR; +} + +/* Add struct register data type */ +enum add_reg_type_struct { + CFG_ADD_REG_TYPE_STRUCT_NAME, + CFG_ADD_REG_TYPE_STRUCT_BITFIELD, +}; + +static Jim_Nvp nvp_add_reg_type_struct_opts[] = { + { .name = "-name", .value = CFG_ADD_REG_TYPE_STRUCT_NAME }, + { .name = "-bitfield", .value = CFG_ADD_REG_TYPE_STRUCT_BITFIELD }, + { .name = NULL, .value = -1 } +}; + +static int jim_arc_set_aux_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +{ + + struct command_context *context; + struct target *target; + uint32_t regnum; + uint32_t value; + + Jim_GetOptInfo goi; + JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1)); + + if (goi.argc != 2) { + Jim_SetResultFormatted(goi.interp, + "usage: %s <aux_reg_num> <aux_reg_value>", Jim_GetString(argv[0], NULL)); + return JIM_ERR; + } + + context = current_command_context(interp); + assert(context); + + target = get_current_target(context); + if (!target) { + Jim_SetResultFormatted(goi.interp, "No current target"); + return JIM_ERR; + } + + /* Register number */ + JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num)); + + /* Register value */ + JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &value)); + + struct arc_common *arc = target_to_arc(target); + assert(arc); + + CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, regnum, value)); + + return ERROR_OK; +} + +static int jim_arc_get_aux_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +{ + struct command_context *context; + struct target *target; + uint32_t regnum; + uint32_t value; + + Jim_GetOptInfo goi; + JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1)); + + if (goi.argc != 1) { + Jim_SetResultFormatted(goi.interp, + "usage: %s <aux_reg_num>", Jim_GetString(argv[0], NULL)); + return JIM_ERR; + } + + context = current_command_context(interp); + assert(context); + + target = get_current_target(context); + if (!target) { + Jim_SetResultFormatted(goi.interp, "No current target"); + return JIM_ERR; + } + + /* Register number */ + JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num)); + + struct arc_common *arc = target_to_arc(target); + assert(arc); + + CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, regnum, &value)); + Jim_SetResultInt(interp, value); + + return ERROR_OK; +} + +static int jim_arc_get_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +{ + struct command_context *context; + struct target *target; + uint32_t regnum; + uint32_t value; + + Jim_GetOptInfo goi; + JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1)); + + if (goi.argc != 1) { + Jim_SetResultFormatted(goi.interp, + "usage: %s <core_reg_num>", Jim_GetString(argv[0], NULL)); + return JIM_ERR; + } + + context = current_command_context(interp); + assert(context); + + target = get_current_target(context); + if (!target) { + Jim_SetResultFormatted(goi.interp, "No current target"); + return JIM_ERR; + } + + /* Register number */ + JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num)); + if (regnum > CORE_REG_MAX_NUMBER || regnum == CORE_R61_NUM || regnum == CORE_R62_NUM) { + Jim_SetResultFormatted(goi.interp, "Core register number %i " + "is invalid. Must less then 64 and not 61 and 62.", regnum); + return JIM_ERR; + } + + struct arc_common *arc = target_to_arc(target); + assert(arc); + + /* Read value */ + CHECK_RETVAL(arc_jtag_read_core_reg_one(&arc->jtag_info, regnum, &value)); + Jim_SetResultInt(interp, value); + + return ERROR_OK; +} + +static int jim_arc_set_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +{ + struct command_context *context; + struct target *target; + uint32_t regnum; + uint32_t value; + + Jim_GetOptInfo goi; + JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1)); + + if (goi.argc != 2) { + Jim_SetResultFormatted(goi.interp, + "usage: %s <core_reg_num> <core_reg_value>", Jim_GetString(argv[0], NULL)); + return JIM_ERR; + } + + context = current_command_context(interp); + assert(context); + + target = get_current_target(context); + if (!target) { + Jim_SetResultFormatted(goi.interp, "No current target"); + return JIM_ERR; + } + + /* Register number */ + JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num)); + if (regnum > CORE_REG_MAX_NUMBER || regnum == CORE_R61_NUM || regnum == CORE_R62_NUM) { + Jim_SetResultFormatted(goi.interp, "Core register number %i " + "is invalid. Must less then 64 and not 61 and 62.", regnum); + return JIM_ERR; + } + + /* Register value */ + JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &value)); + + struct arc_common *arc = target_to_arc(target); + assert(arc); + + CHECK_RETVAL(arc_jtag_write_core_reg_one(&arc->jtag_info, regnum, value)); + + return ERROR_OK; +} + +static const struct command_registration arc_jtag_command_group[] = { + { + .name = "get-aux-reg", + .jim_handler = jim_arc_get_aux_reg, + .mode = COMMAND_EXEC, + .help = "Get AUX register by number. This command does a " + "raw JTAG request that bypasses OpenOCD register cache " + "and thus is unsafe and can have unexpected consequences. " + "Use at your own risk.", + .usage = "arc jtag get-aux-reg <regnum>" + }, + { + .name = "set-aux-reg", + .jim_handler = jim_arc_set_aux_reg, + .mode = COMMAND_EXEC, + .help = "Set AUX register by number. This command does a " + "raw JTAG request that bypasses OpenOCD register cache " + "and thus is unsafe and can have unexpected consequences. " + "Use at your own risk.", + .usage = "arc jtag set-aux-reg <regnum> <value>" + }, + { + .name = "get-core-reg", + .jim_handler = jim_arc_get_core_reg, + .mode = COMMAND_EXEC, + .help = "Get/Set core register by number. This command does a " + "raw JTAG request that bypasses OpenOCD register cache " + "and thus is unsafe and can have unexpected consequences. " + "Use at your own risk.", + .usage = "arc jtag get-core-reg <regnum> [<value>]" + }, + { + .name = "set-core-reg", + .jim_handler = jim_arc_set_core_reg, + .mode = COMMAND_EXEC, + .help = "Get/Set core register by number. This command does a " + "raw JTAG request that bypasses OpenOCD register cache " + "and thus is unsafe and can have unexpected consequences. " + "Use at your own risk.", + .usage = "arc jtag set-core-reg <regnum> [<value>]" + }, + COMMAND_REGISTRATION_DONE +}; + + +/* This function supports only bitfields. */ +static int jim_arc_add_reg_type_struct(Jim_Interp *interp, int argc, + Jim_Obj * const *argv) +{ + Jim_GetOptInfo goi; + JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1)); + + LOG_DEBUG("-"); + + struct command_context *ctx; + struct target *target; + + ctx = current_command_context(interp); + assert(ctx); + target = get_current_target(ctx); + if (!target) { + Jim_SetResultFormatted(goi.interp, "No current target"); + return JIM_ERR; + } + + int e = JIM_OK; + + /* Check if the amount of argnuments is not zero */ + if (goi.argc <= 0) { + Jim_SetResultFormatted(goi.interp, "The command has no argnuments"); + return JIM_ERR; + } + + /* Estimate number of registers as (argc - 2)/4 as each -bitfield option has 3 + * arguments while -name is required. */ + unsigned int fields_sz = (goi.argc - 2) / 4; + unsigned int cur_field = 0; + + /* Tha maximum amount of bitfilds is 32 */ + if (fields_sz > 32) { + Jim_SetResultFormatted(goi.interp, "The amount of bitfields exceed 32"); + return JIM_ERR; + } + + struct arc_reg_data_type *type = calloc(1, sizeof(*type)); + struct reg_data_type_struct *struct_type = &type->data_type_struct; + struct reg_data_type_struct_field *fields = calloc(fields_sz, sizeof(*fields)); + type->reg_type_struct_field = fields; + struct arc_reg_bitfield *bitfields = calloc(fields_sz, sizeof(*bitfields)); + if (!(type && fields && bitfields)) { + Jim_SetResultFormatted(goi.interp, "Failed to allocate memory."); + goto fail; + } + + /* Initialize type */ + type->data_type.id = type->data_type_id; + type->bitfields = bitfields; + type->data_type.type = REG_TYPE_ARCH_DEFINED; + type->data_type.type_class = REG_TYPE_CLASS_STRUCT; + type->data_type.reg_type_struct = struct_type; + struct_type->size = 4; /* For now ARC has only 32-bit registers */ + + while (goi.argc > 0 && e == JIM_OK) { + Jim_Nvp *n; + e = Jim_GetOpt_Nvp(&goi, nvp_add_reg_type_struct_opts, &n); + if (e != JIM_OK) { + Jim_GetOpt_NvpUnknown(&goi, nvp_add_reg_type_struct_opts, 0); + continue; + } + + switch (n->value) { + case CFG_ADD_REG_TYPE_STRUCT_NAME: + { + const char *name = NULL; + int name_len = 0; + + e = jim_arc_read_reg_name_field(&goi, &name, &name_len); + if (e != JIM_OK) { + Jim_SetResultFormatted(goi.interp, "Unable to read reg name."); + goto fail; + } + + if (name_len > REG_TYPE_MAX_NAME_LENGTH) { + Jim_SetResultFormatted(goi.interp, "Reg type name is too big."); + goto fail; + } + + strncpy((void *)type->data_type.id, name, name_len); + if (!type->data_type.id) { + Jim_SetResultFormatted(goi.interp, "Unable to setup reg type name."); + goto fail; + } + + break; + } + case CFG_ADD_REG_TYPE_STRUCT_BITFIELD: + { + const char *field_name = NULL; + int field_name_len = 0; + e = jim_arc_read_reg_type_field(&goi, &field_name, &field_name_len, bitfields, + cur_field, CFG_ADD_REG_TYPE_STRUCT); + if (e != JIM_OK) { + Jim_SetResultFormatted(goi.interp, "Unable to add reg_type_struct field."); + goto fail; + } + + if (field_name_len > REG_TYPE_MAX_NAME_LENGTH) { + Jim_SetResultFormatted(goi.interp, "Reg type field_name_len is too big."); + goto fail; + } + + fields[cur_field].name = bitfields[cur_field].name; + strncpy(bitfields[cur_field].name, field_name, field_name_len); + if (!fields[cur_field].name) { + Jim_SetResultFormatted(goi.interp, "Unable to setup field name. "); + goto fail; + } + + fields[cur_field].bitfield = &(bitfields[cur_field].bitfield); + fields[cur_field].use_bitfields = true; + if (cur_field > 0) + fields[cur_field - 1].next = &(fields[cur_field]); + else + struct_type->fields = fields; + + cur_field += 1; + + break; + } + } + } + + if (!type->data_type.id) { + Jim_SetResultFormatted(goi.interp, "-name is a required option"); + goto fail; + } + + arc_reg_data_type_add(target, type); + LOG_DEBUG("added struct type {name=%s}", type->data_type.id); + return JIM_OK; + +fail: + free(type); + free(fields); + free(bitfields); + + return JIM_ERR; +} + +/* Add register */ +enum opts_add_reg { + CFG_ADD_REG_NAME, + CFG_ADD_REG_ARCH_NUM, + CFG_ADD_REG_IS_CORE, + CFG_ADD_REG_IS_BCR, + CFG_ADD_REG_GDB_FEATURE, + CFG_ADD_REG_TYPE, + CFG_ADD_REG_GENERAL, +}; + +static Jim_Nvp opts_nvp_add_reg[] = { + { .name = "-name", .value = CFG_ADD_REG_NAME }, + { .name = "-num", .value = CFG_ADD_REG_ARCH_NUM }, + { .name = "-core", .value = CFG_ADD_REG_IS_CORE }, + { .name = "-bcr", .value = CFG_ADD_REG_IS_BCR }, + { .name = "-feature", .value = CFG_ADD_REG_GDB_FEATURE }, + { .name = "-type", .value = CFG_ADD_REG_TYPE }, + { .name = "-g", .value = CFG_ADD_REG_GENERAL }, + { .name = NULL, .value = -1 } +}; + +void free_reg_desc(struct arc_reg_desc *r) +{ + free(r->name); + free(r->gdb_xml_feature); + free(r); +} + +static int jim_arc_add_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +{ + Jim_GetOptInfo goi; + JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1)); + + struct arc_reg_desc *reg = calloc(1, sizeof(*reg)); + if (!reg) { + Jim_SetResultFormatted(goi.interp, "Failed to allocate memory."); + return JIM_ERR; + } + + /* There is no architecture number that we could treat as invalid, so + * separate variable requried to ensure that arch num has been set. */ + bool arch_num_set = false; + const char *type_name = "int"; /* Default type */ + int type_name_len = strlen(type_name); + int e = ERROR_OK; + + /* At least we need to specify 4 parameters: name, number and gdb_feature, + * which means there should be 6 arguments. Also there can be additional paramters + * "-type <type>", "-g" and "-core" or "-bcr" which makes maximum 10 parameters. */ + if (goi.argc < 6 || goi.argc > 10) { + free_reg_desc(reg); + Jim_SetResultFormatted(goi.interp, + "Should be at least 6 argnuments and not greater than 10: " + " -name <name> -num <num> -feature <gdb_feature> " + " [-type <type_name>] [-core|-bcr] [-g]."); + return JIM_ERR; + } + + /* Parse options. */ + while (goi.argc > 0) { + Jim_Nvp *n; + e = Jim_GetOpt_Nvp(&goi, opts_nvp_add_reg, &n); + if (e != JIM_OK) { + Jim_GetOpt_NvpUnknown(&goi, opts_nvp_add_reg, 0); + free_reg_desc(reg); + return e; + } + + switch (n->value) { + case CFG_ADD_REG_NAME: + { + const char *reg_name = NULL; + int reg_name_len = 0; + + e = jim_arc_read_reg_name_field(&goi, ®_name, ®_name_len); + if (e != JIM_OK) { + Jim_SetResultFormatted(goi.interp, "Unable to read register name."); + free_reg_desc(reg); + return e; + } + + reg->name = strndup(reg_name, reg_name_len); + break; + } + case CFG_ADD_REG_IS_CORE: + reg->is_core = true; + break; + case CFG_ADD_REG_IS_BCR: + reg->is_bcr = true; + break; + case CFG_ADD_REG_ARCH_NUM: + { + jim_wide archnum; + + if (!goi.argc) { + free_reg_desc(reg); + Jim_WrongNumArgs(interp, goi.argc, goi.argv, "-num <int> ..."); + return JIM_ERR; + } + + e = Jim_GetOpt_Wide(&goi, &archnum); + if (e != JIM_OK) { + free_reg_desc(reg); + return e; + } + + reg->arch_num = archnum; + arch_num_set = true; + break; + } + case CFG_ADD_REG_GDB_FEATURE: + { + const char *feature = NULL; + int feature_len = 0; + + e = jim_arc_read_reg_name_field(&goi, &feature, &feature_len); + if (e != JIM_OK) { + Jim_SetResultFormatted(goi.interp, "Unable to read gdb_feature."); + free_reg_desc(reg); + return e; + } + + reg->gdb_xml_feature = strndup(feature, feature_len); + break; + } + case CFG_ADD_REG_TYPE: + e = jim_arc_read_reg_name_field(&goi, &type_name, &type_name_len); + if (e != JIM_OK) { + Jim_SetResultFormatted(goi.interp, "Unable to read register type."); + free_reg_desc(reg); + return e; + } + + break; + case CFG_ADD_REG_GENERAL: + reg->is_general = true; + break; + default: + LOG_DEBUG("Error: Unknown parameter"); + free_reg_desc(reg); + return JIM_ERR; + } + } + + /* Check that required fields are set */ + const char * const errmsg = validate_register(reg, arch_num_set); + if (errmsg) { + Jim_SetResultFormatted(goi.interp, errmsg); + free_reg_desc(reg); + return JIM_ERR; + } + + /* Add new register */ + struct command_context *ctx; + struct target *target; + + ctx = current_command_context(interp); + assert(ctx); + target = get_current_target(ctx); + if (!target) { + Jim_SetResultFormatted(goi.interp, "No current target"); + free_reg_desc(reg); + return JIM_ERR; + } + + reg->target = target; + + e = arc_reg_add(target, reg, type_name, type_name_len); + if (e == ERROR_ARC_REGTYPE_NOT_FOUND) { + Jim_SetResultFormatted(goi.interp, + "Cannot find type `%s' for register `%s'.", + type_name, reg->name); + free_reg_desc(reg); + return JIM_ERR; + } + + return e; +} + +/* arc set-reg-exists ($reg_name)+ + * Accepts any amount of register names - will set them as existing in a loop.*/ +COMMAND_HANDLER(arc_set_reg_exists) +{ + struct target * const target = get_current_target(CMD_CTX); + if (!target) { + command_print(CMD, "Unable to get current target."); + return JIM_ERR; + } + + if (!CMD_ARGC) { + command_print(CMD, "At least one register name must be specified."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + for (unsigned int i = 0; i < CMD_ARGC; i++) { + const char * const reg_name = CMD_ARGV[i]; + struct reg * const r = arc_reg_get_by_name(target->reg_cache, reg_name, true); + + if (!r) { + command_print(CMD, "Register `%s' is not found.", reg_name); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + r->exist = true; + } + + return JIM_OK; +} + +/* arc reg-field ($reg_name) ($reg_field) + * Reads struct type register field */ +static int jim_arc_get_reg_field(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +{ + Jim_GetOptInfo goi; + const char *reg_name, *field_name; + uint32_t value; + int retval; + + JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1)); + + LOG_DEBUG("Reading register field"); + if (goi.argc != 2) { + if (!goi.argc) + Jim_WrongNumArgs(interp, goi.argc, goi.argv, "<regname> <fieldname>"); + else if (goi.argc == 1) + Jim_WrongNumArgs(interp, goi.argc, goi.argv, "<fieldname>"); + else + Jim_WrongNumArgs(interp, goi.argc, goi.argv, "<regname> <fieldname>"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + JIM_CHECK_RETVAL(Jim_GetOpt_String(&goi, ®_name, NULL)); + JIM_CHECK_RETVAL(Jim_GetOpt_String(&goi, &field_name, NULL)); + assert(reg_name); + assert(field_name); + + struct command_context * const ctx = current_command_context(interp); + assert(ctx); + struct target * const target = get_current_target(ctx); + if (!target) { + Jim_SetResultFormatted(goi.interp, "No current target"); + return JIM_ERR; + } + + retval = arc_reg_get_field(target, reg_name, field_name, &value); + + switch (retval) { + case ERROR_OK: + break; + case ERROR_ARC_REGISTER_NOT_FOUND: + Jim_SetResultFormatted(goi.interp, + "Register `%s' has not been found.", reg_name); + return ERROR_COMMAND_ARGUMENT_INVALID; + case ERROR_ARC_REGISTER_IS_NOT_STRUCT: + Jim_SetResultFormatted(goi.interp, + "Register `%s' must have 'struct' type.", reg_name); + return ERROR_COMMAND_ARGUMENT_INVALID; + case ERROR_ARC_REGISTER_FIELD_NOT_FOUND: + Jim_SetResultFormatted(goi.interp, + "Field `%s' has not been found in register `%s'.", + field_name, reg_name); + return ERROR_COMMAND_ARGUMENT_INVALID; + case ERROR_ARC_FIELD_IS_NOT_BITFIELD: + Jim_SetResultFormatted(goi.interp, + "Field `%s' is not a 'bitfield' field in a structure.", + field_name); + return ERROR_COMMAND_ARGUMENT_INVALID; + default: + /* Pass through other errors. */ + return retval; + } + + Jim_SetResultInt(interp, value); + + return JIM_OK; +} + +/* ----- Exported target commands ------------------------------------------ */ + +static const struct command_registration arc_core_command_handlers[] = { +{ + .name = "add-reg-type-flags", + .jim_handler = jim_arc_add_reg_type_flags, + .mode = COMMAND_CONFIG, + .usage = "arc ardd-reg-type-flags -name <string> -flag <name> <position> " + "[-flag <name> <position>]...", + .help = "Add new 'flags' register data type. Only single bit flags " + "are supported. Type name is global. Bitsize of register is fixed " + "at 32 bits.", + }, + { + .name = "add-reg-type-struct", + .jim_handler = jim_arc_add_reg_type_struct, + .mode = COMMAND_CONFIG, + .usage = "arc add-reg-type-struct -name <string> -bitfield <name> <start> <end> " + "[-bitfield <name> <start> <end>]...", + .help = "Add new 'struct' register data type. Only bit-fields are " + "supported so far, which means that for each bitfield start and end " + "position bits must be specified. GDB also support type-fields, " + "where common type can be used instead. Type name is global. Bitsize of " + "register is fixed at 32 bits.", + }, + { + .name = "add-reg", + .jim_handler = jim_arc_add_reg, + .mode = COMMAND_CONFIG, + .usage = "arc add-reg -name <string> -num <int> -feature <string> [-gdbnum <int>] " + "[-core|-bcr] [-type <type_name>] [-g]", + .help = "Add new register. Name, architectural number and feature name " + "are requried options. GDB regnum will default to previous register " + "(gdbnum + 1) and shouldn't be specified in most cases. Type " + "defaults to default GDB 'int'.", + }, + { + .name = "set-reg-exists", + .handler = arc_set_reg_exists, + .mode = COMMAND_ANY, + .usage = "arc set-reg-exists <register-name> [<register-name>]...", + .help = "Set that register exists. Accepts multiple register names as " + "arguments.", + }, + { + .name = "get-reg-field", + .jim_handler = jim_arc_get_reg_field, + .mode = COMMAND_ANY, + .usage = "arc get-reg-field <regname> <field_name>", + .help = "Returns value of field in a register with 'struct' type.", + }, + { + .name = "jtag", + .mode = COMMAND_ANY, + .help = "ARC JTAG specific commands", + .usage = "", + .chain = arc_jtag_command_group, + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration arc_monitor_command_handlers[] = { + { + .name = "arc", + .mode = COMMAND_ANY, + .help = "ARC monitor command group", + .usage = "Help info ...", + .chain = arc_core_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; diff --git a/src/target/arc_cmd.h b/src/target/arc_cmd.h new file mode 100644 index 0000000..b2264eb --- /dev/null +++ b/src/target/arc_cmd.h @@ -0,0 +1,16 @@ +/*************************************************************************** + * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. * + * Frank Dols <frank.dols@synopsys.com> * + * Mischa Jonker <mischa.jonker@synopsys.com> * + * Anton Kolesov <anton.kolesov@synopsys.com> * + * Evgeniy Didin <didin@synopsys.com> * + * * + * SPDX-License-Identifier: GPL-2.0-or-later * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ARC_CMD_H +#define OPENOCD_TARGET_ARC_CMD_H + +extern const struct command_registration arc_monitor_command_handlers[]; + +#endif /* OPENOCD_TARGET_ARC_CMD_H */ diff --git a/src/target/arc_jtag.c b/src/target/arc_jtag.c new file mode 100644 index 0000000..e85167a --- /dev/null +++ b/src/target/arc_jtag.c @@ -0,0 +1,541 @@ +/*************************************************************************** + * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. * + * Frank Dols <frank.dols@synopsys.com> * + * Mischa Jonker <mischa.jonker@synopsys.com> * + * Anton Kolesov <anton.kolesov@synopsys.com> * + * Evgeniy Didin <didin@synopsys.com> * + * * + * SPDX-License-Identifier: GPL-2.0-or-later * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arc.h" + +/* + * This functions sets instruction register in TAP. TAP end state is always + * IRPAUSE. + * + * @param jtag_info + * @param new_instr Instruction to write to instruction register. + */ +static void arc_jtag_enque_write_ir(struct arc_jtag *jtag_info, uint32_t + new_instr) +{ + uint32_t current_instr; + struct jtag_tap *tap; + uint8_t instr_buffer[sizeof(uint32_t)] = {0}; + + assert(jtag_info); + assert(jtag_info->tap); + + tap = jtag_info->tap; + + /* Do not set instruction if it is the same as current. */ + current_instr = buf_get_u32(tap->cur_instr, 0, tap->ir_length); + if (current_instr == new_instr) + return; + + struct scan_field field = { + .num_bits = tap->ir_length, + .out_value = instr_buffer + }; + buf_set_u32(instr_buffer, 0, field.num_bits, new_instr); + + /* From code in src/jtag/drivers/driver.c it look like that fields are + * copied so it is OK that field in this function is allocated in stack and + * thus this memory will be repurposed before jtag_execute_queue() will be + * invoked. */ + jtag_add_ir_scan(tap, &field, TAP_IRPAUSE); +} + +/** + * Read 4-byte word from data register. + * + * Unlike arc_jtag_write_data, this function returns byte-buffer, caller must + * convert this data to required format himself. This is done, because it is + * impossible to convert data before jtag_execute_queue() is invoked, so it + * cannot be done inside this function, so it has to operate with + * byte-buffers. Write function on the other hand can "write-and-forget", data + * is converted to byte-buffer before jtag_execute_queue(). + * + * @param jtag_info + * @param data Array of bytes to read into. + * @param end_state End state after reading. + */ +static void arc_jtag_enque_read_dr(struct arc_jtag *jtag_info, uint8_t *data, + tap_state_t end_state) +{ + + assert(jtag_info); + assert(jtag_info->tap); + + struct scan_field field = { + .num_bits = 32, + .in_value = data + }; + + jtag_add_dr_scan(jtag_info->tap, 1, &field, end_state); +} + +/** + * Write 4-byte word to data register. + * + * @param jtag_info + * @param data 4-byte word to write into data register. + * @param end_state End state after writing. + */ +static void arc_jtag_enque_write_dr(struct arc_jtag *jtag_info, uint32_t data, + tap_state_t end_state) +{ + uint8_t out_value[sizeof(uint32_t)] = {0}; + + assert(jtag_info); + assert(jtag_info->tap); + + buf_set_u32(out_value, 0, 32, data); + + struct scan_field field = { + .num_bits = 32, + .out_value = out_value + }; + + jtag_add_dr_scan(jtag_info->tap, 1, &field, end_state); +} + + +/** + * Set transaction in command register. This function sets instruction register + * and then transaction register, there is no need to invoke write_ir before + * invoking this function. + * + * @param jtag_info + * @param new_trans Transaction to write to transaction command register. + * @param end_state End state after writing. + */ +static void arc_jtag_enque_set_transaction(struct arc_jtag *jtag_info, + uint32_t new_trans, tap_state_t end_state) +{ + uint8_t out_value[sizeof(uint32_t)] = {0}; + + assert(jtag_info); + assert(jtag_info->tap); + + /* No need to do anything. */ + if (jtag_info->cur_trans == new_trans) + return; + + /* Set instruction. We used to call write_ir at upper levels, however + * write_ir-write_transaction were constantly in pair, so to avoid code + * duplication this function does it self. For this reasons it is "set" + * instead of "write". */ + arc_jtag_enque_write_ir(jtag_info, ARC_TRANSACTION_CMD_REG); + buf_set_u32(out_value, 0, ARC_TRANSACTION_CMD_REG_LENGTH, new_trans); + struct scan_field field = { + .num_bits = ARC_TRANSACTION_CMD_REG_LENGTH, + .out_value = out_value + }; + + jtag_add_dr_scan(jtag_info->tap, 1, &field, end_state); + jtag_info->cur_trans = new_trans; +} + +/** + * Run reset through transaction set. None of the previous + * settings/commands/etc. are used anymore (or no influence). + */ +static void arc_jtag_enque_reset_transaction(struct arc_jtag *jtag_info) +{ + arc_jtag_enque_set_transaction(jtag_info, ARC_JTAG_CMD_NOP, TAP_IDLE); +} + +static void arc_jtag_enque_status_read(struct arc_jtag * const jtag_info, + uint8_t * const buffer) +{ + assert(jtag_info); + assert(jtag_info->tap); + assert(buffer); + + /* first writin code(0x8) of jtag status register in IR */ + arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_STATUS_REG); + /* Now reading dr performs jtag status register read */ + arc_jtag_enque_read_dr(jtag_info, buffer, TAP_IDLE); +} + +/* ----- Exported JTAG functions ------------------------------------------- */ + +int arc_jtag_startup(struct arc_jtag *jtag_info) +{ + assert(jtag_info); + + arc_jtag_enque_reset_transaction(jtag_info); + + return jtag_execute_queue(); +} + +/** Read STATUS register. */ +int arc_jtag_status(struct arc_jtag * const jtag_info, uint32_t * const value) +{ + uint8_t buffer[sizeof(uint32_t)]; + + assert(jtag_info); + assert(jtag_info->tap); + + /* Fill command queue. */ + arc_jtag_enque_reset_transaction(jtag_info); + arc_jtag_enque_status_read(jtag_info, buffer); + arc_jtag_enque_reset_transaction(jtag_info); + + /* Execute queue. */ + CHECK_RETVAL(jtag_execute_queue()); + + /* Parse output. */ + *value = buf_get_u32(buffer, 0, 32); + + return ERROR_OK; +} +/* Helper function: Adding read/write register operation to queue */ +static void arc_jtag_enque_register_rw(struct arc_jtag *jtag_info, uint32_t *addr, + uint8_t *read_buffer, const uint32_t *write_buffer, uint32_t count) +{ + uint32_t i; + + for (i = 0; i < count; i++) { + /* ARC jtag has optimization which is to increment ADDRESS_REG performing + * each transaction. Making sequential reads/writes we can set address for + * only first register in sequence, and than do read/write in cycle. */ + if (i == 0 || (addr[i] != addr[i-1] + 1)) { + arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_ADDRESS_REG); + /* Going to TAP_IDLE state we initiate jtag transaction. + * Reading data we must go to TAP_IDLE, because further + * the data would be read. In case of write we go to TAP_DRPAUSE, + * because we need to write data to Data register first. */ + if (write_buffer) + arc_jtag_enque_write_dr(jtag_info, addr[i], TAP_DRPAUSE); + else + arc_jtag_enque_write_dr(jtag_info, addr[i], TAP_IDLE); + arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_DATA_REG); + } + if (write_buffer) + arc_jtag_enque_write_dr(jtag_info, *(write_buffer + i), TAP_IDLE); + else + arc_jtag_enque_read_dr(jtag_info, read_buffer + i * 4, TAP_IDLE); + } + /* To prevent pollution of next regiter due to optimization it is necessary * + * to reset transaction */ + arc_jtag_enque_reset_transaction(jtag_info); +} + +/** + * Write registers. addr is an array of addresses, and those addresses can be + * in any order, though it is recommended that they are in sequential order + * where possible, as this reduces number of JTAG commands to transfer. + * + * @param jtag_info + * @param type Type of registers to write: core or aux. + * @param addr Array of registers numbers. + * @param count Amount of registers in arrays. + * @param values Array of register values. + */ +static int arc_jtag_write_registers(struct arc_jtag *jtag_info, uint32_t type, + uint32_t *addr, uint32_t count, const uint32_t *buffer) +{ + LOG_DEBUG("Writing to %s registers: addr[0]=0x%" PRIx32 ";count=%" PRIu32 + ";buffer[0]=0x%08" PRIx32, + (type == ARC_JTAG_CORE_REG ? "core" : "aux"), *addr, count, *buffer); + + if (!count) { + LOG_ERROR("Trying to write 0 registers"); + return ERROR_FAIL; + } + + arc_jtag_enque_reset_transaction(jtag_info); + + /* What registers are we writing to? */ + const uint32_t transaction = (type == ARC_JTAG_CORE_REG ? + ARC_JTAG_WRITE_TO_CORE_REG : ARC_JTAG_WRITE_TO_AUX_REG); + arc_jtag_enque_set_transaction(jtag_info, transaction, TAP_DRPAUSE); + + arc_jtag_enque_register_rw(jtag_info, addr, NULL, buffer, count); + + return jtag_execute_queue(); +} + +/** + * Read registers. addr is an array of addresses, and those addresses can be in + * any order, though it is recommended that they are in sequential order where + * possible, as this reduces number of JTAG commands to transfer. + * + * @param jtag_info + * @param type Type of registers to read: core or aux. + * @param addr Array of registers numbers. + * @param count Amount of registers in arrays. + * @param values Array of register values. + */ +static int arc_jtag_read_registers(struct arc_jtag *jtag_info, uint32_t type, + uint32_t *addr, uint32_t count, uint32_t *buffer) +{ + int retval; + uint32_t i; + + assert(jtag_info); + assert(jtag_info->tap); + + LOG_DEBUG("Reading %s registers: addr[0]=0x%" PRIx32 ";count=%" PRIu32, + (type == ARC_JTAG_CORE_REG ? "core" : "aux"), *addr, count); + + if (!count) { + LOG_ERROR("Trying to read 0 registers"); + return ERROR_FAIL; + } + + arc_jtag_enque_reset_transaction(jtag_info); + + /* What type of registers we are reading? */ + const uint32_t transaction = (type == ARC_JTAG_CORE_REG ? + ARC_JTAG_READ_FROM_CORE_REG : ARC_JTAG_READ_FROM_AUX_REG); + arc_jtag_enque_set_transaction(jtag_info, transaction, TAP_DRPAUSE); + + uint8_t *data_buf = calloc(sizeof(uint8_t), count * 4); + + arc_jtag_enque_register_rw(jtag_info, addr, data_buf, NULL, count); + + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute jtag queue: %d", retval); + retval = ERROR_FAIL; + goto exit; + } + + /* Convert byte-buffers to host /presentation. */ + for (i = 0; i < count; i++) + buffer[i] = buf_get_u32(data_buf + 4 * i, 0, 32); + + LOG_DEBUG("Read from register: buf[0]=0x%" PRIx32, buffer[0]); + +exit: + free(data_buf); + + return retval; +} + + +/** Wrapper function to ease writing of one core register. */ +int arc_jtag_write_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr, + uint32_t value) +{ + return arc_jtag_write_core_reg(jtag_info, &addr, 1, &value); +} + +/** + * Write core registers. addr is an array of addresses, and those addresses can + * be in any order, though it is recommended that they are in sequential order + * where possible, as this reduces number of JTAG commands to transfer. + * + * @param jtag_info + * @param addr Array of registers numbers. + * @param count Amount of registers in arrays. + * @param values Array of register values. + */ +int arc_jtag_write_core_reg(struct arc_jtag *jtag_info, uint32_t *addr, + uint32_t count, const uint32_t *buffer) +{ + return arc_jtag_write_registers(jtag_info, ARC_JTAG_CORE_REG, addr, count, + buffer); +} + +/** Wrapper function to ease reading of one core register. */ +int arc_jtag_read_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr, + uint32_t *value) +{ + return arc_jtag_read_core_reg(jtag_info, &addr, 1, value); +} + +/** + * Read core registers. addr is an array of addresses, and those addresses can + * be in any order, though it is recommended that they are in sequential order + * where possible, as this reduces number of JTAG commands to transfer. + * + * @param jtag_info + * @param addr Array of core register numbers. + * @param count Amount of registers in arrays. + * @param values Array of register values. + */ +int arc_jtag_read_core_reg(struct arc_jtag *jtag_info, uint32_t *addr, + uint32_t count, uint32_t *buffer) +{ + return arc_jtag_read_registers(jtag_info, ARC_JTAG_CORE_REG, addr, count, + buffer); +} + +/** Wrapper function to ease writing of one AUX register. */ +int arc_jtag_write_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr, + uint32_t value) +{ + return arc_jtag_write_aux_reg(jtag_info, &addr, 1, &value); +} + +/** + * Write AUX registers. addr is an array of addresses, and those addresses can + * be in any order, though it is recommended that they are in sequential order + * where possible, as this reduces number of JTAG commands to transfer. + * + * @param jtag_info + * @param addr Array of registers numbers. + * @param count Amount of registers in arrays. + * @param values Array of register values. + */ +int arc_jtag_write_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr, + uint32_t count, const uint32_t *buffer) +{ + return arc_jtag_write_registers(jtag_info, ARC_JTAG_AUX_REG, addr, count, + buffer); +} + +/** Wrapper function to ease reading of one AUX register. */ +int arc_jtag_read_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr, + uint32_t *value) +{ + return arc_jtag_read_aux_reg(jtag_info, &addr, 1, value); +} + +/** + * Read AUX registers. addr is an array of addresses, and those addresses can + * be in any order, though it is recommended that they are in sequential order + * where possible, as this reduces number of JTAG commands to transfer. + * + * @param jtag_info + * @param addr Array of AUX register numbers. + * @param count Amount of registers in arrays. + * @param values Array of register values. + */ +int arc_jtag_read_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr, + uint32_t count, uint32_t *buffer) +{ + return arc_jtag_read_registers(jtag_info, ARC_JTAG_AUX_REG, addr, count, + buffer); +} + +/** + * Write a sequence of 4-byte words into target memory. + * + * We can write only 4byte words via JTAG, so any non-word writes should be + * handled at higher levels by read-modify-write. + * + * This function writes directly to the memory, leaving any caches (if there + * are any) in inconsistent state. It is responsibility of upper level to + * resolve this. + * + * @param jtag_info + * @param addr Address of first word to write into. + * @param count Amount of word to write. + * @param buffer Array to write into memory. + */ +int arc_jtag_write_memory(struct arc_jtag *jtag_info, uint32_t addr, + uint32_t count, const uint32_t *buffer) +{ + assert(jtag_info); + assert(buffer); + + LOG_DEBUG("Writing to memory: addr=0x%08" PRIx32 ";count=%" PRIu32 ";buffer[0]=0x%08" PRIx32, + addr, count, *buffer); + + /* No need to waste time on useless operations. */ + if (!count) + return ERROR_OK; + + /* We do not know where we come from. */ + arc_jtag_enque_reset_transaction(jtag_info); + + /* We want to write to memory. */ + arc_jtag_enque_set_transaction(jtag_info, ARC_JTAG_WRITE_TO_MEMORY, TAP_DRPAUSE); + + /* Set target memory address of the first word. */ + arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_ADDRESS_REG); + arc_jtag_enque_write_dr(jtag_info, addr, TAP_DRPAUSE); + + /* Start sending words. Address is auto-incremented on 4bytes by HW. */ + arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_DATA_REG); + + uint32_t i; + for (i = 0; i < count; i++) + arc_jtag_enque_write_dr(jtag_info, *(buffer + i), TAP_IDLE); + + return jtag_execute_queue(); +} + +/** + * Read a sequence of 4-byte words from target memory. + * + * We can read only 4byte words via JTAG. + * + * This function read directly from the memory, so it can read invalid data if + * data cache hasn't been flushed before hand. It is responsibility of upper + * level to resolve this. + * + * @param jtag_info + * @param addr Address of first word to read from. + * @param count Amount of words to read. + * @param buffer Array of words to read into. + * @param slow_memory Whether this is a slow memory (DDR) or fast (CCM). + */ +int arc_jtag_read_memory(struct arc_jtag *jtag_info, uint32_t addr, + uint32_t count, uint32_t *buffer, bool slow_memory) +{ + uint8_t *data_buf; + uint32_t i; + int retval = ERROR_OK; + + + assert(jtag_info); + assert(jtag_info->tap); + + LOG_DEBUG("Reading memory: addr=0x%" PRIx32 ";count=%" PRIu32 ";slow=%c", + addr, count, slow_memory ? 'Y' : 'N'); + + if (!count) + return ERROR_OK; + + data_buf = calloc(sizeof(uint8_t), count * 4); + arc_jtag_enque_reset_transaction(jtag_info); + + /* We are reading from memory. */ + arc_jtag_enque_set_transaction(jtag_info, ARC_JTAG_READ_FROM_MEMORY, TAP_DRPAUSE); + + /* Read data */ + for (i = 0; i < count; i++) { + /* When several words are read at consequent addresses we can + * rely on ARC JTAG auto-incrementing address. That means that + * address can be set only once, for a first word. However it + * has been noted that at least in some cases when reading from + * DDR, JTAG returns 0 instead of a real value. To workaround + * this issue we need to do totally non-required address + * writes, which however resolve a problem by introducing + * delay. See STAR 9000832538... */ + if (slow_memory || i == 0) { + /* Set address */ + arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_ADDRESS_REG); + arc_jtag_enque_write_dr(jtag_info, addr + i * 4, TAP_IDLE); + + arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_DATA_REG); + } + arc_jtag_enque_read_dr(jtag_info, data_buf + i * 4, TAP_IDLE); + } + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute jtag queue: %d", retval); + retval = ERROR_FAIL; + goto exit; + } + + /* Convert byte-buffers to host presentation. */ + for (i = 0; i < count; i++) + buffer[i] = buf_get_u32(data_buf + 4*i, 0, 32); + +exit: + free(data_buf); + + return retval; +} diff --git a/src/target/arc_jtag.h b/src/target/arc_jtag.h new file mode 100644 index 0000000..99795f5 --- /dev/null +++ b/src/target/arc_jtag.h @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. * + * Frank Dols <frank.dols@synopsys.com> * + * Mischa Jonker <mischa.jonker@synopsys.com> * + * Anton Kolesov <anton.kolesov@synopsys.com> * + * Evgeniy Didin <didin@synopsys.com> * + * * + * SPDX-License-Identifier: GPL-2.0-or-later * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ARC_JTAG_H +#define OPENOCD_TARGET_ARC_JTAG_H + +#define ARC_TRANSACTION_CMD_REG 0x9 /* Command to perform */ +#define ARC_TRANSACTION_CMD_REG_LENGTH 4 + +/* Jtag status register, value is placed in IR to read jtag status register */ +#define ARC_JTAG_STATUS_REG 0x8 +#define ARC_JTAG_ADDRESS_REG 0xA /* SoC address to access */ +#define ARC_JTAG_DATA_REG 0xB /* Data read/written from SoC */ + +/* Jtag status register field */ +#define ARC_JTAG_STAT_RU 0x10 + +/* ARC Jtag transactions */ +#define ARC_JTAG_WRITE_TO_MEMORY 0x0 +#define ARC_JTAG_WRITE_TO_CORE_REG 0x1 +#define ARC_JTAG_WRITE_TO_AUX_REG 0x2 +#define ARC_JTAG_CMD_NOP 0x3 +#define ARC_JTAG_READ_FROM_MEMORY 0x4 +#define ARC_JTAG_READ_FROM_CORE_REG 0x5 +#define ARC_JTAG_READ_FROM_AUX_REG 0x6 + +#define ARC_JTAG_CORE_REG 0x0 +#define ARC_JTAG_AUX_REG 0x1 + + +struct arc_jtag { + struct jtag_tap *tap; + uint32_t cur_trans; +}; + +/* ----- Exported JTAG functions ------------------------------------------- */ + +int arc_jtag_startup(struct arc_jtag *jtag_info); +int arc_jtag_status(struct arc_jtag *const jtag_info, uint32_t *const value); + +int arc_jtag_write_core_reg(struct arc_jtag *jtag_info, uint32_t *addr, + uint32_t count, const uint32_t *buffer); +int arc_jtag_read_core_reg(struct arc_jtag *jtag_info, uint32_t *addr, + uint32_t count, uint32_t *buffer); +int arc_jtag_write_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr, + const uint32_t buffer); +int arc_jtag_read_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr, + uint32_t *buffer); + +int arc_jtag_write_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr, + uint32_t count, const uint32_t *buffer); +int arc_jtag_write_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr, + uint32_t value); +int arc_jtag_read_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr, + uint32_t count, uint32_t *buffer); +int arc_jtag_read_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr, + uint32_t *value); + +int arc_jtag_write_memory(struct arc_jtag *jtag_info, uint32_t addr, + uint32_t count, const uint32_t *buffer); +int arc_jtag_read_memory(struct arc_jtag *jtag_info, uint32_t addr, + uint32_t count, uint32_t *buffer, bool slow_memory); +#endif /* OPENOCD_TARGET_ARC_JTAG_H */ diff --git a/src/target/arc_mem.c b/src/target/arc_mem.c new file mode 100644 index 0000000..e80bfb4 --- /dev/null +++ b/src/target/arc_mem.c @@ -0,0 +1,287 @@ +/*************************************************************************** + * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. * + * Frank Dols <frank.dols@synopsys.com> * + * Mischa Jonker <mischa.jonker@synopsys.com> * + * Anton Kolesov <anton.kolesov@synopsys.com> * + * Evgeniy Didin <didin@synopsys.com> * + * * + * SPDX-License-Identifier: GPL-2.0-or-later * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arc.h" + +/* ----- Supporting functions ---------------------------------------------- */ +static bool arc_mem_is_slow_memory(struct arc_common *arc, uint32_t addr, + uint32_t size, uint32_t count) +{ + uint32_t addr_end = addr + size * count; + /* `_end` field can overflow - it points to the first byte after the end, + * therefore if DCCM is right at the end of memory address space, then + * dccm_end will be 0. */ + assert(addr_end >= addr || addr_end == 0); + + return !((addr >= arc->dccm_start && addr_end <= arc->dccm_end) || + (addr >= arc->iccm0_start && addr_end <= arc->iccm0_end) || + (addr >= arc->iccm1_start && addr_end <= arc->iccm1_end)); +} + +/* Write word at word-aligned address */ +static int arc_mem_write_block32(struct target *target, uint32_t addr, + uint32_t count, void *buf) +{ + struct arc_common *arc = target_to_arc(target); + + LOG_DEBUG("Write 4-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32, + addr, count); + + /* Check arguments */ + assert(!(addr & 3)); + + /* No need to flush cache, because we don't read values from memory. */ + CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, addr, count, + (uint32_t *)buf)); + + return ERROR_OK; +} + +/* Write half-word at half-word-aligned address */ +static int arc_mem_write_block16(struct target *target, uint32_t addr, + uint32_t count, void *buf) +{ + struct arc_common *arc = target_to_arc(target); + uint32_t i; + uint32_t buffer_he; + uint8_t buffer_te[sizeof(uint32_t)]; + uint8_t halfword_te[sizeof(uint16_t)]; + + LOG_DEBUG("Write 2-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32, + addr, count); + + /* Check arguments */ + assert(!(addr & 1)); + + /* non-word writes are less common, than 4-byte writes, so I suppose we can + * allowe ourselves to write this in a cycle, instead of calling arc_jtag + * with count > 1. */ + for (i = 0; i < count; i++) { + /* We can read only word at word-aligned address. Also *jtag_read_memory + * functions return data in host endianness, so host endianness != + * target endianness we have to convert data back to target endianness, + * or bytes will be at the wrong places.So: + * 1) read word + * 2) convert to target endianness + * 3) make changes + * 4) convert back to host endianness + * 5) write word back to target. + */ + bool is_slow_memory = arc_mem_is_slow_memory(arc, + (addr + i * sizeof(uint16_t)) & ~3u, 4, 1); + CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, + (addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he, + is_slow_memory)); + target_buffer_set_u32(target, buffer_te, buffer_he); + + /* buf is in host endianness, convert to target */ + target_buffer_set_u16(target, halfword_te, ((uint16_t *)buf)[i]); + + memcpy(buffer_te + ((addr + i * sizeof(uint16_t)) & 3u), + halfword_te, sizeof(uint16_t)); + + buffer_he = target_buffer_get_u32(target, buffer_te); + + CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, + (addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he)); + } + + return ERROR_OK; +} + +/* Write byte at address */ +static int arc_mem_write_block8(struct target *target, uint32_t addr, + uint32_t count, void *buf) +{ + struct arc_common *arc = target_to_arc(target); + uint32_t i; + uint32_t buffer_he; + uint8_t buffer_te[sizeof(uint32_t)]; + + + LOG_DEBUG("Write 1-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32, + addr, count); + + /* non-word writes are less common, than 4-byte writes, so I suppose we can + * allowe ourselves to write this in a cycle, instead of calling arc_jtag + * with count > 1. */ + for (i = 0; i < count; i++) { + /* See comment in arc_mem_write_block16 for details. Since it is a byte + * there is not need to convert write buffer to target endianness, but + * we still have to convert read buffer. */ + CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, (addr + i) & ~3, 1, &buffer_he, + arc_mem_is_slow_memory(arc, (addr + i) & ~3, 4, 1))); + target_buffer_set_u32(target, buffer_te, buffer_he); + memcpy(buffer_te + ((addr + i) & 3), (uint8_t *)buf + i, 1); + buffer_he = target_buffer_get_u32(target, buffer_te); + CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, (addr + i) & ~3, 1, &buffer_he)); + } + + return ERROR_OK; +} + +/* ----- Exported functions ------------------------------------------------ */ +int arc_mem_write(struct target *target, target_addr_t address, uint32_t size, + uint32_t count, const uint8_t *buffer) +{ + int retval = ERROR_OK; + void *tunnel = NULL; + + LOG_DEBUG("address: 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: %" PRIu32, + address, size, count); + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* sanitize arguments */ + if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer)) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) + return ERROR_TARGET_UNALIGNED_ACCESS; + + /* correct endianess if we have word or hword access */ + if (size > 1) { + /* + * arc_..._write_mem with size 4/2 requires uint32_t/uint16_t + * in host endianness, but byte array represents target endianness. + */ + tunnel = calloc(1, count * size * sizeof(uint8_t)); + + if (!tunnel) { + LOG_ERROR("Unable to allocate memory"); + return ERROR_FAIL; + } + + switch (size) { + case 4: + target_buffer_get_u32_array(target, buffer, count, + (uint32_t *)tunnel); + break; + case 2: + target_buffer_get_u16_array(target, buffer, count, + (uint16_t *)tunnel); + break; + } + buffer = tunnel; + } + + if (size == 4) { + retval = arc_mem_write_block32(target, address, count, (void *)buffer); + } else if (size == 2) { + /* We convert buffer from host endianness to target. But then in + * write_block16, we do the reverse. Is there a way to avoid this without + * breaking other cases? */ + retval = arc_mem_write_block16(target, address, count, (void *)buffer); + } else { + retval = arc_mem_write_block8(target, address, count, (void *)buffer); + } + + free(tunnel); + + return retval; +} + +static int arc_mem_read_block(struct target *target, target_addr_t addr, + uint32_t size, uint32_t count, void *buf) +{ + struct arc_common *arc = target_to_arc(target); + + LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32 + ", count=%" PRIu32, addr, size, count); + assert(!(addr & 3)); + assert(size == 4); + + CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, addr, count, buf, + arc_mem_is_slow_memory(arc, addr, size, count))); + + return ERROR_OK; +} + +int arc_mem_read(struct target *target, target_addr_t address, uint32_t size, + uint32_t count, uint8_t *buffer) +{ + int retval = ERROR_OK; + void *tunnel_he; + uint8_t *tunnel_te; + uint32_t words_to_read, bytes_to_read; + + + LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32 + ", count=%" PRIu32, address, size, count); + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* Sanitize arguments */ + if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer)) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) + return ERROR_TARGET_UNALIGNED_ACCESS; + + /* Reads are word-aligned, so padding might be required if count > 1. + * NB: +3 is a padding for the last word (in case it's not aligned; + * addr&3 is a padding for the first word (since address can be + * unaligned as well). */ + bytes_to_read = (count * size + 3 + (address & 3u)) & ~3u; + words_to_read = bytes_to_read >> 2; + tunnel_he = calloc(1, bytes_to_read); + tunnel_te = calloc(1, bytes_to_read); + + if (!tunnel_he || !tunnel_te) { + LOG_ERROR("Unable to allocate memory"); + free(tunnel_he); + free(tunnel_te); + return ERROR_FAIL; + } + + /* We can read only word-aligned words. */ + retval = arc_mem_read_block(target, address & ~3u, sizeof(uint32_t), + words_to_read, tunnel_he); + + /* arc_..._read_mem with size 4/2 returns uint32_t/uint16_t in host */ + /* endianness, but byte array should represent target endianness */ + + if (ERROR_OK == retval) { + switch (size) { + case 4: + target_buffer_set_u32_array(target, buffer, count, + tunnel_he); + break; + case 2: + target_buffer_set_u32_array(target, tunnel_te, + words_to_read, tunnel_he); + /* Will that work properly with count > 1 and big endian? */ + memcpy(buffer, tunnel_te + (address & 3u), + count * sizeof(uint16_t)); + break; + case 1: + target_buffer_set_u32_array(target, tunnel_te, + words_to_read, tunnel_he); + /* Will that work properly with count > 1 and big endian? */ + memcpy(buffer, tunnel_te + (address & 3u), count); + break; + } + } + + free(tunnel_he); + free(tunnel_te); + + return retval; +} diff --git a/src/target/arc_mem.h b/src/target/arc_mem.h new file mode 100644 index 0000000..06e1c88 --- /dev/null +++ b/src/target/arc_mem.h @@ -0,0 +1,21 @@ +/*************************************************************************** + * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. * + * Frank Dols <frank.dols@synopsys.com> * + * Anton Kolesov <anton.kolesov@synopsys.com> * + * Evgeniy Didin <didin@synopsys.com> * + * * + * SPDX-License-Identifier: GPL-2.0-or-later * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ARC_MEM_H +#define OPENOCD_TARGET_ARC_MEM_H + +/* ----- Exported functions ------------------------------------------------ */ + +int arc_mem_read(struct target *target, target_addr_t address, uint32_t size, + uint32_t count, uint8_t *buffer); +int arc_mem_write(struct target *target, target_addr_t address, uint32_t size, + uint32_t count, const uint8_t *buffer); + + +#endif /* OPENOCD_TARGET_ARC_MEM_H */ diff --git a/src/target/arm.h b/src/target/arm.h index ea83d38..3450260 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -41,6 +41,26 @@ */ /** + * Indicates what registers are in the ARM state core register set. + * + * - ARM_CORE_TYPE_STD indicates the standard set of 37 registers, seen + * on for example ARM7TDMI cores. + * - ARM_CORE_TYPE_SEC_EXT indicates core has security extensions, thus + * three more registers are shadowed for "Secure Monitor" mode. + * - ARM_CORE_TYPE_VIRT_EXT indicates core has virtualization extensions + * and also security extensions. Additional shadowed registers for + * "Secure Monitor" and "Hypervisor" modes. + * - ARM_CORE_TYPE_M_PROFILE indicates a microcontroller profile core, + * which only shadows SP. + */ +enum arm_core_type { + ARM_CORE_TYPE_STD = -1, + ARM_CORE_TYPE_SEC_EXT = 1, + ARM_CORE_TYPE_VIRT_EXT, + ARM_CORE_TYPE_M_PROFILE, +}; + +/** * Represent state of an ARM core. * * Most numbers match the five low bits of the *PSR registers on @@ -60,6 +80,7 @@ enum arm_mode { ARM_MODE_SVC = 19, ARM_MODE_MON = 22, ARM_MODE_ABT = 23, + ARM_MODE_HYP = 26, ARM_MODE_UND = 27, ARM_MODE_1176_MON = 28, ARM_MODE_SYS = 31, @@ -161,15 +182,8 @@ struct arm { /** Support for arm_reg_current() */ const int *map; - /** - * Indicates what registers are in the ARM state core register set. - * ARM_MODE_ANY indicates the standard set of 37 registers, - * seen on for example ARM7TDMI cores. ARM_MODE_MON indicates three - * more registers are shadowed, for "Secure Monitor" mode. - * ARM_MODE_THREAD indicates a microcontroller profile core, - * which only shadows SP. - */ - enum arm_mode core_type; + /** Indicates what registers are in the ARM state core register set. */ + enum arm_core_type core_type; /** Record the current core mode: SVC, USR, or some other mode. */ enum arm_mode core_mode; @@ -258,6 +272,8 @@ struct arm_reg { }; struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm); +void arm_free_reg_cache(struct arm *arm); + struct reg_cache *armv8_build_reg_cache(struct target *target); extern const struct command_registration arm_command_handlers[]; diff --git a/src/target/arm11.c b/src/target/arm11.c index 159c30a..10a1d6d 100644 --- a/src/target/arm11.c +++ b/src/target/arm11.c @@ -1105,11 +1105,11 @@ static int arm11_target_create(struct target *target, Jim_Interp *interp) return ERROR_COMMAND_SYNTAX_ERROR; } - arm11 = calloc(1, sizeof *arm11); + arm11 = calloc(1, sizeof(*arm11)); if (!arm11) return ERROR_FAIL; - arm11->arm.core_type = ARM_MODE_ANY; + arm11->arm.core_type = ARM_CORE_TYPE_STD; arm_init_arch_info(target, &arm11->arm); arm11->jtag_info.tap = target->tap; @@ -1180,7 +1180,7 @@ static int arm11_examine(struct target *target) type = "ARM1156"; break; case 0x7B76: - arm11->arm.core_type = ARM_MODE_MON; + arm11->arm.core_type = ARM_CORE_TYPE_SEC_EXT; /* NOTE: could default arm11->hardware_step to true */ type = "ARM1176"; break; diff --git a/src/target/arm11_dbgtap.c b/src/target/arm11_dbgtap.c index 2232b3e..a758db5 100644 --- a/src/target/arm11_dbgtap.c +++ b/src/target/arm11_dbgtap.c @@ -1183,7 +1183,7 @@ int arm11_dpm_init(struct arm11_common *arm11, uint32_t didr) /* alloc enough to enable all breakpoints and watchpoints at once */ arm11->bpwp_actions = calloc(2 * (dpm->nbp + dpm->nwp), - sizeof *arm11->bpwp_actions); + sizeof(*arm11->bpwp_actions)); if (!arm11->bpwp_actions) return ERROR_FAIL; diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index b2962d1..6a7bf9d 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -2848,7 +2848,7 @@ int arm7_9_init_arch_info(struct target *target, struct arm7_9_common *arm7_9) arm7_9->dcc_downloads = false; arm->arch_info = arm7_9; - arm->core_type = ARM_MODE_ANY; + arm->core_type = ARM_CORE_TYPE_STD; arm->read_core_reg = arm7_9_read_core_reg; arm->write_core_reg = arm7_9_write_core_reg; arm->full_context = arm7_9_full_context; diff --git a/src/target/arm920t.c b/src/target/arm920t.c index 2ecf218..3ddd198 100644 --- a/src/target/arm920t.c +++ b/src/target/arm920t.c @@ -484,7 +484,7 @@ int arm920t_post_debug_entry(struct target *target) /* EXPORTED to FA256 */ void arm920t_pre_restore_context(struct target *target) { - uint32_t cp15c15; + uint32_t cp15c15 = 0; struct arm920t_common *arm920t = target_to_arm920(target); /* restore i/d fault status and address register */ diff --git a/src/target/arm946e.c b/src/target/arm946e.c index 112631a..4ef167a 100644 --- a/src/target/arm946e.c +++ b/src/target/arm946e.c @@ -267,7 +267,11 @@ uint32_t arm946e_invalidate_whole_dcache(struct target *target) /* Read dtag */ uint32_t dtag; - arm946e_read_cp15(target, 0x16, (uint32_t *) &dtag); + retval = arm946e_read_cp15(target, 0x16, &dtag); + if (retval != ERROR_OK) { + LOG_DEBUG("ERROR reading dtag"); + return retval; + } /* Check cache line VALID bit */ if (!(dtag >> 4 & 0x1)) @@ -321,7 +325,7 @@ int arm946e_post_debug_entry(struct target *target) /* See if CACHES are enabled, and save that info * in the context bits, so that arm946e_pre_restore_context() can use them */ - arm946e_read_cp15(target, CP15_CTL, (uint32_t *) &ctr_reg); + arm946e_read_cp15(target, CP15_CTL, &ctr_reg); /* Save control reg in the context */ arm946e->cp15_control_reg = ctr_reg; @@ -362,7 +366,7 @@ void arm946e_pre_restore_context(struct target *target) if (arm946e_preserve_cache) { struct arm946e_common *arm946e = target_to_arm946(target); /* Get the contents of the CTR reg */ - arm946e_read_cp15(target, CP15_CTL, (uint32_t *) &ctr_reg); + arm946e_read_cp15(target, CP15_CTL, &ctr_reg); /** * Read-modify-write CP15 control @@ -410,7 +414,11 @@ uint32_t arm946e_invalidate_dcache(struct target *target, uint32_t address, } /* Read dtag */ - arm946e_read_cp15(target, 0x16, (uint32_t *) &dtag); + retval = arm946e_read_cp15(target, 0x16, &dtag); + if (retval != ERROR_OK) { + LOG_DEBUG("ERROR reading dtag"); + return retval; + } /* Check cache line VALID bit */ if (!(dtag >> 4 & 0x1)) @@ -463,7 +471,11 @@ uint32_t arm946e_invalidate_icache(struct target *target, uint32_t address, } /* Read itag */ - arm946e_read_cp15(target, 0x17, (uint32_t *) &itag); + retval = arm946e_read_cp15(target, 0x17, &itag); + if (retval != ERROR_OK) { + LOG_DEBUG("ERROR reading itag"); + return retval; + } /* Check cache line VALID bit */ if (!(itag >> 4 & 0x1)) diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index d2ec960..f19514c 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -804,26 +804,9 @@ int mem_ap_init(struct adiv5_ap *ap) */ int dap_to_swd(struct adiv5_dap *dap) { - int retval; - LOG_DEBUG("Enter SWD mode"); - if (transport_is_jtag()) { - retval = jtag_add_tms_seq(swd_seq_jtag_to_swd_len, - swd_seq_jtag_to_swd, TAP_INVALID); - if (retval == ERROR_OK) - retval = jtag_execute_queue(); - return retval; - } - - if (transport_is_swd()) { - const struct swd_driver *swd = adiv5_dap_swd_driver(dap); - - return swd->switch_seq(JTAG_TO_SWD); - } - - LOG_ERROR("Nor JTAG nor SWD transport"); - return ERROR_FAIL; + return dap_send_sequence(dap, JTAG_TO_SWD); } /** @@ -839,26 +822,9 @@ int dap_to_swd(struct adiv5_dap *dap) */ int dap_to_jtag(struct adiv5_dap *dap) { - int retval; - LOG_DEBUG("Enter JTAG mode"); - if (transport_is_jtag()) { - retval = jtag_add_tms_seq(swd_seq_swd_to_jtag_len, - swd_seq_swd_to_jtag, TAP_RESET); - if (retval == ERROR_OK) - retval = jtag_execute_queue(); - return retval; - } - - if (transport_is_swd()) { - const struct swd_driver *swd = adiv5_dap_swd_driver(dap); - - return swd->switch_seq(SWD_TO_JTAG); - } - - LOG_ERROR("Nor JTAG nor SWD transport"); - return ERROR_FAIL; + return dap_send_sequence(dap, SWD_TO_JTAG); } /* CID interpretation -- see ARM IHI 0029B section 3 @@ -1644,8 +1610,10 @@ COMMAND_HANDLER(handle_dap_info_command) break; case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); - if (apsel > DP_APSEL_MAX) - return ERROR_COMMAND_SYNTAX_ERROR; + if (apsel > DP_APSEL_MAX) { + command_print(CMD, "Invalid AP number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } break; default: return ERROR_COMMAND_SYNTAX_ERROR; @@ -1667,8 +1635,10 @@ COMMAND_HANDLER(dap_baseaddr_command) case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); /* AP address is in bits 31:24 of DP_SELECT */ - if (apsel > DP_APSEL_MAX) - return ERROR_COMMAND_SYNTAX_ERROR; + if (apsel > DP_APSEL_MAX) { + command_print(CMD, "Invalid AP number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } break; default: return ERROR_COMMAND_SYNTAX_ERROR; @@ -1726,8 +1696,10 @@ COMMAND_HANDLER(dap_apsel_command) case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); /* AP address is in bits 31:24 of DP_SELECT */ - if (apsel > DP_APSEL_MAX) - return ERROR_COMMAND_SYNTAX_ERROR; + if (apsel > DP_APSEL_MAX) { + command_print(CMD, "Invalid AP number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } break; default: return ERROR_COMMAND_SYNTAX_ERROR; @@ -1756,7 +1728,7 @@ COMMAND_HANDLER(dap_apcsw_command) if (csw_val & (CSW_SIZE_MASK | CSW_ADDRINC_MASK)) { LOG_ERROR("CSW value cannot include 'Size' and 'AddrInc' bit-fields"); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } apcsw = csw_val; break; @@ -1765,7 +1737,7 @@ COMMAND_HANDLER(dap_apcsw_command) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], csw_mask); if (csw_mask & (CSW_SIZE_MASK | CSW_ADDRINC_MASK)) { LOG_ERROR("CSW mask cannot include 'Size' and 'AddrInc' bit-fields"); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } apcsw = (apcsw & ~csw_mask) | (csw_val & csw_mask); break; @@ -1792,8 +1764,10 @@ COMMAND_HANDLER(dap_apid_command) case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); /* AP address is in bits 31:24 of DP_SELECT */ - if (apsel > DP_APSEL_MAX) - return ERROR_COMMAND_SYNTAX_ERROR; + if (apsel > DP_APSEL_MAX) { + command_print(CMD, "Invalid AP number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } break; default: return ERROR_COMMAND_SYNTAX_ERROR; @@ -1823,13 +1797,18 @@ COMMAND_HANDLER(dap_apreg_command) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); /* AP address is in bits 31:24 of DP_SELECT */ - if (apsel > DP_APSEL_MAX) - return ERROR_COMMAND_SYNTAX_ERROR; + if (apsel > DP_APSEL_MAX) { + command_print(CMD, "Invalid AP number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + ap = dap_ap(dap, apsel); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg); - if (reg >= 256 || (reg & 3)) - return ERROR_COMMAND_SYNTAX_ERROR; + if (reg >= 256 || (reg & 3)) { + command_print(CMD, "Invalid reg value (should be less than 256 and 4 bytes aligned)"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } if (CMD_ARGC == 3) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); @@ -1873,8 +1852,10 @@ COMMAND_HANDLER(dap_dpreg_command) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], reg); - if (reg >= 256 || (reg & 3)) - return ERROR_COMMAND_SYNTAX_ERROR; + if (reg >= 256 || (reg & 3)) { + command_print(CMD, "Invalid reg value (should be less than 256 and 4 bytes aligned)"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } if (CMD_ARGC == 2) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); @@ -1897,24 +1878,8 @@ COMMAND_HANDLER(dap_dpreg_command) COMMAND_HANDLER(dap_ti_be_32_quirks_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); - uint32_t enable = dap->ti_be_32_quirks; - - switch (CMD_ARGC) { - case 0: - break; - case 1: - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], enable); - if (enable > 1) - return ERROR_COMMAND_SYNTAX_ERROR; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - dap->ti_be_32_quirks = enable; - command_print(CMD, "TI BE-32 quirks mode %s", - enable ? "enabled" : "disabled"); - - return 0; + return CALL_COMMAND_HANDLER(handle_command_parse_bool, &dap->ti_be_32_quirks, + "TI BE-32 quirks mode"); } const struct command_registration dap_instance_commands[] = { diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index 6e2d8a1..17365bd 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -158,6 +158,15 @@ #define DP_APSEL_MAX (255) #define DP_APSEL_INVALID (-1) +/* FIXME: not SWD specific; should be renamed, e.g. adiv5_special_seq */ +enum swd_special_seq { + LINE_RESET, + JTAG_TO_SWD, + SWD_TO_JTAG, + SWD_TO_DORMANT, + DORMANT_TO_SWD, +}; + /** * This represents an ARM Debug Interface (v5) Access Port (AP). * Most common is a MEM-AP, for memory access. @@ -234,6 +243,12 @@ struct adiv5_dap { /* dap transaction list for WAIT support */ struct list_head cmd_journal; + /* pool for dap_cmd objects */ + struct list_head cmd_pool; + + /* number of dap_cmd objects in the pool */ + size_t cmd_pool_size; + struct jtag_tap *tap; /* Control config */ uint32_t dp_ctrl_stat; @@ -265,6 +280,12 @@ struct adiv5_dap { bool ti_be_32_quirks; /** + * STLINK adapter need to know if last AP operation was read or write, and + * in case of write has to flush it with a dummy read from DP_RDBUFF + */ + bool stlink_flush_ap_write; + + /** * Signals that an attempt to reestablish communication afresh * should be performed before the next access. */ @@ -285,6 +306,10 @@ struct adiv5_dap { struct dap_ops { /** connect operation for SWD */ int (*connect)(struct adiv5_dap *dap); + + /** send a sequence to the DAP */ + int (*send_sequence)(struct adiv5_dap *dap, enum swd_special_seq seq); + /** DP register read. */ int (*queue_dp_read)(struct adiv5_dap *dap, unsigned reg, uint32_t *data); @@ -333,6 +358,21 @@ enum ap_type { }; /** + * Send an adi-v5 sequence to the DAP. + * + * @param dap The DAP used for reading. + * @param seq The sequence to send. + * + * @return ERROR_OK for success, else a fault code. + */ +static inline int dap_send_sequence(struct adiv5_dap *dap, + enum swd_special_seq seq) +{ + assert(dap->ops != NULL); + return dap->ops->send_sequence(dap, seq); +} + +/** * Queue a DP register read. * Note that not all DP registers are readable; also, that JTAG and SWD * have slight differences in DP register support. diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c index 3f063b8..579bacb 100644 --- a/src/target/arm_cti.c +++ b/src/target/arm_cti.c @@ -261,14 +261,11 @@ COMMAND_HANDLER(handle_cti_dump) COMMAND_HANDLER(handle_cti_enable) { struct arm_cti_object *obj = CMD_DATA; - Jim_Interp *interp = CMD_CTX->interp; struct arm_cti *cti = &obj->cti; bool on_off; - if (CMD_ARGC != 1) { - Jim_SetResultString(interp, "wrong number of args", -1); - return ERROR_FAIL; - } + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off); @@ -278,14 +275,11 @@ COMMAND_HANDLER(handle_cti_enable) COMMAND_HANDLER(handle_cti_testmode) { struct arm_cti_object *obj = CMD_DATA; - Jim_Interp *interp = CMD_CTX->interp; struct arm_cti *cti = &obj->cti; bool on_off; - if (CMD_ARGC != 1) { - Jim_SetResultString(interp, "wrong number of args", -1); - return ERROR_FAIL; - } + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off); @@ -295,15 +289,12 @@ COMMAND_HANDLER(handle_cti_testmode) COMMAND_HANDLER(handle_cti_write) { struct arm_cti_object *obj = CMD_DATA; - Jim_Interp *interp = CMD_CTX->interp; struct arm_cti *cti = &obj->cti; int offset; uint32_t value; - if (CMD_ARGC != 2) { - Jim_SetResultString(interp, "Wrong number of args", -1); - return ERROR_FAIL; - } + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; offset = cti_find_reg_offset(CMD_ARGV[0]); if (offset < 0) @@ -317,16 +308,13 @@ COMMAND_HANDLER(handle_cti_write) COMMAND_HANDLER(handle_cti_read) { struct arm_cti_object *obj = CMD_DATA; - Jim_Interp *interp = CMD_CTX->interp; struct arm_cti *cti = &obj->cti; int offset; int retval; uint32_t value; - if (CMD_ARGC != 1) { - Jim_SetResultString(interp, "Wrong number of args", -1); - return ERROR_FAIL; - } + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; offset = cti_find_reg_offset(CMD_ARGV[0]); if (offset < 0) @@ -341,6 +329,59 @@ COMMAND_HANDLER(handle_cti_read) return ERROR_OK; } +COMMAND_HANDLER(handle_cti_ack) +{ + struct arm_cti_object *obj = CMD_DATA; + struct arm_cti *cti = &obj->cti; + uint32_t event; + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], event); + + int retval = arm_cti_ack_events(cti, 1 << event); + + + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_cti_channel) +{ + struct arm_cti_object *obj = CMD_DATA; + struct arm_cti *cti = &obj->cti; + int retval = ERROR_OK; + uint32_t ch_num; + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], ch_num); + + if (!strcmp(CMD_ARGV[1], "gate")) + retval = arm_cti_gate_channel(cti, ch_num); + else if (!strcmp(CMD_ARGV[1], "ungate")) + retval = arm_cti_ungate_channel(cti, ch_num); + else if (!strcmp(CMD_ARGV[1], "pulse")) + retval = arm_cti_pulse_channel(cti, ch_num); + else if (!strcmp(CMD_ARGV[1], "set")) + retval = arm_cti_set_channel(cti, ch_num); + else if (!strcmp(CMD_ARGV[1], "clear")) + retval = arm_cti_clear_channel(cti, ch_num); + else { + command_print(CMD, "Possible channel operations: gate|ungate|set|clear|pulse"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + static const struct command_registration cti_instance_command_handlers[] = { { .name = "dump", @@ -377,6 +418,21 @@ static const struct command_registration cti_instance_command_handlers[] = { .help = "read a CTI register", .usage = "register_name", }, + { + .name = "ack", + .mode = COMMAND_EXEC, + .handler = handle_cti_ack, + .help = "acknowledge a CTI event", + .usage = "event", + }, + { + .name = "channel", + .mode = COMMAND_EXEC, + .handler = handle_cti_channel, + .help = "do an operation on one CTI channel, possible operations: " + "gate, ungate, set, clear and pulse", + .usage = "channel_number operation", + }, COMMAND_REGISTRATION_DONE }; @@ -585,4 +641,3 @@ int cti_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, cti_command_handlers); } - diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c index fbcfe0d..56442f1 100644 --- a/src/target/arm_dap.c +++ b/src/target/arm_dap.c @@ -34,7 +34,7 @@ static LIST_HEAD(all_dap); extern const struct dap_ops swd_dap_ops; extern const struct dap_ops jtag_dp_ops; -extern struct jtag_interface *jtag_interface; +extern struct adapter_driver *adapter_driver; /* DAP command support */ struct arm_dap_object { @@ -59,6 +59,7 @@ static void dap_instance_init(struct adiv5_dap *dap) dap->ap[i].csw_default = CSW_AHB_DEFAULT; } INIT_LIST_HEAD(&dap->cmd_journal); + INIT_LIST_HEAD(&dap->cmd_pool); } const char *adiv5_dap_name(struct adiv5_dap *self) @@ -117,7 +118,11 @@ static int dap_init_all(void) if (transport_is_swd()) { dap->ops = &swd_dap_ops; - obj->swd = jtag_interface->swd; + obj->swd = adapter_driver->swd_ops; + } else if (transport_is_dapdirect_swd()) { + dap->ops = adapter_driver->dap_swd_ops; + } else if (transport_is_dapdirect_jtag()) { + dap->ops = adapter_driver->dap_jtag_ops; } else dap->ops = &jtag_dp_ops; diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c index 8eb8194..da8aee2 100644 --- a/src/target/arm_disassembler.c +++ b/src/target/arm_disassembler.c @@ -2086,7 +2086,7 @@ static int evaluate_b_bl_blx_thumb(uint16_t opcode, break; /* BL/BLX prefix */ case 2: - instruction->type = ARM_UNKNOWN_INSTUCTION; + instruction->type = ARM_UNKNOWN_INSTRUCTION; mnemonic = "prefix"; target_address = offset << 12; break; @@ -2309,7 +2309,6 @@ static int evaluate_data_proc_thumb(uint16_t opcode, address, opcode); } return ERROR_OK; - break; } } else { switch (op) { @@ -2673,7 +2672,7 @@ static int evaluate_load_store_multiple_thumb(uint16_t opcode, instruction->type = ARM_STM; mnemonic = "STM"; } - snprintf(ptr_name, sizeof ptr_name, "r%i%s, ", Rn, wback); + snprintf(ptr_name, sizeof(ptr_name), "r%i%s, ", Rn, wback); } else {/* push/pop */ Rn = 13;/* SP */ if (L) { diff --git a/src/target/arm_disassembler.h b/src/target/arm_disassembler.h index e9f4d44..486e903 100644 --- a/src/target/arm_disassembler.h +++ b/src/target/arm_disassembler.h @@ -20,7 +20,7 @@ #define OPENOCD_TARGET_ARM_DISASSEMBLER_H enum arm_instruction_type { - ARM_UNKNOWN_INSTUCTION, + ARM_UNKNOWN_INSTRUCTION, /* Branch instructions */ ARM_B, diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index 8b99570..72215f9 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -145,6 +145,9 @@ static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum) retval = dpm->instr_read_data_r0(dpm, ARMV4_5_VMOV(1, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4), ((regnum - ARM_VFP_V3_D0) & 0xf)), &value_r0); + if (retval != ERROR_OK) + break; + /* read r1 via dcc */ retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, 1, 0, 5, 0), @@ -209,7 +212,6 @@ int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) break; case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: return dpm_read_reg_u64(dpm, r, regnum); - break; case ARM_VFP_V3_FPSCR: /* "VMRS r0, FPSCR"; then return via DCC */ retval = dpm->instr_read_data_r0(dpm, @@ -248,6 +250,9 @@ static int dpm_write_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, 1, 0, 5, 0), value_r1); + if (retval != ERROR_OK) + break; + /* write value_r0 to r0 via dcc then, * move to double word register from r0:r1: "vmov vm, r0, r1" */ @@ -288,7 +293,6 @@ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) break; case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: return dpm_write_reg_u64(dpm, r, regnum); - break; case ARM_VFP_V3_FPSCR: /* move to r0 from DCC, then "VMSR FPSCR, r0" */ retval = dpm->instr_write_data_r0(dpm, @@ -1092,10 +1096,11 @@ int arm_dpm_setup(struct arm_dpm *dpm) dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf); dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf); - dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp); - dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp); + dpm->dbp = calloc(dpm->nbp, sizeof(*dpm->dbp)); + dpm->dwp = calloc(dpm->nwp, sizeof(*dpm->dwp)); if (!dpm->dbp || !dpm->dwp) { + arm_free_reg_cache(arm); free(dpm->dbp); free(dpm->dwp); return ERROR_FAIL; diff --git a/src/target/arm_jtag.c b/src/target/arm_jtag.c index 9b73d4e..49aca34 100644 --- a/src/target/arm_jtag.c +++ b/src/target/arm_jtag.c @@ -33,7 +33,7 @@ int arm_jtag_set_instr_inner(struct jtag_tap *tap, uint32_t new_instr, void *no_verify_capture, tap_state_t end_state) { struct scan_field field; - uint8_t t[4]; + uint8_t t[4] = { 0 }; field.num_bits = tap->ir_length; field.out_value = t; @@ -56,7 +56,7 @@ int arm_jtag_scann_inner(struct arm_jtag *jtag_info, uint32_t new_scan_chain, ta { int retval = ERROR_OK; - uint8_t out_value[4]; + uint8_t out_value[4] = { 0 }; buf_set_u32(out_value, 0, jtag_info->scann_size, new_scan_chain); struct scan_field field = { .num_bits = jtag_info->scann_size, .out_value = out_value, }; diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 53a6b22..58bc339 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -48,6 +48,7 @@ enum { ARMV4_5_SPSR_ABT = 35, ARMV4_5_SPSR_UND = 36, ARM_SPSR_MON = 41, + ARM_SPSR_HYP = 43, }; static const uint8_t arm_usr_indices[17] = { @@ -78,6 +79,10 @@ static const uint8_t arm_mon_indices[3] = { 39, 40, ARM_SPSR_MON, }; +static const uint8_t arm_hyp_indices[2] = { + 42, ARM_SPSR_HYP, +}; + static const struct { const char *name; unsigned short psr; @@ -163,6 +168,14 @@ static const struct { .name = "Handler", .psr = ARM_MODE_HANDLER, }, + + /* armv7-a with virtualization extension */ + { + .name = "Hypervisor", + .psr = ARM_MODE_HYP, + .n_indices = ARRAY_SIZE(arm_hyp_indices), + .indices = arm_hyp_indices, + }, }; /** Map PSR mode bits to the name of an ARM processor operating mode. */ @@ -209,6 +222,8 @@ int arm_mode_to_number(enum arm_mode mode) case ARM_MODE_MON: case ARM_MODE_1176_MON: return 7; + case ARM_MODE_HYP: + return 8; default: LOG_ERROR("invalid mode value encountered %d", mode); return -1; @@ -235,6 +250,8 @@ enum arm_mode armv4_5_number_to_mode(int number) return ARM_MODE_SYS; case 7: return ARM_MODE_MON; + case 8: + return ARM_MODE_HYP; default: LOG_ERROR("mode index out of bounds %d", number); return ARM_MODE_ANY; @@ -274,24 +291,24 @@ static const struct { * correspond to r0..r7, and the fifteenth to PC, so that callers * don't need to map them. */ - { .name = "r0", .cookie = 0, .mode = ARM_MODE_ANY, .gdb_index = 0, }, - { .name = "r1", .cookie = 1, .mode = ARM_MODE_ANY, .gdb_index = 1, }, - { .name = "r2", .cookie = 2, .mode = ARM_MODE_ANY, .gdb_index = 2, }, - { .name = "r3", .cookie = 3, .mode = ARM_MODE_ANY, .gdb_index = 3, }, - { .name = "r4", .cookie = 4, .mode = ARM_MODE_ANY, .gdb_index = 4, }, - { .name = "r5", .cookie = 5, .mode = ARM_MODE_ANY, .gdb_index = 5, }, - { .name = "r6", .cookie = 6, .mode = ARM_MODE_ANY, .gdb_index = 6, }, - { .name = "r7", .cookie = 7, .mode = ARM_MODE_ANY, .gdb_index = 7, }, + [0] = { .name = "r0", .cookie = 0, .mode = ARM_MODE_ANY, .gdb_index = 0, }, + [1] = { .name = "r1", .cookie = 1, .mode = ARM_MODE_ANY, .gdb_index = 1, }, + [2] = { .name = "r2", .cookie = 2, .mode = ARM_MODE_ANY, .gdb_index = 2, }, + [3] = { .name = "r3", .cookie = 3, .mode = ARM_MODE_ANY, .gdb_index = 3, }, + [4] = { .name = "r4", .cookie = 4, .mode = ARM_MODE_ANY, .gdb_index = 4, }, + [5] = { .name = "r5", .cookie = 5, .mode = ARM_MODE_ANY, .gdb_index = 5, }, + [6] = { .name = "r6", .cookie = 6, .mode = ARM_MODE_ANY, .gdb_index = 6, }, + [7] = { .name = "r7", .cookie = 7, .mode = ARM_MODE_ANY, .gdb_index = 7, }, /* NOTE: regs 8..12 might be shadowed by FIQ ... flagging * them as MODE_ANY creates special cases. (ANY means * "not mapped" elsewhere; here it's "everything but FIQ".) */ - { .name = "r8", .cookie = 8, .mode = ARM_MODE_ANY, .gdb_index = 8, }, - { .name = "r9", .cookie = 9, .mode = ARM_MODE_ANY, .gdb_index = 9, }, - { .name = "r10", .cookie = 10, .mode = ARM_MODE_ANY, .gdb_index = 10, }, - { .name = "r11", .cookie = 11, .mode = ARM_MODE_ANY, .gdb_index = 11, }, - { .name = "r12", .cookie = 12, .mode = ARM_MODE_ANY, .gdb_index = 12, }, + [8] = { .name = "r8", .cookie = 8, .mode = ARM_MODE_ANY, .gdb_index = 8, }, + [9] = { .name = "r9", .cookie = 9, .mode = ARM_MODE_ANY, .gdb_index = 9, }, + [10] = { .name = "r10", .cookie = 10, .mode = ARM_MODE_ANY, .gdb_index = 10, }, + [11] = { .name = "r11", .cookie = 11, .mode = ARM_MODE_ANY, .gdb_index = 11, }, + [12] = { .name = "r12", .cookie = 12, .mode = ARM_MODE_ANY, .gdb_index = 12, }, /* Historical GDB mapping of indices: * - 13-14 are sp and lr, but banked counterparts are used @@ -300,48 +317,51 @@ static const struct { */ /* NOTE all MODE_USR registers are equivalent to MODE_SYS ones */ - { .name = "sp_usr", .cookie = 13, .mode = ARM_MODE_USR, .gdb_index = 26, }, - { .name = "lr_usr", .cookie = 14, .mode = ARM_MODE_USR, .gdb_index = 27, }, + [13] = { .name = "sp_usr", .cookie = 13, .mode = ARM_MODE_USR, .gdb_index = 26, }, + [14] = { .name = "lr_usr", .cookie = 14, .mode = ARM_MODE_USR, .gdb_index = 27, }, /* guaranteed to be at index 15 */ - { .name = "pc", .cookie = 15, .mode = ARM_MODE_ANY, .gdb_index = 15, }, - { .name = "r8_fiq", .cookie = 8, .mode = ARM_MODE_FIQ, .gdb_index = 28, }, - { .name = "r9_fiq", .cookie = 9, .mode = ARM_MODE_FIQ, .gdb_index = 29, }, - { .name = "r10_fiq", .cookie = 10, .mode = ARM_MODE_FIQ, .gdb_index = 30, }, - { .name = "r11_fiq", .cookie = 11, .mode = ARM_MODE_FIQ, .gdb_index = 31, }, - { .name = "r12_fiq", .cookie = 12, .mode = ARM_MODE_FIQ, .gdb_index = 32, }, + [15] = { .name = "pc", .cookie = 15, .mode = ARM_MODE_ANY, .gdb_index = 15, }, + [16] = { .name = "r8_fiq", .cookie = 8, .mode = ARM_MODE_FIQ, .gdb_index = 28, }, + [17] = { .name = "r9_fiq", .cookie = 9, .mode = ARM_MODE_FIQ, .gdb_index = 29, }, + [18] = { .name = "r10_fiq", .cookie = 10, .mode = ARM_MODE_FIQ, .gdb_index = 30, }, + [19] = { .name = "r11_fiq", .cookie = 11, .mode = ARM_MODE_FIQ, .gdb_index = 31, }, + [20] = { .name = "r12_fiq", .cookie = 12, .mode = ARM_MODE_FIQ, .gdb_index = 32, }, - { .name = "sp_fiq", .cookie = 13, .mode = ARM_MODE_FIQ, .gdb_index = 33, }, - { .name = "lr_fiq", .cookie = 14, .mode = ARM_MODE_FIQ, .gdb_index = 34, }, + [21] = { .name = "sp_fiq", .cookie = 13, .mode = ARM_MODE_FIQ, .gdb_index = 33, }, + [22] = { .name = "lr_fiq", .cookie = 14, .mode = ARM_MODE_FIQ, .gdb_index = 34, }, - { .name = "sp_irq", .cookie = 13, .mode = ARM_MODE_IRQ, .gdb_index = 35, }, - { .name = "lr_irq", .cookie = 14, .mode = ARM_MODE_IRQ, .gdb_index = 36, }, + [23] = { .name = "sp_irq", .cookie = 13, .mode = ARM_MODE_IRQ, .gdb_index = 35, }, + [24] = { .name = "lr_irq", .cookie = 14, .mode = ARM_MODE_IRQ, .gdb_index = 36, }, - { .name = "sp_svc", .cookie = 13, .mode = ARM_MODE_SVC, .gdb_index = 37, }, - { .name = "lr_svc", .cookie = 14, .mode = ARM_MODE_SVC, .gdb_index = 38, }, + [25] = { .name = "sp_svc", .cookie = 13, .mode = ARM_MODE_SVC, .gdb_index = 37, }, + [26] = { .name = "lr_svc", .cookie = 14, .mode = ARM_MODE_SVC, .gdb_index = 38, }, - { .name = "sp_abt", .cookie = 13, .mode = ARM_MODE_ABT, .gdb_index = 39, }, - { .name = "lr_abt", .cookie = 14, .mode = ARM_MODE_ABT, .gdb_index = 40, }, + [27] = { .name = "sp_abt", .cookie = 13, .mode = ARM_MODE_ABT, .gdb_index = 39, }, + [28] = { .name = "lr_abt", .cookie = 14, .mode = ARM_MODE_ABT, .gdb_index = 40, }, - { .name = "sp_und", .cookie = 13, .mode = ARM_MODE_UND, .gdb_index = 41, }, - { .name = "lr_und", .cookie = 14, .mode = ARM_MODE_UND, .gdb_index = 42, }, + [29] = { .name = "sp_und", .cookie = 13, .mode = ARM_MODE_UND, .gdb_index = 41, }, + [30] = { .name = "lr_und", .cookie = 14, .mode = ARM_MODE_UND, .gdb_index = 42, }, - { .name = "cpsr", .cookie = 16, .mode = ARM_MODE_ANY, .gdb_index = 25, }, - { .name = "spsr_fiq", .cookie = 16, .mode = ARM_MODE_FIQ, .gdb_index = 43, }, - { .name = "spsr_irq", .cookie = 16, .mode = ARM_MODE_IRQ, .gdb_index = 44, }, - { .name = "spsr_svc", .cookie = 16, .mode = ARM_MODE_SVC, .gdb_index = 45, }, - { .name = "spsr_abt", .cookie = 16, .mode = ARM_MODE_ABT, .gdb_index = 46, }, - { .name = "spsr_und", .cookie = 16, .mode = ARM_MODE_UND, .gdb_index = 47, }, + [31] = { .name = "cpsr", .cookie = 16, .mode = ARM_MODE_ANY, .gdb_index = 25, }, + [32] = { .name = "spsr_fiq", .cookie = 16, .mode = ARM_MODE_FIQ, .gdb_index = 43, }, + [33] = { .name = "spsr_irq", .cookie = 16, .mode = ARM_MODE_IRQ, .gdb_index = 44, }, + [34] = { .name = "spsr_svc", .cookie = 16, .mode = ARM_MODE_SVC, .gdb_index = 45, }, + [35] = { .name = "spsr_abt", .cookie = 16, .mode = ARM_MODE_ABT, .gdb_index = 46, }, + [36] = { .name = "spsr_und", .cookie = 16, .mode = ARM_MODE_UND, .gdb_index = 47, }, /* These are only used for GDB target description, banked registers are accessed instead */ - { .name = "sp", .cookie = 13, .mode = ARM_MODE_ANY, .gdb_index = 13, }, - { .name = "lr", .cookie = 14, .mode = ARM_MODE_ANY, .gdb_index = 14, }, + [37] = { .name = "sp", .cookie = 13, .mode = ARM_MODE_ANY, .gdb_index = 13, }, + [38] = { .name = "lr", .cookie = 14, .mode = ARM_MODE_ANY, .gdb_index = 14, }, /* These exist only when the Security Extension (TrustZone) is present */ - { .name = "sp_mon", .cookie = 13, .mode = ARM_MODE_MON, .gdb_index = 48, }, - { .name = "lr_mon", .cookie = 14, .mode = ARM_MODE_MON, .gdb_index = 49, }, - { .name = "spsr_mon", .cookie = 16, .mode = ARM_MODE_MON, .gdb_index = 50, }, + [39] = { .name = "sp_mon", .cookie = 13, .mode = ARM_MODE_MON, .gdb_index = 48, }, + [40] = { .name = "lr_mon", .cookie = 14, .mode = ARM_MODE_MON, .gdb_index = 49, }, + [41] = { .name = "spsr_mon", .cookie = 16, .mode = ARM_MODE_MON, .gdb_index = 50, }, + /* These exist only when the Virtualization Extensions is present */ + [42] = { .name = "sp_hyp", .cookie = 13, .mode = ARM_MODE_HYP, .gdb_index = 51, }, + [43] = { .name = "spsr_hyp", .cookie = 16, .mode = ARM_MODE_HYP, .gdb_index = 52, }, }; static const struct { @@ -391,7 +411,7 @@ static const struct { /* map core mode (USR, FIQ, ...) and register number to * indices into the register cache */ -const int armv4_5_core_reg_map[8][17] = { +const int armv4_5_core_reg_map[9][17] = { { /* USR */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31 }, @@ -414,7 +434,10 @@ const int armv4_5_core_reg_map[8][17] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31 }, { /* MON */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 37, 38, 15, 39, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 39, 40, 15, 41, + }, + { /* HYP */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 42, 14, 15, 43, } }; @@ -658,7 +681,11 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) for (i = 0; i < num_core_regs; i++) { /* Skip registers this core doesn't expose */ if (arm_core_regs[i].mode == ARM_MODE_MON - && arm->core_type != ARM_MODE_MON) + && arm->core_type != ARM_CORE_TYPE_SEC_EXT + && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) + continue; + if (arm_core_regs[i].mode == ARM_MODE_HYP + && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) continue; /* REVISIT handle Cortex-M, which only shadows R13/SP */ @@ -742,6 +769,27 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) return cache; } +void arm_free_reg_cache(struct arm *arm) +{ + if (!arm || !arm->core_cache) + return; + + struct reg_cache *cache = arm->core_cache; + + for (unsigned int i = 0; i < cache->num_regs; i++) { + struct reg *reg = &cache->reg_list[i]; + + free(reg->feature); + free(reg->reg_data_type); + } + + free(cache->reg_list[0].arch_info); + free(cache->reg_list); + free(cache); + + arm->core_cache = NULL; +} + int arm_arch_state(struct target *target) { struct arm *arm = target_to_arm(target); @@ -768,9 +816,6 @@ int arm_arch_state(struct target *target) return ERROR_OK; } -#define ARMV4_5_CORE_REG_MODENUM(cache, mode, num) \ - (cache->reg_list[armv4_5_core_reg_map[mode][num]]) - COMMAND_HANDLER(handle_armv4_5_reg_command) { struct target *target = get_current_target(CMD_CTX); @@ -787,7 +832,7 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) return ERROR_FAIL; } - if (arm->core_type != ARM_MODE_ANY) { + if (arm->core_type != ARM_CORE_TYPE_STD) { command_print(CMD, "Microcontroller Profile not supported - use standard reg cmd"); return ERROR_OK; @@ -819,8 +864,13 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) name = "System and User"; sep = ""; break; + case ARM_MODE_HYP: + if (arm->core_type != ARM_CORE_TYPE_VIRT_EXT) + continue; + /* FALLTHROUGH */ case ARM_MODE_MON: - if (arm->core_type != ARM_MODE_MON) + if (arm->core_type != ARM_CORE_TYPE_SEC_EXT + && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) continue; /* FALLTHROUGH */ default: @@ -872,7 +922,7 @@ COMMAND_HANDLER(handle_armv4_5_core_state_command) return ERROR_FAIL; } - if (arm->core_type == ARM_MODE_THREAD) { + if (arm->core_type == ARM_CORE_TYPE_M_PROFILE) { /* armv7m not supported */ command_print(CMD, "Unsupported Command"); return ERROR_OK; @@ -910,7 +960,7 @@ COMMAND_HANDLER(handle_arm_disassemble_command) return ERROR_FAIL; } - if (arm->core_type == ARM_MODE_THREAD) { + if (arm->core_type == ARM_CORE_TYPE_M_PROFILE) { /* armv7m is always thumb mode */ thumb = 1; } @@ -1098,10 +1148,7 @@ static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) return JIM_OK; } -extern __COMMAND_HANDLER(handle_common_semihosting_command); -extern __COMMAND_HANDLER(handle_common_semihosting_fileio_command); -extern __COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command); -extern __COMMAND_HANDLER(handle_common_semihosting_cmdline); +extern const struct command_registration semihosting_common_handlers[]; static const struct command_registration arm_exec_command_handlers[] = { { @@ -1140,32 +1187,7 @@ static const struct command_registration arm_exec_command_handlers[] = { .usage = "cpnum op1 CRn CRm op2", }, { - .name = "semihosting", - .handler = handle_common_semihosting_command, - .mode = COMMAND_EXEC, - .usage = "['enable'|'disable']", - .help = "activate support for semihosting operations", - }, - { - .name = "semihosting_cmdline", - .handler = handle_common_semihosting_cmdline, - .mode = COMMAND_EXEC, - .usage = "arguments", - .help = "command line arguments to be passed to program", - }, - { - .name = "semihosting_fileio", - .handler = handle_common_semihosting_fileio_command, - .mode = COMMAND_EXEC, - .usage = "['enable'|'disable']", - .help = "activate support for semihosting fileio operations", - }, - { - .name = "semihosting_resexit", - .handler = handle_common_semihosting_resumable_exit_command, - .mode = COMMAND_EXEC, - .usage = "['enable'|'disable']", - .help = "activate support for semihosting resumable exit", + .chain = semihosting_common_handlers, }, COMMAND_REGISTRATION_DONE }; @@ -1222,10 +1244,18 @@ int arm_get_gdb_reg_list(struct target *target, (*reg_list)[25] = arm->cpsr; return ERROR_OK; - break; case REG_CLASS_ALL: - *reg_list_size = (arm->core_type != ARM_MODE_MON ? 48 : 51); + switch (arm->core_type) { + case ARM_CORE_TYPE_SEC_EXT: + *reg_list_size = 51; + break; + case ARM_CORE_TYPE_VIRT_EXT: + *reg_list_size = 53; + break; + default: + *reg_list_size = 48; + } unsigned int list_size_core = *reg_list_size; if (arm->arm_vfp_version == ARM_VFP_V3) *reg_list_size += 33; @@ -1237,9 +1267,15 @@ int arm_get_gdb_reg_list(struct target *target, for (i = 13; i < ARRAY_SIZE(arm_core_regs); i++) { int reg_index = arm->core_cache->reg_list[i].number; - if (!(arm_core_regs[i].mode == ARM_MODE_MON - && arm->core_type != ARM_MODE_MON)) - (*reg_list)[reg_index] = &(arm->core_cache->reg_list[i]); + + if (arm_core_regs[i].mode == ARM_MODE_MON + && arm->core_type != ARM_CORE_TYPE_SEC_EXT + && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) + continue; + if (arm_core_regs[i].mode == ARM_MODE_HYP + && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) + continue; + (*reg_list)[reg_index] = &(arm->core_cache->reg_list[i]); } /* When we supply the target description, there is no need for fake FPA */ @@ -1257,12 +1293,10 @@ int arm_get_gdb_reg_list(struct target *target, } return ERROR_OK; - break; default: LOG_ERROR("not a valid register class type in query."); return ERROR_FAIL; - break; } } @@ -1701,8 +1735,8 @@ int arm_init_arch_info(struct target *target, struct arm *arm) arm->common_magic = ARM_COMMON_MAGIC; /* core_type may be overridden by subtype logic */ - if (arm->core_type != ARM_MODE_THREAD) { - arm->core_type = ARM_MODE_ANY; + if (arm->core_type != ARM_CORE_TYPE_M_PROFILE) { + arm->core_type = ARM_CORE_TYPE_STD; arm_set_cpsr(arm, ARM_MODE_USR); } diff --git a/src/target/armv4_5.h b/src/target/armv4_5.h index 3ce4ed0..bef1cfe 100644 --- a/src/target/armv4_5.h +++ b/src/target/armv4_5.h @@ -38,7 +38,7 @@ int arm_mode_to_number(enum arm_mode mode); enum arm_mode armv4_5_number_to_mode(int number); -extern const int armv4_5_core_reg_map[8][17]; +extern const int armv4_5_core_reg_map[9][17]; #define ARMV4_5_CORE_REG_MODE(cache, mode, num) \ (cache->reg_list[armv4_5_core_reg_map[arm_mode_to_number(mode)][num]]) diff --git a/src/target/armv7a.h b/src/target/armv7a.h index 0ef04c1..3d88c86 100644 --- a/src/target/armv7a.h +++ b/src/target/armv7a.h @@ -178,6 +178,9 @@ static inline bool is_armv7a(struct armv7a_common *armv7a) /* See ARMv7a arch spec section C10.8 */ #define CPUDBG_AUTHSTATUS 0xFB8 +/* See ARMv7a arch spec DDI 0406C C11.10 */ +#define CPUDBG_ID_PFR1 0xD24 + /* Masks for Vector Catch register */ #define DBG_VCR_FIQ_MASK ((1 << 31) | (1 << 7)) #define DBG_VCR_IRQ_MASK ((1 << 30) | (1 << 6)) diff --git a/src/target/armv7a_mmu.c b/src/target/armv7a_mmu.c index f83228d..eec14a3 100644 --- a/src/target/armv7a_mmu.c +++ b/src/target/armv7a_mmu.c @@ -62,12 +62,6 @@ int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va, /* decode memory attribute */ SS = (value >> 1) & 1; -#if !BUILD_TARGET64 - if (SS) { - LOG_ERROR("Super section found with no-64 bit address support"); - return ERROR_FAIL; - } -#endif NOS = (value >> 10) & 1; /* Not Outer shareable */ NS = (value >> 9) & 1; /* Non secure */ INNER = (value >> 4) & 0x7; diff --git a/src/target/armv7m.c b/src/target/armv7m.c index 4b37774..017d693 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -301,20 +301,22 @@ int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { struct armv7m_common *armv7m = target_to_armv7m(target); - int i; + int i, size; if (reg_class == REG_CLASS_ALL) - *reg_list_size = armv7m->arm.core_cache->num_regs; + size = armv7m->arm.core_cache->num_regs; else - *reg_list_size = ARMV7M_NUM_CORE_REGS; + size = ARMV7M_NUM_CORE_REGS; - *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); + *reg_list = malloc(sizeof(struct reg *) * size); if (*reg_list == NULL) return ERROR_FAIL; - for (i = 0; i < *reg_list_size; i++) + for (i = 0; i < size; i++) (*reg_list)[i] = &armv7m->arm.core_cache->reg_list[i]; + *reg_list_size = size; + return ERROR_OK; } @@ -462,7 +464,6 @@ int armv7m_wait_algorithm(struct target *target, struct armv7m_common *armv7m = target_to_armv7m(target); struct armv7m_algorithm *armv7m_algorithm_info = arch_info; int retval = ERROR_OK; - uint32_t pc; /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint * at the exit point */ @@ -484,12 +485,14 @@ int armv7m_wait_algorithm(struct target *target, return ERROR_TARGET_TIMEOUT; } - armv7m->load_core_reg_u32(target, 15, &pc); - if (exit_point && (pc != exit_point)) { - LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" TARGET_PRIxADDR, - pc, - exit_point); - return ERROR_TARGET_TIMEOUT; + if (exit_point) { + /* PC value has been cached in cortex_m_debug_entry() */ + uint32_t pc = buf_get_u32(armv7m->arm.pc->value, 0, 32); + if (pc != exit_point) { + LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" TARGET_PRIxADDR, + pc, exit_point); + return ERROR_TARGET_ALGO_EXIT; + } } /* Read memory values to mem_params[] */ @@ -695,7 +698,7 @@ int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m) /* Enable stimulus port #0 by default */ armv7m->trace_config.itm_ter[0] = 1; - arm->core_type = ARM_MODE_THREAD; + arm->core_type = ARM_CORE_TYPE_M_PROFILE; arm->arch_info = armv7m; arm->setup_semihosting = armv7m_setup_semihosting; diff --git a/src/target/armv7m_trace.c b/src/target/armv7m_trace.c index 6170119..6b368f7 100644 --- a/src/target/armv7m_trace.c +++ b/src/target/armv7m_trace.c @@ -56,41 +56,39 @@ int armv7m_trace_tpiu_config(struct target *target) { struct armv7m_common *armv7m = target_to_armv7m(target); struct armv7m_trace_config *trace_config = &armv7m->trace_config; - int prescaler; + uint16_t prescaler; int retval; target_unregister_timer_callback(armv7m_poll_trace, target); - retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL, - trace_config->pin_protocol, - trace_config->port_size, - &trace_config->trace_freq); + trace_config->pin_protocol, trace_config->port_size, + &trace_config->trace_freq, trace_config->traceclkin_freq, &prescaler); + if (retval != ERROR_OK) return retval; + if (trace_config->config_type == TRACE_CONFIG_TYPE_EXTERNAL) { + prescaler = trace_config->traceclkin_freq / trace_config->trace_freq; + + if (trace_config->traceclkin_freq % trace_config->trace_freq) { + prescaler++; + + int trace_freq = trace_config->traceclkin_freq / prescaler; + LOG_INFO("Can not obtain %u trace port frequency from %u " + "TRACECLKIN frequency, using %u instead", + trace_config->trace_freq, trace_config->traceclkin_freq, + trace_freq); + + trace_config->trace_freq = trace_freq; + } + } + if (!trace_config->trace_freq) { LOG_ERROR("Trace port frequency is 0, can't enable TPIU"); return ERROR_FAIL; } - prescaler = trace_config->traceclkin_freq / trace_config->trace_freq; - - if (trace_config->traceclkin_freq % trace_config->trace_freq) { - prescaler++; - int trace_freq = trace_config->traceclkin_freq / prescaler; - LOG_INFO("Can not obtain %u trace port frequency from %u TRACECLKIN frequency, using %u instead", - trace_config->trace_freq, trace_config->traceclkin_freq, - trace_freq); - trace_config->trace_freq = trace_freq; - retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL, - trace_config->pin_protocol, - trace_config->port_size, - &trace_config->trace_freq); - if (retval != ERROR_OK) - return retval; - } - retval = target_write_u32(target, TPIU_CSPSR, 1 << trace_config->port_size); if (retval != ERROR_OK) return retval; diff --git a/src/target/armv8.c b/src/target/armv8.c index e736937..61f11f2 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -1131,8 +1131,9 @@ int armv8_aarch64_state(struct target *target) return ERROR_FAIL; } - LOG_USER("target halted in %s state due to %s, current mode: %s\n" + LOG_USER("%s halted in %s state due to %s, current mode: %s\n" "cpsr: 0x%8.8" PRIx32 " pc: 0x%" PRIx64 "%s", + target_name(target), armv8_state_strings[arm->core_state], debug_reason_name(target), armv8_mode_name(arm->core_mode), @@ -1753,7 +1754,8 @@ const struct command_registration armv8_command_handlers[] = { const char *armv8_get_gdb_arch(struct target *target) { - return "aarch64"; + struct arm *arm = target_to_arm(target); + return arm->core_state == ARM_STATE_AARCH64 ? "aarch64" : "arm"; } int armv8_get_gdb_reg_list(struct target *target, diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index 081eed2..a3edb7f 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -681,6 +681,10 @@ static int dpmv8_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) LOG_DEBUG("READ: %s, hvalue=%16.8llx", r->name, (unsigned long long) hvalue); } } + + if (retval != ERROR_OK) + LOG_ERROR("Failed to read %s register", r->name); + return retval; } @@ -720,6 +724,9 @@ static int dpmv8_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) } } + if (retval != ERROR_OK) + LOG_ERROR("Failed to write %s register", r->name); + return retval; } @@ -1464,10 +1471,10 @@ int armv8_dpm_setup(struct arm_dpm *dpm) /* FIXME add vector catch support */ dpm->nbp = 1 + ((dpm->didr >> 12) & 0xf); - dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp); + dpm->dbp = calloc(dpm->nbp, sizeof(*dpm->dbp)); dpm->nwp = 1 + ((dpm->didr >> 20) & 0xf); - dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp); + dpm->dwp = calloc(dpm->nwp, sizeof(*dpm->dwp)); if (!dpm->dbp || !dpm->dwp) { free(dpm->dbp); diff --git a/src/target/armv8_opcodes.c b/src/target/armv8_opcodes.c index 6887b29..96db728 100644 --- a/src/target/armv8_opcodes.c +++ b/src/target/armv8_opcodes.c @@ -68,13 +68,13 @@ static const uint32_t t32_opcodes[ARMV8_OPC_NUM] = { [ARMV8_OPC_DCCISW] = ARMV4_5_MCR(15, 0, 0, 7, 14, 2), [ARMV8_OPC_DCCIVAC] = ARMV4_5_MCR(15, 0, 0, 7, 14, 1), [ARMV8_OPC_ICIVAU] = ARMV4_5_MCR(15, 0, 0, 7, 5, 1), - [ARMV8_OPC_HLT] = ARMV8_HLT_A1(11), - [ARMV8_OPC_LDRB_IP] = ARMV4_5_LDRB_IP(1, 0), - [ARMV8_OPC_LDRH_IP] = ARMV4_5_LDRH_IP(1, 0), - [ARMV8_OPC_LDRW_IP] = ARMV4_5_LDRW_IP(1, 0), - [ARMV8_OPC_STRB_IP] = ARMV4_5_STRB_IP(1, 0), - [ARMV8_OPC_STRH_IP] = ARMV4_5_STRH_IP(1, 0), - [ARMV8_OPC_STRW_IP] = ARMV4_5_STRW_IP(1, 0), + [ARMV8_OPC_HLT] = ARMV8_HLT_T1(11), + [ARMV8_OPC_LDRB_IP] = ARMV8_LDRB_IP_T3(1, 0), + [ARMV8_OPC_LDRH_IP] = ARMV8_LDRH_IP_T3(1, 0), + [ARMV8_OPC_LDRW_IP] = ARMV8_LDRW_IP_T3(1, 0), + [ARMV8_OPC_STRB_IP] = ARMV8_STRB_IP_T3(1, 0), + [ARMV8_OPC_STRH_IP] = ARMV8_STRH_IP_T3(1, 0), + [ARMV8_OPC_STRW_IP] = ARMV8_STRW_IP_T3(1, 0), }; void armv8_select_opcodes(struct armv8_common *armv8, bool state_is_aarch64) diff --git a/src/target/armv8_opcodes.h b/src/target/armv8_opcodes.h index 3fda296..239c4c5 100644 --- a/src/target/armv8_opcodes.h +++ b/src/target/armv8_opcodes.h @@ -153,6 +153,7 @@ #define ARMV8_BKPT(Im) (0xD4200000 | ((Im & 0xffff) << 5)) #define ARMV8_HLT(Im) (0x0D4400000 | ((Im & 0xffff) << 5)) #define ARMV8_HLT_A1(Im) (0xE1000070 | ((Im & 0xFFF0) << 4) | (Im & 0xF)) +#define ARMV8_HLT_T1(Im) (0xba80 | (Im & 0x3f)) #define ARMV8_MOVFSP_64(Rt) ((1 << 31) | 0x11000000 | (0x1f << 5) | (Rt)) #define ARMV8_MOVTSP_64(Rt) ((1 << 31) | 0x11000000 | (Rt << 5) | (0x1F)) @@ -163,10 +164,18 @@ #define ARMV8_LDRH_IP(Rd, Rn) (0x78402400 | (Rn << 5) | Rd) #define ARMV8_LDRW_IP(Rd, Rn) (0xb8404400 | (Rn << 5) | Rd) +#define ARMV8_LDRB_IP_T3(Rd, Rn) (0xf8100b01 | (Rn << 16) | (Rd << 12)) +#define ARMV8_LDRH_IP_T3(Rd, Rn) (0xf8300b02 | (Rn << 16) | (Rd << 12)) +#define ARMV8_LDRW_IP_T3(Rd, Rn) (0xf8500b04 | (Rn << 16) | (Rd << 12)) + #define ARMV8_STRB_IP(Rd, Rn) (0x38001400 | (Rn << 5) | Rd) #define ARMV8_STRH_IP(Rd, Rn) (0x78002400 | (Rn << 5) | Rd) #define ARMV8_STRW_IP(Rd, Rn) (0xb8004400 | (Rn << 5) | Rd) +#define ARMV8_STRB_IP_T3(Rd, Rn) (0xf8000b01 | (Rn << 16) | (Rd << 12)) +#define ARMV8_STRH_IP_T3(Rd, Rn) (0xf8200b02 | (Rn << 16) | (Rd << 12)) +#define ARMV8_STRW_IP_T3(Rd, Rn) (0xf8400b04 | (Rn << 16) | (Rd << 12)) + #define ARMV8_MOV_GPR_VFP(Rd, Rn, Index) (0x4e083c00 | (Index << 20) | (Rn << 5) | Rd) #define ARMV8_MOV_VFP_GPR(Rd, Rn, Index) (0x4e081c00 | (Index << 20) | (Rn << 5) | Rd) diff --git a/src/target/avr32_ap7k.c b/src/target/avr32_ap7k.c index cf08e3a..6221059 100644 --- a/src/target/avr32_ap7k.c +++ b/src/target/avr32_ap7k.c @@ -464,7 +464,6 @@ static int avr32_ap7k_read_memory(struct target *target, target_addr_t address, break; case 1: return avr32_jtag_read_memory8(&ap7k->jtag, address, count, buffer); - break; default: break; } @@ -505,7 +504,6 @@ static int avr32_ap7k_write_memory(struct target *target, target_addr_t address, break; case 1: return avr32_jtag_write_memory8(&ap7k->jtag, address, count, buffer); - break; default: break; } diff --git a/src/target/avr32_jtag.c b/src/target/avr32_jtag.c index 6526810..64ebf12 100644 --- a/src/target/avr32_jtag.c +++ b/src/target/avr32_jtag.c @@ -35,7 +35,7 @@ static int avr32_jtag_set_instr(struct avr32_jtag *jtag_info, int new_instr) if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != (uint32_t)new_instr) { do { struct scan_field field; - uint8_t t[4]; + uint8_t t[4] = { 0 }; uint8_t ret[4]; field.num_bits = tap->ir_length; @@ -173,19 +173,15 @@ int avr32_jtag_nexus_read(struct avr32_jtag *jtag_info, { avr32_jtag_set_instr(jtag_info, AVR32_INST_NEXUS_ACCESS); avr32_jtag_nexus_set_address(jtag_info, addr, MODE_READ); - avr32_jtag_nexus_read_data(jtag_info, value); - - return ERROR_OK; - + return avr32_jtag_nexus_read_data(jtag_info, value); } + int avr32_jtag_nexus_write(struct avr32_jtag *jtag_info, uint32_t addr, uint32_t value) { avr32_jtag_set_instr(jtag_info, AVR32_INST_NEXUS_ACCESS); avr32_jtag_nexus_set_address(jtag_info, addr, MODE_WRITE); - avr32_jtag_nexus_write_data(jtag_info, value); - - return ERROR_OK; + return avr32_jtag_nexus_write_data(jtag_info, value); } int avr32_jtag_mwa_set_address(struct avr32_jtag *jtag_info, int slave, @@ -373,4 +369,3 @@ int avr32_ocd_clearbits(struct avr32_jtag *jtag, int reg, uint32_t bits) return ERROR_OK; } - diff --git a/src/target/avrt.c b/src/target/avrt.c index 1e1898c..9cb6f2f 100644 --- a/src/target/avrt.c +++ b/src/target/avrt.c @@ -145,7 +145,7 @@ static int avr_deassert_reset(struct target *target) return ERROR_OK; } -int avr_jtag_senddat(struct jtag_tap *tap, uint32_t* dr_in, uint32_t dr_out, +int avr_jtag_senddat(struct jtag_tap *tap, uint32_t *dr_in, uint32_t dr_out, int len) { return mcu_write_dr_u32(tap, dr_in, dr_out, len, 1); diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index b23b37f..46c9805 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -334,6 +334,18 @@ static int breakpoint_remove_internal(struct target *target, target_addr_t addre return 0; } } + +static void breakpoint_remove_all_internal(struct target *target) +{ + struct breakpoint *breakpoint = target->breakpoints; + + while (breakpoint) { + struct breakpoint *tmp = breakpoint; + breakpoint = breakpoint->next; + breakpoint_free(target, tmp); + } +} + void breakpoint_remove(struct target *target, target_addr_t address) { int found = 0; @@ -352,7 +364,23 @@ void breakpoint_remove(struct target *target, target_addr_t address) breakpoint_remove_internal(target, address); } -void breakpoint_clear_target_internal(struct target *target) +void breakpoint_remove_all(struct target *target) +{ + if (target->smp) { + struct target_list *head; + struct target *curr; + head = target->head; + while (head != (struct target_list *)NULL) { + curr = head->target; + breakpoint_remove_all_internal(curr); + head = head->next; + } + } else { + breakpoint_remove_all_internal(target); + } +} + +static void breakpoint_clear_target_internal(struct target *target) { LOG_DEBUG("Delete all breakpoints for target: %s", target_name(target)); diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h index 51bd05a..20faf4e 100644 --- a/src/target/breakpoints.h +++ b/src/target/breakpoints.h @@ -63,6 +63,7 @@ int context_breakpoint_add(struct target *target, int hybrid_breakpoint_add(struct target *target, target_addr_t address, uint32_t asid, uint32_t length, enum breakpoint_type type); void breakpoint_remove(struct target *target, target_addr_t address); +void breakpoint_remove_all(struct target *target); struct breakpoint *breakpoint_find(struct target *target, target_addr_t address); diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index b3a8a41..f562a76 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -425,22 +425,35 @@ static int cortex_a_instr_write_data_dcc(struct arm_dpm *dpm, &dscr); } -static int cortex_a_instr_write_data_r0(struct arm_dpm *dpm, - uint32_t opcode, uint32_t data) +static int cortex_a_instr_write_data_rt_dcc(struct arm_dpm *dpm, + uint8_t rt, uint32_t data) { struct cortex_a_common *a = dpm_to_a(dpm); uint32_t dscr = DSCR_INSTR_COMP; int retval; + if (rt > 15) + return ERROR_TARGET_INVALID; + retval = cortex_a_write_dcc(a, data); if (retval != ERROR_OK) return retval; - /* DCCRX to R0, "MCR p14, 0, R0, c0, c5, 0", 0xEE000E15 */ - retval = cortex_a_exec_opcode( + /* DCCRX to Rt, "MCR p14, 0, R0, c0, c5, 0", 0xEE000E15 */ + return cortex_a_exec_opcode( a->armv7a_common.arm.target, - ARMV4_5_MRC(14, 0, 0, 0, 5, 0), + ARMV4_5_MRC(14, 0, rt, 0, 5, 0), &dscr); +} + +static int cortex_a_instr_write_data_r0(struct arm_dpm *dpm, + uint32_t opcode, uint32_t data) +{ + struct cortex_a_common *a = dpm_to_a(dpm); + uint32_t dscr = DSCR_INSTR_COMP; + int retval; + + retval = cortex_a_instr_write_data_rt_dcc(dpm, 0, data); if (retval != ERROR_OK) return retval; @@ -482,31 +495,43 @@ static int cortex_a_instr_read_data_dcc(struct arm_dpm *dpm, return cortex_a_read_dcc(a, data, &dscr); } - -static int cortex_a_instr_read_data_r0(struct arm_dpm *dpm, - uint32_t opcode, uint32_t *data) +static int cortex_a_instr_read_data_rt_dcc(struct arm_dpm *dpm, + uint8_t rt, uint32_t *data) { struct cortex_a_common *a = dpm_to_a(dpm); uint32_t dscr = DSCR_INSTR_COMP; int retval; - /* the opcode, writing data to R0 */ + if (rt > 15) + return ERROR_TARGET_INVALID; + retval = cortex_a_exec_opcode( a->armv7a_common.arm.target, - opcode, + ARMV4_5_MCR(14, 0, rt, 0, 5, 0), &dscr); if (retval != ERROR_OK) return retval; - /* write R0 to DCC */ + return cortex_a_read_dcc(a, data, &dscr); +} + +static int cortex_a_instr_read_data_r0(struct arm_dpm *dpm, + uint32_t opcode, uint32_t *data) +{ + struct cortex_a_common *a = dpm_to_a(dpm); + uint32_t dscr = DSCR_INSTR_COMP; + int retval; + + /* the opcode, writing data to R0 */ retval = cortex_a_exec_opcode( a->armv7a_common.arm.target, - ARMV4_5_MCR(14, 0, 0, 0, 5, 0), + opcode, &dscr); if (retval != ERROR_OK) return retval; - return cortex_a_read_dcc(a, data, &dscr); + /* write R0 to DCC */ + return cortex_a_instr_read_data_rt_dcc(dpm, 0, data); } static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, @@ -1678,6 +1703,7 @@ static int cortex_a_assert_reset(struct target *target) static int cortex_a_deassert_reset(struct target *target) { + struct armv7a_common *armv7a = target_to_armv7a(target); int retval; LOG_DEBUG(" "); @@ -1696,7 +1722,8 @@ static int cortex_a_deassert_reset(struct target *target) LOG_WARNING("%s: ran after reset and before halt ...", target_name(target)); if (target_was_examined(target)) { - retval = target_halt(target); + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_DRCR, DRCR_HALT); if (retval != ERROR_OK) return retval; } else @@ -1893,7 +1920,8 @@ static int cortex_a_write_cpu_memory_slow(struct target *target, { /* Writes count objects of size size from *buffer. Old value of DSCR must * be in *dscr; updated to new value. This is slow because it works for - * non-word-sized objects and (maybe) unaligned accesses. If size == 4 and + * non-word-sized objects. Avoid unaligned accesses as they do not work + * on memory address space without "Normal" attribute. If size == 4 and * the address is aligned, cortex_a_write_cpu_memory_fast should be * preferred. * Preconditions: @@ -2050,7 +2078,22 @@ static int cortex_a_write_cpu_memory(struct target *target, /* We are doing a word-aligned transfer, so use fast mode. */ retval = cortex_a_write_cpu_memory_fast(target, count, buffer, &dscr); } else { - /* Use slow path. */ + /* Use slow path. Adjust size for aligned accesses */ + switch (address % 4) { + case 1: + case 3: + count *= size; + size = 1; + break; + case 2: + if (size == 4) { + count *= 2; + size = 2; + } + case 0: + default: + break; + } retval = cortex_a_write_cpu_memory_slow(target, size, count, buffer, &dscr); } @@ -2136,7 +2179,8 @@ static int cortex_a_read_cpu_memory_slow(struct target *target, { /* Reads count objects of size size into *buffer. Old value of DSCR must be * in *dscr; updated to new value. This is slow because it works for - * non-word-sized objects and (maybe) unaligned accesses. If size == 4 and + * non-word-sized objects. Avoid unaligned accesses as they do not work + * on memory address space without "Normal" attribute. If size == 4 and * the address is aligned, cortex_a_read_cpu_memory_fast should be * preferred. * Preconditions: @@ -2352,7 +2396,23 @@ static int cortex_a_read_cpu_memory(struct target *target, /* We are doing a word-aligned transfer, so use fast mode. */ retval = cortex_a_read_cpu_memory_fast(target, count, buffer, &dscr); } else { - /* Use slow path. */ + /* Use slow path. Adjust size for aligned accesses */ + switch (address % 4) { + case 1: + case 3: + count *= size; + size = 1; + break; + case 2: + if (size == 4) { + count *= 2; + size = 2; + } + break; + case 0: + default: + break; + } retval = cortex_a_read_cpu_memory_slow(target, size, count, buffer, &dscr); } @@ -2620,7 +2680,7 @@ static int cortex_a_examine_first(struct target *target) int i; int retval = ERROR_OK; - uint32_t didr, cpuid, dbg_osreg; + uint32_t didr, cpuid, dbg_osreg, dbg_idpfr1; /* Search for the APB-AP - it is needed for access to debug registers */ retval = dap_find_ap(swjdp, AP_TYPE_APB_AP, &armv7a->debug_ap); @@ -2660,6 +2720,10 @@ static int cortex_a_examine_first(struct target *target) } else armv7a->debug_base = target->dbgbase; + if ((armv7a->debug_base & (1UL<<31)) == 0) + LOG_WARNING("Debug base address for target %s has bit 31 set to 0. Access to debug registers will likely fail!\n" + "Please fix the target configuration.", target_name(target)); + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DIDR, &didr); if (retval != ERROR_OK) { @@ -2725,7 +2789,25 @@ static int cortex_a_examine_first(struct target *target) } } - armv7a->arm.core_type = ARM_MODE_MON; + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_ID_PFR1, &dbg_idpfr1); + if (retval != ERROR_OK) + return retval; + + if (dbg_idpfr1 & 0x000000f0) { + LOG_DEBUG("target->coreid %" PRId32 " has security extensions", + target->coreid); + armv7a->arm.core_type = ARM_CORE_TYPE_SEC_EXT; + } + if (dbg_idpfr1 & 0x0000f000) { + LOG_DEBUG("target->coreid %" PRId32 " has virtualization extensions", + target->coreid); + /* + * overwrite and simplify the checks. + * virtualization extensions require implementation of security extension + */ + armv7a->arm.core_type = ARM_CORE_TYPE_VIRT_EXT; + } /* Avoid recreating the registers cache */ if (!target_was_examined(target)) { @@ -2877,6 +2959,7 @@ static void cortex_a_deinit_target(struct target *target) } free(cortex_a->brp_list); + arm_free_reg_cache(dpm->arm); free(dpm->dbp); free(dpm->dwp); free(target->private_config); diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 7f59401..d9bee0e 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -129,7 +129,7 @@ static int cortex_m_write_debug_halt_mask(struct target *target, struct armv7m_common *armv7m = &cortex_m->armv7m; /* mask off status bits */ - cortex_m->dcb_dhcsr &= ~((0xFFFF << 16) | mask_off); + cortex_m->dcb_dhcsr &= ~((0xFFFFul << 16) | mask_off); /* create new register mask */ cortex_m->dcb_dhcsr |= DBGKEY | C_DEBUGEN | mask_on; @@ -710,11 +710,11 @@ static int cortex_m_soft_reset_halt(struct target *target) uint32_t dcb_dhcsr = 0; int retval, timeout = 0; - /* soft_reset_halt is deprecated on cortex_m as the same functionality - * can be obtained by using 'reset halt' and 'cortex_m reset_config vectreset' - * As this reset only used VC_CORERESET it would only ever reset the cortex_m + /* on single cortex_m MCU soft_reset_halt should be avoided as same functionality + * can be obtained by using 'reset halt' and 'cortex_m reset_config vectreset'. + * As this reset only uses VC_CORERESET it would only ever reset the cortex_m * core, not the peripherals */ - LOG_WARNING("soft_reset_halt is deprecated, please use 'reset halt' instead."); + LOG_DEBUG("soft_reset_halt is discouraged, please use 'reset halt' instead."); /* Set C_DEBUGEN */ retval = cortex_m_write_debug_halt_mask(target, 0, C_STEP | C_MASKINTS); @@ -919,7 +919,7 @@ static int cortex_m_step(struct target *target, int current, * a normal step, otherwise we have to manually step over the bkpt * instruction - as such simulate a step */ if (bkpt_inst_found == false) { - if ((cortex_m->isrmasking_mode != CORTEX_M_ISRMASK_AUTO)) { + if (cortex_m->isrmasking_mode != CORTEX_M_ISRMASK_AUTO) { /* Automatic ISR masking mode off: Just step over the next * instruction, with interrupts on or off as appropriate. */ cortex_m_set_maskints_for_step(target); @@ -966,8 +966,7 @@ static int cortex_m_step(struct target *target, int current, /* Re-enable interrupts if appropriate */ cortex_m_write_debug_halt_mask(target, C_HALT, 0); cortex_m_set_maskints_for_halt(target); - } - else { + } else { /* Set a temporary break point */ if (breakpoint) { @@ -1980,7 +1979,7 @@ static void cortex_m_dwt_addreg(struct target *t, struct reg *r, const struct dw { struct dwt_reg_state *state; - state = calloc(1, sizeof *state); + state = calloc(1, sizeof(*state)); if (!state) return; state->addr = d->addr; @@ -2021,7 +2020,7 @@ fail0: return; } - cache = calloc(1, sizeof *cache); + cache = calloc(1, sizeof(*cache)); if (!cache) { fail1: free(cm->dwt_comparator_list); @@ -2029,7 +2028,7 @@ fail1: } cache->name = "Cortex-M DWT registers"; cache->num_regs = 2 + cm->dwt_num_comp * 3; - cache->reg_list = calloc(cache->num_regs, sizeof *cache->reg_list); + cache->reg_list = calloc(cache->num_regs, sizeof(*cache->reg_list)); if (!cache->reg_list) { free(cache); goto fail1; @@ -2231,6 +2230,19 @@ int cortex_m_examine(struct target *target) armv7m->debug_ap->tar_autoincr_block = (1 << 10); } + /* Enable debug requests */ + retval = target_read_u32(target, DCB_DHCSR, &cortex_m->dcb_dhcsr); + if (retval != ERROR_OK) + return retval; + if (!(cortex_m->dcb_dhcsr & C_DEBUGEN)) { + uint32_t dhcsr = (cortex_m->dcb_dhcsr | C_DEBUGEN) & ~(C_HALT | C_STEP | C_MASKINTS); + + retval = target_write_u32(target, DCB_DHCSR, DBGKEY | (dhcsr & 0x0000FFFFUL)); + if (retval != ERROR_OK) + return retval; + cortex_m->dcb_dhcsr = dhcsr; + } + /* Configure trace modules */ retval = target_write_u32(target, DCB_DEMCR, TRCENA | armv7m->demcr); if (retval != ERROR_OK) diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index 54d7a02..a767f93 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -26,6 +26,7 @@ #define OPENOCD_TARGET_CORTEX_M_H #include "armv7m.h" +#include "helper/bits.h" #define CORTEX_M_COMMON_MAGIC 0x1A451A45 @@ -50,7 +51,7 @@ #define DCB_DCRDR 0xE000EDF8 #define DCB_DEMCR 0xE000EDFC -#define DCRSR_WnR (1 << 16) +#define DCRSR_WnR BIT(16) #define DWT_CTRL 0xE0001000 #define DWT_CYCCNT 0xE0001004 @@ -86,29 +87,32 @@ #define TPIU_FFCR 0xE0040304 #define TPIU_FSCR 0xE0040308 +/* Maximum SWO prescaler value. */ +#define TPIU_ACPR_MAX_SWOSCALER 0x1fff + /* DCB_DHCSR bit and field definitions */ -#define DBGKEY (0xA05F << 16) -#define C_DEBUGEN (1 << 0) -#define C_HALT (1 << 1) -#define C_STEP (1 << 2) -#define C_MASKINTS (1 << 3) -#define S_REGRDY (1 << 16) -#define S_HALT (1 << 17) -#define S_SLEEP (1 << 18) -#define S_LOCKUP (1 << 19) -#define S_RETIRE_ST (1 << 24) -#define S_RESET_ST (1 << 25) +#define DBGKEY (0xA05Ful << 16) +#define C_DEBUGEN BIT(0) +#define C_HALT BIT(1) +#define C_STEP BIT(2) +#define C_MASKINTS BIT(3) +#define S_REGRDY BIT(16) +#define S_HALT BIT(17) +#define S_SLEEP BIT(18) +#define S_LOCKUP BIT(19) +#define S_RETIRE_ST BIT(24) +#define S_RESET_ST BIT(25) /* DCB_DEMCR bit and field definitions */ -#define TRCENA (1 << 24) -#define VC_HARDERR (1 << 10) -#define VC_INTERR (1 << 9) -#define VC_BUSERR (1 << 8) -#define VC_STATERR (1 << 7) -#define VC_CHKERR (1 << 6) -#define VC_NOCPERR (1 << 5) -#define VC_MMERR (1 << 4) -#define VC_CORERESET (1 << 0) +#define TRCENA BIT(24) +#define VC_HARDERR BIT(10) +#define VC_INTERR BIT(9) +#define VC_BUSERR BIT(8) +#define VC_STATERR BIT(7) +#define VC_CHKERR BIT(6) +#define VC_NOCPERR BIT(5) +#define VC_MMERR BIT(4) +#define VC_CORERESET BIT(0) #define NVIC_ICTR 0xE000E004 #define NVIC_ISE0 0xE000E100 @@ -125,12 +129,12 @@ #define NVIC_BFAR 0xE000ED38 /* NVIC_AIRCR bits */ -#define AIRCR_VECTKEY (0x5FA << 16) -#define AIRCR_SYSRESETREQ (1 << 2) -#define AIRCR_VECTCLRACTIVE (1 << 1) -#define AIRCR_VECTRESET (1 << 0) +#define AIRCR_VECTKEY (0x5FAul << 16) +#define AIRCR_SYSRESETREQ BIT(2) +#define AIRCR_VECTCLRACTIVE BIT(1) +#define AIRCR_VECTRESET BIT(0) /* NVIC_SHCSR bits */ -#define SHCSR_BUSFAULTENA (1 << 17) +#define SHCSR_BUSFAULTENA BIT(17) /* NVIC_DFSR bits */ #define DFSR_HALTED 1 #define DFSR_BKPT 2 @@ -140,10 +144,10 @@ #define FPCR_CODE 0 #define FPCR_LITERAL 1 -#define FPCR_REPLACE_REMAP (0 << 30) -#define FPCR_REPLACE_BKPT_LOW (1 << 30) -#define FPCR_REPLACE_BKPT_HIGH (2 << 30) -#define FPCR_REPLACE_BKPT_BOTH (3 << 30) +#define FPCR_REPLACE_REMAP (0ul << 30) +#define FPCR_REPLACE_BKPT_LOW (1ul << 30) +#define FPCR_REPLACE_BKPT_HIGH (2ul << 30) +#define FPCR_REPLACE_BKPT_BOTH (3ul << 30) struct cortex_m_fp_comparator { bool used; diff --git a/src/target/dsp563xx_once.c b/src/target/dsp563xx_once.c index fe4927b..624474d 100644 --- a/src/target/dsp563xx_once.c +++ b/src/target/dsp563xx_once.c @@ -46,7 +46,7 @@ #define JTAG_INSTR_BYPASS 0x0F /** */ -static inline int dsp563xx_write_dr(struct jtag_tap *tap, uint8_t * dr_in, uint8_t * dr_out, int dr_len, int rti) +static inline int dsp563xx_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, int dr_len, int rti) { jtag_add_plain_dr_scan(dr_len, dr_out, dr_in, TAP_IDLE); @@ -54,19 +54,20 @@ static inline int dsp563xx_write_dr(struct jtag_tap *tap, uint8_t * dr_in, uint8 } /** */ -static inline int dsp563xx_write_dr_u8(struct jtag_tap *tap, uint8_t * dr_in, uint8_t dr_out, int dr_len, int rti) +static inline int dsp563xx_write_dr_u8(struct jtag_tap *tap, uint8_t *dr_in, uint8_t dr_out, int dr_len, int rti) { return dsp563xx_write_dr(tap, dr_in, &dr_out, dr_len, rti); } /** */ -static inline int dsp563xx_write_dr_u32(struct jtag_tap *tap, uint32_t * dr_in, uint32_t dr_out, int dr_len, int rti) +static inline int dsp563xx_write_dr_u32(struct jtag_tap *tap, uint32_t *dr_in, uint32_t dr_out, int dr_len, int rti) { return dsp563xx_write_dr(tap, (uint8_t *) dr_in, (uint8_t *) &dr_out, dr_len, rti); } /** single word instruction */ -static inline int dsp563xx_once_ir_exec(struct jtag_tap *tap, int flush, uint8_t instr, uint8_t rw, uint8_t go, uint8_t ex) +static inline int dsp563xx_once_ir_exec(struct jtag_tap *tap, int flush, uint8_t instr, + uint8_t rw, uint8_t go, uint8_t ex) { int err; @@ -79,19 +80,19 @@ static inline int dsp563xx_once_ir_exec(struct jtag_tap *tap, int flush, uint8_t } /* IR and DR functions */ -static inline int dsp563xx_write_ir(struct jtag_tap *tap, uint8_t * ir_in, uint8_t * ir_out, int ir_len, int rti) +static inline int dsp563xx_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti) { jtag_add_plain_ir_scan(tap->ir_length, ir_out, ir_in, TAP_IDLE); return ERROR_OK; } -static inline int dsp563xx_write_ir_u8(struct jtag_tap *tap, uint8_t * ir_in, uint8_t ir_out, int ir_len, int rti) +static inline int dsp563xx_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len, int rti) { return dsp563xx_write_ir(tap, ir_in, &ir_out, ir_len, rti); } -static inline int dsp563xx_jtag_sendinstr(struct jtag_tap *tap, uint8_t * ir_in, uint8_t ir_out) +static inline int dsp563xx_jtag_sendinstr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out) { return dsp563xx_write_ir_u8(tap, ir_in, ir_out, tap->ir_length, 1); } @@ -195,7 +196,7 @@ int dsp563xx_once_read_register(struct jtag_tap *tap, int flush, struct once_reg } /** once read register with register len */ -int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t * data) +int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t *data) { int err; @@ -212,7 +213,7 @@ int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint } /** once read register */ -int dsp563xx_once_reg_read(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t * data) +int dsp563xx_once_reg_read(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t *data) { int err; diff --git a/src/target/dsp563xx_once.h b/src/target/dsp563xx_once.h index da7f5e9..811c086 100644 --- a/src/target/dsp563xx_once.h +++ b/src/target/dsp563xx_once.h @@ -76,9 +76,9 @@ int dsp563xx_once_target_status(struct jtag_tap *tap); /** once read registers */ int dsp563xx_once_read_register(struct jtag_tap *tap, int flush, struct once_reg *regs, int len); /** once read register */ -int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t * data); +int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t *data); /** once read register */ -int dsp563xx_once_reg_read(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t * data); +int dsp563xx_once_reg_read(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t *data); /** once write register */ int dsp563xx_once_reg_write(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t data); /** single word instruction */ diff --git a/src/target/dsp5680xx.c b/src/target/dsp5680xx.c index a50f2cd..c74a418 100644 --- a/src/target/dsp5680xx.c +++ b/src/target/dsp5680xx.c @@ -1731,7 +1731,12 @@ static int dsp5680xx_f_ex(struct target *t, uint16_t c, uint32_t a, uint32_t d, } /** - * Prior to the execution of any Flash module command, the Flash module Clock Divider (CLKDIV) register must be initialized. The values of this register determine the speed of the internal Flash Clock (FCLK). FCLK must be in the range of 150kHz ≤ FCLK ≤ 200kHz for proper operation of the Flash module. (Running FCLK too slowly wears out the module, while running it too fast under programs Flash leading to bit errors.) + * Prior to the execution of any Flash module command, the Flash module Clock + * Divider (CLKDIV) register must be initialized. The values of this register + * determine the speed of the internal Flash Clock (FCLK). FCLK must be in the + * range of 150kHz ≤ FCLK ≤ 200kHz for proper operation of the Flash module. + * (Running FCLK too slowly wears out the module, while running it too fast + * under programs Flash leading to bit errors.) * * @param target * @@ -1787,7 +1792,11 @@ static int set_fm_ck_div(struct target *target) } /** - * Executes the FM calculate signature command. The FM will calculate over the data from @address to @address + @words -1. The result is written to a register, then read out by this function and returned in @signature. The value @signature may be compared to the the one returned by perl_crc to verify the flash was written correctly. + * Executes the FM calculate signature command. The FM will calculate over the + * data from @address to @address + @words -1. The result is written to a + * register, then read out by this function and returned in @signature. The + * value @signature may be compared to the the one returned by perl_crc to + * verify the flash was written correctly. * * @param target * @param address Start of flash array where the signature should be calculated. diff --git a/src/target/dsp5680xx.h b/src/target/dsp5680xx.h index 842796b..72557ce 100644 --- a/src/target/dsp5680xx.h +++ b/src/target/dsp5680xx.h @@ -315,7 +315,7 @@ static inline struct dsp5680xx_common *target_to_dsp5680xx(struct target * * @return */ -int dsp5680xx_f_wr(struct target *target, const uint8_t * buffer, uint32_t address, +int dsp5680xx_f_wr(struct target *target, const uint8_t *buffer, uint32_t address, uint32_t count, int is_flash_lock); /** @@ -329,7 +329,7 @@ int dsp5680xx_f_wr(struct target *target, const uint8_t * buffer, uint32_t addre * * @return */ -int dsp5680xx_f_erase_check(struct target *target, uint8_t * erased, +int dsp5680xx_f_erase_check(struct target *target, uint8_t *erased, uint32_t sector); /** @@ -354,7 +354,7 @@ int dsp5680xx_f_erase(struct target *target, int first, int last); * * @return */ -int dsp5680xx_f_protect_check(struct target *target, uint16_t * protected); +int dsp5680xx_f_protect_check(struct target *target, uint16_t *protected); /** * Writes the flash security words with a specific value. The chip's security will be diff --git a/src/target/esirisc_jtag.c b/src/target/esirisc_jtag.c index 333a622..700ae3a 100644 --- a/src/target/esirisc_jtag.c +++ b/src/target/esirisc_jtag.c @@ -36,7 +36,7 @@ static void esirisc_jtag_set_instr(struct esirisc_jtag *jtag_info, uint32_t new_ if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { struct scan_field field; - uint8_t t[4]; + uint8_t t[4] = { 0 }; field.num_bits = tap->ir_length; field.out_value = t; diff --git a/src/target/etb.c b/src/target/etb.c index 392c6ad..0c03c4d 100644 --- a/src/target/etb.c +++ b/src/target/etb.c @@ -176,13 +176,13 @@ static int etb_read_ram(struct etb *etb, uint32_t *data, int num_frames) fields[0].in_value = NULL; fields[1].num_bits = 7; - uint8_t temp1; + uint8_t temp1 = 0; fields[1].out_value = &temp1; buf_set_u32(&temp1, 0, 7, 4); fields[1].in_value = NULL; fields[2].num_bits = 1; - uint8_t temp2; + uint8_t temp2 = 0; fields[2].out_value = &temp2; buf_set_u32(&temp2, 0, 1, 0); fields[2].in_value = NULL; @@ -229,7 +229,7 @@ static int etb_read_reg_w_check(struct reg *reg, fields[0].check_mask = NULL; fields[1].num_bits = 7; - uint8_t temp1; + uint8_t temp1 = 0; fields[1].out_value = &temp1; buf_set_u32(&temp1, 0, 7, reg_addr); fields[1].in_value = NULL; @@ -237,7 +237,7 @@ static int etb_read_reg_w_check(struct reg *reg, fields[1].check_mask = NULL; fields[2].num_bits = 1; - uint8_t temp2; + uint8_t temp2 = 0; fields[2].out_value = &temp2; buf_set_u32(&temp2, 0, 1, 0); fields[2].in_value = NULL; @@ -310,13 +310,13 @@ static int etb_write_reg(struct reg *reg, uint32_t value) fields[0].in_value = NULL; fields[1].num_bits = 7; - uint8_t temp1; + uint8_t temp1 = 0; fields[1].out_value = &temp1; buf_set_u32(&temp1, 0, 7, reg_addr); fields[1].in_value = NULL; fields[2].num_bits = 1; - uint8_t temp2; + uint8_t temp2 = 0; fields[2].out_value = &temp2; buf_set_u32(&temp2, 0, 1, 1); fields[2].in_value = NULL; diff --git a/src/target/etm.c b/src/target/etm.c index 5751348..5d079ff 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -303,6 +303,11 @@ struct reg_cache *etm_build_reg_cache(struct target *target, reg_list = calloc(128, sizeof(struct reg)); arch_info = calloc(128, sizeof(struct etm_reg)); + if (reg_cache == NULL || reg_list == NULL || arch_info == NULL) { + LOG_ERROR("No memory"); + goto fail; + } + /* fill in values for the reg cache */ reg_cache->name = "etm registers"; reg_cache->next = NULL; @@ -498,6 +503,7 @@ static int etm_read_reg_w_check(struct reg *reg, uint8_t *check_value, uint8_t *check_mask) { struct etm_reg *etm_reg = reg->arch_info; + assert(etm_reg); const struct etm_reg_info *r = etm_reg->reg_info; uint8_t reg_addr = r->addr & 0x7f; struct scan_field fields[3]; @@ -527,7 +533,7 @@ static int etm_read_reg_w_check(struct reg *reg, fields[0].check_mask = NULL; fields[1].num_bits = 7; - uint8_t temp1; + uint8_t temp1 = 0; fields[1].out_value = &temp1; buf_set_u32(&temp1, 0, 7, reg_addr); fields[1].in_value = NULL; @@ -535,7 +541,7 @@ static int etm_read_reg_w_check(struct reg *reg, fields[1].check_mask = NULL; fields[2].num_bits = 1; - uint8_t temp2; + uint8_t temp2 = 0; fields[2].out_value = &temp2; buf_set_u32(&temp2, 0, 1, 0); fields[2].in_value = NULL; @@ -614,13 +620,13 @@ static int etm_write_reg(struct reg *reg, uint32_t value) fields[0].in_value = NULL; fields[1].num_bits = 7; - uint8_t tmp2; + uint8_t tmp2 = 0; fields[1].out_value = &tmp2; buf_set_u32(&tmp2, 0, 7, reg_addr); fields[1].in_value = NULL; fields[2].num_bits = 1; - uint8_t tmp3; + uint8_t tmp3 = 0; fields[2].out_value = &tmp3; buf_set_u32(&tmp3, 0, 1, 1); fields[2].in_value = NULL; @@ -1068,8 +1074,8 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_invocatio (instruction.type == ARM_STM)) { int i; for (i = 0; i < 16; i++) { - if (instruction.info.load_store_multiple. - register_list & (1 << i)) { + if (instruction.info.load_store_multiple.register_list + & (1 << i)) { uint32_t data; if (etmv1_data(ctx, 4, &data) != 0) return ERROR_ETM_ANALYSIS_FAILED; diff --git a/src/target/hla_target.c b/src/target/hla_target.c index 60ed7d6..f0dc572 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -25,6 +25,7 @@ #include "config.h" #endif +#include "jtag/interface.h" #include "jtag/jtag.h" #include "jtag/hla/hla_transport.h" #include "jtag/hla/hla_interface.h" @@ -499,7 +500,7 @@ static int adapter_poll(struct target *target) return ERROR_OK; } -static int adapter_assert_reset(struct target *target) +static int hl_assert_reset(struct target *target) { int res = ERROR_OK; struct hl_interface_s *adapter = target_to_adapter(target); @@ -514,8 +515,7 @@ static int adapter_assert_reset(struct target *target) if ((jtag_reset_config & RESET_HAS_SRST) && (jtag_reset_config & RESET_SRST_NO_GATING)) { - jtag_add_reset(0, 1); - res = adapter->layout->api->assert_srst(adapter->handle, 0); + res = adapter_assert_reset(); srst_asserted = true; } @@ -529,8 +529,7 @@ static int adapter_assert_reset(struct target *target) if (jtag_reset_config & RESET_HAS_SRST) { if (!srst_asserted) { - jtag_add_reset(0, 1); - res = adapter->layout->api->assert_srst(adapter->handle, 0); + res = adapter_assert_reset(); } if (res == ERROR_COMMAND_NOTFOUND) LOG_ERROR("Hardware srst not supported, falling back to software reset"); @@ -563,21 +562,14 @@ static int adapter_assert_reset(struct target *target) return ERROR_OK; } -static int adapter_deassert_reset(struct target *target) +static int hl_deassert_reset(struct target *target) { - struct hl_interface_s *adapter = target_to_adapter(target); - enum reset_types jtag_reset_config = jtag_get_reset_config(); LOG_DEBUG("%s", __func__); if (jtag_reset_config & RESET_HAS_SRST) - adapter->layout->api->assert_srst(adapter->handle, 1); - - /* virtual deassert reset, we need it for the internal - * jtag state machine - */ - jtag_add_reset(0, 0); + adapter_deassert_reset(); target->savedDCRDR = 0; /* clear both DCC busy bits on initial resume */ @@ -819,8 +811,8 @@ struct target_type hla_target = { .arch_state = armv7m_arch_state, .target_request_data = hl_target_request_data, - .assert_reset = adapter_assert_reset, - .deassert_reset = adapter_deassert_reset, + .assert_reset = hl_assert_reset, + .deassert_reset = hl_deassert_reset, .halt = adapter_halt, .resume = adapter_resume, diff --git a/src/target/ls1_sap.c b/src/target/ls1_sap.c index bc46ed4..330042f 100644 --- a/src/target/ls1_sap.c +++ b/src/target/ls1_sap.c @@ -113,7 +113,7 @@ static void ls1_sap_set_instr(struct jtag_tap *tap, uint32_t new_instr) static void ls1_sap_set_addr_high(struct jtag_tap *tap, uint16_t addr_high) { struct scan_field field; - uint8_t buf[2]; + uint8_t buf[2] = { 0 }; ls1_sap_set_instr(tap, 0x21); @@ -130,7 +130,7 @@ static void ls1_sap_memory_cmd(struct jtag_tap *tap, uint32_t address, int32_t size, bool rnw) { struct scan_field field; - uint8_t cmd[8]; + uint8_t cmd[8] = { 0 }; ls1_sap_set_instr(tap, 0x24); diff --git a/src/target/mem_ap.c b/src/target/mem_ap.c index 29cd37a..ade48b6 100644 --- a/src/target/mem_ap.c +++ b/src/target/mem_ap.c @@ -65,6 +65,15 @@ static int mem_ap_init_target(struct command_context *cmd_ctx, struct target *ta return ERROR_OK; } +static void mem_ap_deinit_target(struct target *target) +{ + LOG_DEBUG("%s", __func__); + + free(target->private_config); + free(target->arch_info); + return; +} + static int mem_ap_arch_state(struct target *target) { LOG_DEBUG("%s", __func__); @@ -169,6 +178,7 @@ struct target_type mem_ap_target = { .target_create = mem_ap_target_create, .init_target = mem_ap_init_target, + .deinit_target = mem_ap_deinit_target, .examine = mem_ap_examine, .target_jim_configure = adiv5_jim_configure, diff --git a/src/target/mips64.c b/src/target/mips64.c new file mode 100644 index 0000000..6a7c425 --- /dev/null +++ b/src/target/mips64.c @@ -0,0 +1,623 @@ +/* + * Support for processors implementing MIPS64 instruction set + * + * Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com> + * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru> + * Copyright (C) 2014 by Antony Pavlov <antonynpavlov@gmail.com> + * Copyright (C) 2014 by Peter Mamonov <pmamonov@gmail.com> + * + * Based on the work of: + * Copyright (C) 2008 by Spencer Oliver + * Copyright (C) 2008 by David T.L. Wong + * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mips64.h" + +static const struct { + unsigned id; + const char *name; + enum reg_type type; + const char *group; + const char *feature; + int flag; +} mips64_regs[] = { + { 0, "r0", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 1, "r1", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 2, "r2", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 3, "r3", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 4, "r4", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 5, "r5", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 6, "r6", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 7, "r7", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 8, "r8", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 9, "r9", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 10, "r10", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 11, "r11", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 12, "r12", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 13, "r13", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 14, "r14", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 15, "r15", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 16, "r16", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 17, "r17", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 18, "r18", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 19, "r19", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 20, "r20", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 21, "r21", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 22, "r22", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 23, "r23", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 24, "r24", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 25, "r25", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 26, "r26", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 27, "r27", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 28, "r28", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 29, "r29", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 30, "r30", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 31, "r31", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 32, "lo", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 33, "hi", REG_TYPE_UINT64, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { MIPS64_NUM_CORE_REGS + 0, "pc", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cpu", 0 }, + { MIPS64_NUM_CORE_REGS + 1, "Random", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 2, "Entrylo_0", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 3, "Entrylo_1", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 4, "Context", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 5, "Pagemask", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 6, "Wired", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 7, "badvaddr", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 8, "Count", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 9, "EntryHi", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 10, "Compare", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 11, "status", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 12, "cause", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 13, "EPC", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 14, "PrID", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 15, "Config", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 16, "LLA", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 17, "WatchLo0", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 18, "WatchLo1", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 19, "WatchHi0", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 20, "WatchHi1", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 21, "Xcontext", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 22, "ChipMemCtrl", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 23, "Debug", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 24, "Perfcount, sel=0", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 25, "Perfcount, sel=1", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 26, "Perfcount, sel=2", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 27, "Perfcount, sel=3", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 28, "ECC", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 29, "CacheErr", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 30, "TagLo", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 31, "TagHi", REG_TYPE_UINT32, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 32, "DataHi", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_REGS + 33, "EEPC", REG_TYPE_UINT64, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 0, "f0", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 1, "f1", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 2, "f2", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 3, "f3", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 4, "f4", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 5, "f5", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 6, "f6", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 7, "f7", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 8, "f8", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 9, "f9", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 10, "f10", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 11, "f11", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 12, "f12", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 13, "f13", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 14, "f14", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 15, "f15", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 16, "f16", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 17, "f17", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 18, "f18", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 19, "f19", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 20, "f20", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 21, "f21", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 22, "f22", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 23, "f23", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 24, "f24", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 25, "f25", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 26, "f26", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 27, "f27", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 28, "f28", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 29, "f29", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 30, "f30", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 31, "f31", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 32, "fcsr", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 33, "fir", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 34, "fconfig", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 35, "fccr", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 36, "fexr", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS64_NUM_CORE_C0_REGS + 37, "fenr", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, +}; + +static int reg_type2size(enum reg_type type) +{ + switch (type) { + case REG_TYPE_UINT32: + case REG_TYPE_INT: + return 32; + case REG_TYPE_UINT64: + case REG_TYPE_IEEE_DOUBLE: + return 64; + default: + return 64; + } +} + +static int mips64_get_core_reg(struct reg *reg) +{ + int retval; + struct mips64_core_reg *mips64_reg = reg->arch_info; + struct target *target = mips64_reg->target; + struct mips64_common *mips64_target = target->arch_info; + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + retval = mips64_target->read_core_reg(target, mips64_reg->num); + + return retval; +} + +static int mips64_set_core_reg(struct reg *reg, uint8_t *buf) +{ + struct mips64_core_reg *mips64_reg = reg->arch_info; + struct target *target = mips64_reg->target; + uint64_t value = buf_get_u64(buf, 0, 64); + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + buf_set_u64(reg->value, 0, 64, value); + reg->dirty = 1; + reg->valid = 1; + + return ERROR_OK; +} + +static int mips64_read_core_reg(struct target *target, int num) +{ + uint64_t reg_value; + + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + + if ((num < 0) || (num >= MIPS64_NUM_REGS)) + return ERROR_COMMAND_ARGUMENT_INVALID; + + reg_value = mips64->core_regs[num]; + buf_set_u64(mips64->core_cache->reg_list[num].value, 0, 64, reg_value); + mips64->core_cache->reg_list[num].valid = 1; + mips64->core_cache->reg_list[num].dirty = 0; + + return ERROR_OK; +} + +static int mips64_write_core_reg(struct target *target, int num) +{ + uint64_t reg_value; + + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + + if ((num < 0) || (num >= MIPS64_NUM_REGS)) + return ERROR_COMMAND_ARGUMENT_INVALID; + + reg_value = buf_get_u64(mips64->core_cache->reg_list[num].value, 0, 64); + mips64->core_regs[num] = reg_value; + LOG_DEBUG("write core reg %i value 0x%" PRIx64 "", num , reg_value); + mips64->core_cache->reg_list[num].valid = 1; + mips64->core_cache->reg_list[num].dirty = 0; + + return ERROR_OK; +} + +int mips64_invalidate_core_regs(struct target *target) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + unsigned int i; + + for (i = 0; i < mips64->core_cache->num_regs; i++) { + mips64->core_cache->reg_list[i].valid = 0; + mips64->core_cache->reg_list[i].dirty = 0; + } + + return ERROR_OK; +} + + +int mips64_get_gdb_reg_list(struct target *target, struct reg **reg_list[], + int *reg_list_size, enum target_register_class reg_class) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + register int i; + + /* include floating point registers */ + *reg_list_size = MIPS64_NUM_REGS; + *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); + + for (i = 0; i < MIPS64_NUM_REGS; i++) + (*reg_list)[i] = &mips64->core_cache->reg_list[i]; + + return ERROR_OK; +} + +int mips64_save_context(struct target *target) +{ + int retval; + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + + retval = mips64_pracc_read_regs(ejtag_info, mips64->core_regs); + if (retval != ERROR_OK) + return retval; + + for (unsigned i = 0; i < MIPS64_NUM_REGS; i++) + retval = mips64->read_core_reg(target, i); + + return retval; +} + +int mips64_restore_context(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + + for (unsigned i = 0; i < MIPS64_NUM_REGS; i++) { + if (mips64->core_cache->reg_list[i].dirty) + mips64->write_core_reg(target, i); + } + + return mips64_pracc_write_regs(ejtag_info, mips64->core_regs); +} + +int mips64_arch_state(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + struct reg *pc = &mips64->core_cache->reg_list[MIPS64_PC]; + + if (mips64->common_magic != MIPS64_COMMON_MAGIC) { + LOG_ERROR("BUG: called for a non-MIPS64 target"); + exit(-1); + } + + LOG_USER("target halted due to %s, pc: 0x%" PRIx64 "", + debug_reason_name(target), buf_get_u64(pc->value, 0, 64)); + + return ERROR_OK; +} + +static const struct reg_arch_type mips64_reg_type = { + .get = mips64_get_core_reg, + .set = mips64_set_core_reg, +}; + +int mips64_build_reg_cache(struct target *target) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + struct reg_cache **cache_p, *cache; + struct mips64_core_reg *arch_info = NULL; + struct reg *reg_list = NULL; + unsigned i; + + cache = calloc(1, sizeof(*cache)); + if (!cache) { + LOG_ERROR("unable to allocate cache"); + return ERROR_FAIL; + } + + reg_list = calloc(MIPS64_NUM_REGS, sizeof(*reg_list)); + if (!reg_list) { + LOG_ERROR("unable to allocate reg_list"); + goto alloc_fail; + } + + arch_info = calloc(MIPS64_NUM_REGS, sizeof(*arch_info)); + if (!arch_info) { + LOG_ERROR("unable to allocate arch_info"); + goto alloc_fail; + } + + for (i = 0; i < MIPS64_NUM_REGS; i++) { + struct mips64_core_reg *a = &arch_info[i]; + struct reg *r = ®_list[i]; + + r->arch_info = &arch_info[i]; + r->caller_save = true; /* gdb defaults to true */ + r->exist = true; + r->feature = &a->feature; + r->feature->name = mips64_regs[i].feature; + r->group = mips64_regs[i].group; + r->name = mips64_regs[i].name; + r->number = i; + r->reg_data_type = &a->reg_data_type; + r->reg_data_type->type = mips64_regs[i].type; + r->size = reg_type2size(mips64_regs[i].type); + r->type = &mips64_reg_type; + r->value = &a->value[0]; + + a->mips64_common = mips64; + a->num = mips64_regs[i].id; + a->target = target; + } + + cache->name = "mips64 registers"; + cache->reg_list = reg_list; + cache->num_regs = MIPS64_NUM_REGS; + + cache_p = register_get_last_cache_p(&target->reg_cache); + (*cache_p) = cache; + + mips64->core_cache = cache; + + return ERROR_OK; + +alloc_fail: + free(cache); + free(reg_list); + free(arch_info); + + return ERROR_FAIL; +} + +int mips64_init_arch_info(struct target *target, struct mips64_common *mips64, + struct jtag_tap *tap) +{ + mips64->bp_scanned = false; + mips64->common_magic = MIPS64_COMMON_MAGIC; + mips64->data_break_list = NULL; + mips64->ejtag_info.tap = tap; + mips64->fast_data_area = NULL; + mips64->mips64mode32 = false; + mips64->read_core_reg = mips64_read_core_reg; + mips64->write_core_reg = mips64_write_core_reg; + + return ERROR_OK; +} + +int mips64_run_algorithm(struct target *target, int num_mem_params, + struct mem_param *mem_params, int num_reg_params, + struct reg_param *reg_params, target_addr_t entry_point, + target_addr_t exit_point, int timeout_ms, void *arch_info) +{ + /* TODO */ + return ERROR_OK; +} + +int mips64_examine(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + + if (target_was_examined(target)) + return ERROR_OK; + + /* TODO: why we do not do mips64_configure_break_unit() here? */ + mips64->bp_scanned = false; + mips64->num_data_bpoints = 0; + mips64->num_data_bpoints_avail = 0; + mips64->num_inst_bpoints = 0; + mips64->num_inst_bpoints_avail = 0; + + target_set_examined(target); + + return ERROR_OK; +} + +static int mips64_configure_i_break_unit(struct target *target) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + struct mips64_comparator *ibl; + uint64_t bpinfo; + int retval; + int i; + + /* get number of inst breakpoints */ + retval = target_read_u64(target, EJTAG64_V25_IBS, &bpinfo); + if (retval != ERROR_OK) + return retval; + + mips64->num_inst_bpoints = (bpinfo >> 24) & 0x0F; + mips64->num_inst_bpoints_avail = mips64->num_inst_bpoints; + ibl = calloc(mips64->num_inst_bpoints, sizeof(*ibl)); + if (!ibl) { + LOG_ERROR("unable to allocate inst_break_list"); + return ERROR_FAIL; + } + + for (i = 0; i < mips64->num_inst_bpoints; i++) + ibl[i].reg_address = EJTAG64_V25_IBA0 + (0x100 * i); + + mips64->inst_break_list = ibl; + /* clear IBIS reg */ + retval = target_write_u64(target, EJTAG64_V25_IBS, 0); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int mips64_configure_d_break_unit(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips64_comparator *dbl; + uint64_t bpinfo; + int retval; + int i; + + /* get number of data breakpoints */ + retval = target_read_u64(target, EJTAG64_V25_DBS, &bpinfo); + if (retval != ERROR_OK) + return retval; + + mips64->num_data_bpoints = (bpinfo >> 24) & 0x0F; + mips64->num_data_bpoints_avail = mips64->num_data_bpoints; + + dbl = calloc(mips64->num_data_bpoints, sizeof(*dbl)); + + if (!dbl) { + LOG_ERROR("unable to allocate data_break_list"); + return ERROR_FAIL; + } + + for (i = 0; i < mips64->num_data_bpoints; i++) + dbl[i].reg_address = EJTAG64_V25_DBA0 + (0x100 * i); + + mips64->data_break_list = dbl; + + /* clear DBIS reg */ + retval = target_write_u64(target, EJTAG64_V25_DBS, 0); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +int mips64_configure_break_unit(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + uint64_t dcr; + int retval; + + if (mips64->bp_scanned) + return ERROR_OK; + + /* get info about breakpoint support */ + retval = target_read_u64(target, EJTAG64_DCR, &dcr); + if (retval != ERROR_OK) + return retval; + + if (dcr & EJTAG64_DCR_IB) { + retval = mips64_configure_i_break_unit(target); + if (retval != ERROR_OK) + return retval; + } + + if (dcr & EJTAG64_DCR_DB) { + retval = mips64_configure_d_break_unit(target); + if (retval != ERROR_OK) + return retval; + } + + LOG_DEBUG("DCR 0x%" PRIx64 " numinst %i numdata %i", dcr, + mips64->num_inst_bpoints, mips64->num_data_bpoints); + + mips64->bp_scanned = true; + + return ERROR_OK; +} + +int mips64_enable_interrupts(struct target *target, bool enable) +{ + int retval; + bool update = false; + uint64_t dcr; + + /* read debug control register */ + retval = target_read_u64(target, EJTAG64_DCR, &dcr); + if (retval != ERROR_OK) + return retval; + + if (enable) { + if (!(dcr & EJTAG64_DCR_INTE)) { + /* enable interrupts */ + dcr |= EJTAG64_DCR_INTE; + update = true; + } + } else { + if (dcr & EJTAG64_DCR_INTE) { + /* disable interrupts */ + dcr &= ~(uint64_t)EJTAG64_DCR_INTE; + update = true; + } + } + + if (update) { + retval = target_write_u64(target, EJTAG64_DCR, dcr); + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} diff --git a/src/target/mips64.h b/src/target/mips64.h new file mode 100644 index 0000000..3453e4e --- /dev/null +++ b/src/target/mips64.h @@ -0,0 +1,226 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Support for processors implementing MIPS64 instruction set + * + * Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com> + * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru> + * Copyright (C) 2014-2019 by Peter Mamonov <pmamonov@gmail.com> + * + * Based on the work of: + * Copyright (C) 2008 by Spencer Oliver + * Copyright (C) 2008 by David T.L. Wong + * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev + */ + +#ifndef OPENOCD_TARGET_MIPS64_H +#define OPENOCD_TARGET_MIPS64_H + +#include "target.h" +#include "register.h" +#include "mips64_pracc.h" + +#define MIPS64_COMMON_MAGIC 0xB640B640 + +/* MIPS64 CP0 registers */ +#define MIPS64_C0_INDEX 0 +#define MIPS64_C0_RANDOM 1 +#define MIPS64_C0_ENTRYLO0 2 +#define MIPS64_C0_ENTRYLO1 3 +#define MIPS64_C0_CONTEXT 4 +#define MIPS64_C0_PAGEMASK 5 +#define MIPS64_C0_WIRED 6 +#define MIPS64_C0_BADVADDR 8 +#define MIPS64_C0_COUNT 9 +#define MIPS64_C0_ENTRYHI 10 +#define MIPS64_C0_COMPARE 11 +#define MIPS64_C0_STATUS 12 +#define MIPS64_C0_CAUSE 13 +#define MIPS64_C0_EPC 14 +#define MIPS64_C0_PRID 15 +#define MIPS64_C0_CONFIG 16 +#define MIPS64_C0_LLA 17 +#define MIPS64_C0_WATCHLO 18 +#define MIPS64_C0_WATCHHI 19 +#define MIPS64_C0_XCONTEXT 20 +#define MIPS64_C0_MEMCTRL 22 +#define MIPS64_C0_DEBUG 23 +#define MIPS64_C0_DEPC 24 +#define MIPS64_C0_PERFCOUNT 25 +#define MIPS64_C0_ECC 26 +#define MIPS64_C0_CACHERR 27 +#define MIPS64_C0_TAGLO 28 +#define MIPS64_C0_TAGHI 29 +#define MIPS64_C0_DATAHI 29 +#define MIPS64_C0_EEPC 30 + +/* MIPS64 CP1 registers */ +#define MIPS64_C1_FIR 0 +#define MIPS64_C1_FCONFIG 24 +#define MIPS64_C1_FCSR 31 +#define MIPS64_C1_FCCR 25 +#define MIPS64_C1_FEXR 26 +#define MIPS64_C1_FENR 28 + +/* offsets into mips64 register cache */ +#define MIPS64_NUM_CORE_REGS 34 +#define MIPS64_NUM_C0_REGS 34 +#define MIPS64_NUM_FP_REGS 38 + +#define MIPS64_NUM_REGS (MIPS64_NUM_CORE_REGS + \ + MIPS64_NUM_C0_REGS + \ + MIPS64_NUM_FP_REGS) + +#define MIPS64_NUM_CORE_C0_REGS (MIPS64_NUM_CORE_REGS + MIPS64_NUM_C0_REGS) + +#define MIPS64_PC MIPS64_NUM_CORE_REGS + +struct mips64_comparator { + bool used; + uint64_t bp_value; + uint64_t reg_address; +}; + +struct mips64_common { + uint32_t common_magic; + void *arch_info; + struct reg_cache *core_cache; + struct mips_ejtag ejtag_info; + uint64_t core_regs[MIPS64_NUM_REGS]; + + struct working_area *fast_data_area; + + bool bp_scanned; + int num_inst_bpoints; + int num_data_bpoints; + int num_inst_bpoints_avail; + int num_data_bpoints_avail; + struct mips64_comparator *inst_break_list; + struct mips64_comparator *data_break_list; + + /* register cache to processor synchronization */ + int (*read_core_reg)(struct target *target, int num); + int (*write_core_reg)(struct target *target, int num); + + bool mips64mode32; +}; + +struct mips64_core_reg { + uint32_t num; + struct target *target; + struct mips64_common *mips64_common; + uint8_t value[8]; + struct reg_feature feature; + struct reg_data_type reg_data_type; +}; + +#define MIPS64_OP_SRL 0x02 +#define MIPS64_OP_BEQ 0x04 +#define MIPS64_OP_BNE 0x05 +#define MIPS64_OP_ADDI 0x08 +#define MIPS64_OP_ANDI 0x0c +#define MIPS64_OP_DADDI 0x18 +#define MIPS64_OP_DADDIU 0x19 +#define MIPS64_OP_AND 0x24 +#define MIPS64_OP_LUI 0x0F +#define MIPS64_OP_LW 0x23 +#define MIPS64_OP_LD 0x37 +#define MIPS64_OP_LBU 0x24 +#define MIPS64_OP_LHU 0x25 +#define MIPS64_OP_MFHI 0x10 +#define MIPS64_OP_MTHI 0x11 +#define MIPS64_OP_MFLO 0x12 +#define MIPS64_OP_MTLO 0x13 +#define MIPS64_OP_SB 0x28 +#define MIPS64_OP_SH 0x29 +#define MIPS64_OP_SW 0x2B +#define MIPS64_OP_SD 0x3F +#define MIPS64_OP_ORI 0x0D +#define MIPS64_OP_JR 0x08 + +#define MIPS64_OP_COP0 0x10 +#define MIPS64_OP_COP1 0x11 +#define MIPS64_OP_COP2 0x12 + +#define MIPS64_COP_MF 0x00 +#define MIPS64_COP_DMF 0x01 +#define MIPS64_COP_MT 0x04 +#define MIPS64_COP_DMT 0x05 +#define MIPS64_COP_CF 0x02 +#define MIPS64_COP_CT 0x06 + +#define MIPS64_R_INST(opcode, rs, rt, rd, shamt, funct) \ +(((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | ((rd) << 11) | ((shamt) << 6) | (funct)) +#define MIPS64_I_INST(opcode, rs, rt, immd) (((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | (immd)) +#define MIPS64_J_INST(opcode, addr) (((opcode) << 26) | (addr)) + +#define MIPS64_NOP 0 +#define MIPS64_ADDI(tar, src, val) MIPS64_I_INST(MIPS64_OP_ADDI, src, tar, val) +#define MIPS64_DADDI(tar, src, val) MIPS64_I_INST(MIPS64_OP_DADDI, src, tar, val) +#define MIPS64_DADDIU(tar, src, val) MIPS64_I_INST(MIPS64_OP_DADDIU, src, tar, val) +#define MIPS64_AND(reg, off, val) MIPS64_R_INST(0, off, val, reg, 0, MIPS64_OP_AND) +#define MIPS64_ANDI(d, s, im) MIPS64_I_INST(MIPS64_OP_ANDI, s, d, im) +#define MIPS64_SRL(d, w, sh) MIPS64_R_INST(0, 0, w, d, sh, MIPS64_OP_SRL) +#define MIPS64_B(off) MIPS64_BEQ(0, 0, off) +#define MIPS64_BEQ(src, tar, off) MIPS64_I_INST(MIPS64_OP_BEQ, src, tar, off) +#define MIPS64_BNE(src, tar, off) MIPS64_I_INST(MIPS64_OP_BNE, src, tar, off) +#define MIPS64_MFC0(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_MF, gpr, cpr, 0, sel) +#define MIPS64_DMFC0(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_DMF, gpr, cpr, 0, sel) +#define MIPS64_MTC0(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_MT, gpr, cpr, 0, sel) +#define MIPS64_DMTC0(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP0, MIPS64_COP_DMT, gpr, cpr, 0, sel) +#define MIPS64_MFC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_MF, gpr, cpr, 0, 0) +#define MIPS64_DMFC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_DMF, gpr, cpr, 0, 0) +#define MIPS64_MTC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_MT, gpr, cpr, 0, 0) +#define MIPS64_DMTC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_DMT, gpr, cpr, 0, 0) +#define MIPS64_MFC2(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_MF, gpr, cpr, 0, sel) +#define MIPS64_MTC2(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_MT, gpr, cpr, 0, sel) +#define MIPS64_CFC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_CF, gpr, cpr, 0, 0) +#define MIPS64_CTC1(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP1, MIPS64_COP_CT, gpr, cpr, 0, 0) +#define MIPS64_CFC2(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_CF, gpr, cpr, 0, sel) +#define MIPS64_CTC2(gpr, cpr, sel) MIPS64_R_INST(MIPS64_OP_COP2, MIPS64_COP_CT, gpr, cpr, 0, sel) +#define MIPS64_LBU(reg, off, base) MIPS64_I_INST(MIPS64_OP_LBU, base, reg, off) +#define MIPS64_LHU(reg, off, base) MIPS64_I_INST(MIPS64_OP_LHU, base, reg, off) +#define MIPS64_LUI(reg, val) MIPS64_I_INST(MIPS64_OP_LUI, 0, reg, val) +#define MIPS64_LW(reg, off, base) MIPS64_I_INST(MIPS64_OP_LW, base, reg, off) +#define MIPS64_LD(reg, off, base) MIPS64_I_INST(MIPS64_OP_LD, base, reg, off) +#define MIPS64_MFLO(reg) MIPS64_R_INST(0, 0, 0, reg, 0, MIPS64_OP_MFLO) +#define MIPS64_MFHI(reg) MIPS64_R_INST(0, 0, 0, reg, 0, MIPS64_OP_MFHI) +#define MIPS64_MTLO(reg) MIPS64_R_INST(0, reg, 0, 0, 0, MIPS64_OP_MTLO) +#define MIPS64_MTHI(reg) MIPS64_R_INST(0, reg, 0, 0, 0, MIPS64_OP_MTHI) +#define MIPS64_ORI(src, tar, val) MIPS64_I_INST(MIPS64_OP_ORI, src, tar, val) +#define MIPS64_SB(reg, off, base) MIPS64_I_INST(MIPS64_OP_SB, base, reg, off) +#define MIPS64_SH(reg, off, base) MIPS64_I_INST(MIPS64_OP_SH, base, reg, off) +#define MIPS64_SW(reg, off, base) MIPS64_I_INST(MIPS64_OP_SW, base, reg, off) +#define MIPS64_SD(reg, off, base) MIPS64_I_INST(MIPS64_OP_SD, base, reg, off) +#define MIPS64_CACHE(op, reg, off) (47 << 26 | (reg) << 21 | (op) << 16 | (off)) +#define MIPS64_SYNCI(reg, off) (1 << 26 | (reg) << 21 | 0x1f << 16 | (off)) +#define MIPS64_JR(reg) MIPS64_R_INST(0, reg, 0, 0, 0, MIPS64_OP_JR) + +/* ejtag specific instructions */ +#define MIPS64_DRET 0x4200001F +#define MIPS64_SDBBP 0x7000003F +#define MIPS64_SDBBP_LE 0x3f000007 +#define MIPS64_SDBBP_SIZE 4 +#define MIPS16_SDBBP_SIZE 2 + +#define MIPS64_SYNC 0x0000000F + +int mips64_arch_state(struct target *target); +int mips64_init_arch_info(struct target *target, struct mips64_common *mips64, struct jtag_tap *tap); +int mips64_restore_context(struct target *target); +int mips64_save_context(struct target *target); +int mips64_build_reg_cache(struct target *target); +int mips64_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + target_addr_t entry_point, target_addr_t exit_point, + int timeout_ms, void *arch_info); +int mips64_configure_break_unit(struct target *target); +int mips64_enable_interrupts(struct target *target, bool enable); +int mips64_examine(struct target *target); + +int mips64_register_commands(struct command_context *cmd_ctx); +int mips64_invalidate_core_regs(struct target *target); +int mips64_get_gdb_reg_list(struct target *target, + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class); + +#endif /* OPENOCD_TARGET_MIPS64_H */ diff --git a/src/target/mips64_pracc.c b/src/target/mips64_pracc.c new file mode 100644 index 0000000..b19fd04 --- /dev/null +++ b/src/target/mips64_pracc.c @@ -0,0 +1,1427 @@ +/* + * Support for processors implementing MIPS64 instruction set + * + * Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com> + * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru> + * Copyright (C) 2014-2019 by Peter Mamonov <pmamonov@gmail.com> + * + * Based on the work of: + * Copyright (C) 2008 by Spencer Oliver + * Copyright (C) 2008 by David T.L. Wong + * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mips64.h" +#include "mips64_pracc.h" + +#include "time_support.h" + +#define STACK_DEPTH 32 + +typedef struct { + uint64_t *local_iparam; + unsigned num_iparam; + uint64_t *local_oparam; + unsigned num_oparam; + const uint32_t *code; + unsigned code_len; + uint64_t stack[STACK_DEPTH]; + unsigned stack_offset; + struct mips_ejtag *ejtag_info; +} mips64_pracc_context; + +static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl) +{ + uint32_t ejtag_ctrl; + int nt = 5; + int rc; + + while (1) { + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); + ejtag_ctrl = ejtag_info->ejtag_ctrl; + rc = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); + if (rc != ERROR_OK) + return rc; + + if (ejtag_ctrl & EJTAG_CTRL_PRACC) + break; + LOG_DEBUG("DEBUGMODULE: No memory access in progress!\n"); + if (nt == 0) + return ERROR_JTAG_DEVICE_ERROR; + nt--; + } + + *ctrl = ejtag_ctrl; + return ERROR_OK; +} + +static int mips64_pracc_exec_read(mips64_pracc_context *ctx, uint64_t address) +{ + struct mips_ejtag *ejtag_info = ctx->ejtag_info; + unsigned offset; + uint32_t ejtag_ctrl; + uint64_t data; + int rc; + + if ((address >= MIPS64_PRACC_PARAM_IN) + && (address < MIPS64_PRACC_PARAM_IN + ctx->num_iparam * MIPS64_PRACC_DATA_STEP)) { + + offset = (address - MIPS64_PRACC_PARAM_IN) / MIPS64_PRACC_DATA_STEP; + + if (offset >= MIPS64_PRACC_PARAM_IN_SIZE) { + LOG_ERROR("Error: iparam size exceeds MIPS64_PRACC_PARAM_IN_SIZE"); + return ERROR_JTAG_DEVICE_ERROR; + } + + if (ctx->local_iparam == NULL) { + LOG_ERROR("Error: unexpected reading of input parameter"); + return ERROR_JTAG_DEVICE_ERROR; + } + + data = ctx->local_iparam[offset]; + LOG_DEBUG("Reading %" PRIx64 " at %" PRIx64, data, address); + + } else if ((address >= MIPS64_PRACC_PARAM_OUT) + && (address < MIPS64_PRACC_PARAM_OUT + ctx->num_oparam * MIPS64_PRACC_DATA_STEP)) { + + offset = (address - MIPS64_PRACC_PARAM_OUT) / MIPS64_PRACC_DATA_STEP; + if (ctx->local_oparam == NULL) { + LOG_ERROR("Error: unexpected reading of output parameter"); + return ERROR_JTAG_DEVICE_ERROR; + } + + data = ctx->local_oparam[offset]; + LOG_DEBUG("Reading %" PRIx64 " at %" PRIx64, data, address); + + } else if ((address >= MIPS64_PRACC_TEXT) + && (address < MIPS64_PRACC_TEXT + ctx->code_len * MIPS64_PRACC_ADDR_STEP)) { + + offset = ((address & ~7ull) - MIPS64_PRACC_TEXT) / MIPS64_PRACC_ADDR_STEP; + data = (uint64_t)ctx->code[offset] << 32; + if (offset + 1 < ctx->code_len) + data |= (uint64_t)ctx->code[offset + 1]; + + LOG_DEBUG("Running commands %" PRIx64 " at %" PRIx64, data, + address); + + } else if ((address & ~7llu) == MIPS64_PRACC_STACK) { + + /* load from our debug stack */ + if (ctx->stack_offset == 0) { + LOG_ERROR("Error reading from stack: stack is empty"); + return ERROR_JTAG_DEVICE_ERROR; + } + + data = ctx->stack[--ctx->stack_offset]; + LOG_DEBUG("Reading %" PRIx64 " at %" PRIx64, data, address); + + } else { + /* TODO: send JMP 0xFF200000 instruction. Hopefully processor jump back + * to start of debug vector */ + + data = 0; + LOG_ERROR("Error reading unexpected address %" PRIx64, address); + return ERROR_JTAG_DEVICE_ERROR; + } + + /* Send the data out */ + mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA); + rc = mips_ejtag_drscan_64(ctx->ejtag_info, &data); + if (rc != ERROR_OK) + return rc; + + /* Clear the access pending bit (let the processor eat!) */ + + ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; + mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL); + rc = mips_ejtag_drscan_32(ctx->ejtag_info, &ejtag_ctrl); + if (rc != ERROR_OK) + return rc; + + jtag_add_clocks(5); + + return jtag_execute_queue(); +} + +static int mips64_pracc_exec_write(mips64_pracc_context *ctx, uint64_t address) +{ + uint32_t ejtag_ctrl; + uint64_t data; + unsigned offset; + struct mips_ejtag *ejtag_info = ctx->ejtag_info; + int rc; + + mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA); + rc = mips_ejtag_drscan_64(ctx->ejtag_info, &data); + if (rc != ERROR_OK) + return rc; + + /* Clear access pending bit */ + ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; + mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL); + rc = mips_ejtag_drscan_32(ctx->ejtag_info, &ejtag_ctrl); + if (rc != ERROR_OK) + return rc; + + jtag_add_clocks(5); + rc = jtag_execute_queue(); + if (rc != ERROR_OK) + return rc; + + LOG_DEBUG("Writing %" PRIx64 " at %" PRIx64, data, address); + + if ((address >= MIPS64_PRACC_PARAM_IN) + && (address < MIPS64_PRACC_PARAM_IN + ctx->num_iparam * MIPS64_PRACC_DATA_STEP)) { + offset = (address - MIPS64_PRACC_PARAM_IN) / MIPS64_PRACC_DATA_STEP; + if (ctx->local_iparam == NULL) { + LOG_ERROR("Error: unexpected writing of input parameter"); + return ERROR_JTAG_DEVICE_ERROR; + } + ctx->local_iparam[offset] = data; + } else if ((address >= MIPS64_PRACC_PARAM_OUT) + && (address < MIPS64_PRACC_PARAM_OUT + ctx->num_oparam * MIPS64_PRACC_DATA_STEP)) { + offset = (address - MIPS64_PRACC_PARAM_OUT) / MIPS64_PRACC_DATA_STEP; + if (ctx->local_oparam == NULL) { + LOG_ERROR("Error: unexpected writing of output parameter"); + return ERROR_JTAG_DEVICE_ERROR; + } + ctx->local_oparam[offset] = data; + } else if (address == MIPS64_PRACC_STACK) { + /* save data onto our stack */ + if (ctx->stack_offset >= STACK_DEPTH) { + LOG_ERROR("Error: PrAcc stack depth exceeded"); + return ERROR_FAIL; + } + ctx->stack[ctx->stack_offset++] = data; + } else { + LOG_ERROR("Error writing unexpected address 0x%" PRIx64, address); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +int mips64_pracc_exec(struct mips_ejtag *ejtag_info, + unsigned code_len, const uint32_t *code, + unsigned num_param_in, uint64_t *param_in, + unsigned num_param_out, uint64_t *param_out) +{ + uint32_t ejtag_ctrl; + uint64_t address = 0, address_prev = 0, data; + mips64_pracc_context ctx; + int retval; + int pass = 0; + bool first_time_call = true; + unsigned i; + + for (i = 0; i < code_len; i++) + LOG_DEBUG("%08x", code[i]); + + ctx.local_iparam = param_in; + ctx.local_oparam = param_out; + ctx.num_iparam = num_param_in; + ctx.num_oparam = num_param_out; + ctx.code = code; + ctx.code_len = code_len; + ctx.ejtag_info = ejtag_info; + ctx.stack_offset = 0; + + while (true) { + uint32_t address32; + retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); + if (retval != ERROR_OK) { + LOG_DEBUG("ERROR wait_for_pracc_rw"); + return retval; + } + if (pass) + address_prev = address; + else + address_prev = 0; + address32 = data = 0; + + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); + mips_ejtag_drscan_32(ejtag_info, &address32); + LOG_DEBUG("-> %08x", address32); + address = 0xffffffffff200000ull | address32; + + int psz = (ejtag_ctrl >> 29) & 3; + int address20 = address & 7; + switch (psz) { + case 3: + if (address20 != 7) { + LOG_ERROR("PSZ=%d ADDRESS[2:0]=%d: not supported", psz, address20); + return ERROR_FAIL; + } + address &= ~7ull; + break; + case 2: + if (address20 != 0 && address20 != 4) { + LOG_ERROR("PSZ=%d ADDRESS[2:0]=%d: not supported", psz, address20); + return ERROR_FAIL; + } + break; + default: + LOG_ERROR("PSZ=%d ADDRESS[2:0]=%d: not supported", psz, address20); + return ERROR_FAIL; + } + + if (first_time_call && address != MIPS64_PRACC_TEXT) { + LOG_ERROR("Error reading address " TARGET_ADDR_FMT " (0x%08llx expected)", + address, MIPS64_PRACC_TEXT); + return ERROR_JTAG_DEVICE_ERROR; + } + + first_time_call = false; + + /* Check for read or write */ + if (ejtag_ctrl & EJTAG_CTRL_PRNW) { + retval = mips64_pracc_exec_write(&ctx, address); + if (retval != ERROR_OK) { + printf("ERROR mips64_pracc_exec_write\n"); + return retval; + } + } else { + /* Check to see if its reading at the debug vector. The first pass through + * the module is always read at the vector, so the first one we allow. When + * the second read from the vector occurs we are done and just exit. */ + if ((address == MIPS64_PRACC_TEXT) && (pass++)) { + LOG_DEBUG("@MIPS64_PRACC_TEXT, address_prev=%" PRIx64, address_prev); + break; + } + retval = mips64_pracc_exec_read(&ctx, address); + if (retval != ERROR_OK) { + printf("ERROR mips64_pracc_exec_read\n"); + return retval; + } + + } + } + + /* stack sanity check */ + if (ctx.stack_offset != 0) + LOG_ERROR("Pracc Stack not zero"); + + return ERROR_OK; +} + +static int mips64_pracc_read_u64(struct mips_ejtag *ejtag_info, uint64_t addr, + uint64_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* load R8 @ param_in[0] = address */ + MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* ld $8, 0($8), Load $8 with the word @mem[$8] */ + MIPS64_LD(8, 0, 8), + /* sd $8, 0($15) */ + MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(10)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + uint64_t param_in[1]; + param_in[0] = addr; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + ARRAY_SIZE(param_in), param_in, 1, (uint64_t *) buf); +} + +static int mips64_pracc_read_mem64(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned count, uint64_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_read_u64(ejtag_info, addr + 8*i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_read_u32(struct mips_ejtag *ejtag_info, uint64_t addr, + uint32_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* load R8 @ param_in[0] = address */ + MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* lw $8, 0($8), Load $8 with the word @mem[$8] */ + MIPS64_LW(8, 0, 8), + /* sd $8, 0($9) */ + MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(10)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + int retval = ERROR_OK; + uint64_t param_in[1]; + uint64_t param_out[1]; + + param_in[0] = addr; + + LOG_DEBUG("enter mips64_pracc_exec"); + retval = mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + 1, param_in, 1, param_out); + buf[0] = (uint32_t) param_out[0]; + return retval; +} + +static int mips64_pracc_read_mem32(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned count, uint32_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_read_u32(ejtag_info, addr + 4 * i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_read_u16(struct mips_ejtag *ejtag_info, uint64_t addr, + uint16_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* load R8 @ param_in[0] = address */ + MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* lw $8, 0($8), Load $8 with the word @mem[$8] */ + MIPS64_LHU(8, 0, 8), + /* sd $8, 0($9) */ + MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(10)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + int retval; + uint64_t param_in[1]; + uint64_t param_out[1]; + + param_in[0] = addr; + + LOG_DEBUG("enter mips64_pracc_exec"); + retval = mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + 1, param_in, 1, param_out); + buf[0] = (uint16_t)param_out[0]; + return retval; +} + +static int mips64_pracc_read_mem16(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned count, uint16_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_read_u16(ejtag_info, addr + 2*i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_read_u8(struct mips_ejtag *ejtag_info, uint64_t addr, + uint8_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* load R8 @ param_in[0] = address */ + MIPS64_LD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* lw $8, 0($8), Load $8 with the word @mem[$8] */ + MIPS64_LBU(8, 0, 8), + /* sd $8, 0($9) */ + MIPS64_SD(8, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_OUT), 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(10)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + int retval; + uint64_t param_in[1]; + uint64_t param_out[1]; + + param_in[0] = addr; + + LOG_DEBUG("enter mips64_pracc_exec"); + retval = mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + 1, param_in, 1, param_out); + buf[0] = (uint8_t)param_out[0]; + return retval; +} + +static int mips64_pracc_read_mem8(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned count, uint8_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_read_u8(ejtag_info, addr + i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +int mips64_pracc_read_mem(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned size, unsigned count, void *buf) +{ + switch (size) { + case 1: + return mips64_pracc_read_mem8(ejtag_info, addr, count, buf); + case 2: + return mips64_pracc_read_mem16(ejtag_info, addr, count, buf); + case 4: + return mips64_pracc_read_mem32(ejtag_info, addr, count, buf); + case 8: + return mips64_pracc_read_mem64(ejtag_info, addr, count, buf); + } + return ERROR_FAIL; +} + +static int mips64_pracc_write_u64(struct mips_ejtag *ejtag_info, uint64_t addr, + uint64_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* sd $9, ($15) */ + MIPS64_SD(9, 0, 15), + /* load R8 @ param_in[1] = data */ + MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN)-8), 15), + /* load R9 @ param_in[0] = address */ + MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* sd $8, 0($9) */ + MIPS64_SD(8, 0, 9), + MIPS64_SYNCI(9, 0), + /* ld $9, ($15) */ + MIPS64_LD(9, 0, 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(13)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + /* TODO remove array */ + uint64_t param_in[2]; + param_in[0] = addr; + param_in[1] = *buf; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + ARRAY_SIZE(param_in), param_in, 0, NULL); +} + +static int mips64_pracc_write_mem64(struct mips_ejtag *ejtag_info, + uint64_t addr, unsigned count, uint64_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_write_u64(ejtag_info, addr + 8 * i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_write_u32(struct mips_ejtag *ejtag_info, uint64_t addr, + uint32_t *buf) +{ + const uint32_t code[] = { + MIPS64_DMTC0(15, 31, 0), + /* move $15 to COP0 DeSave */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + MIPS64_SD(8, 0, 15), + /* sd $8, ($15) */ + MIPS64_SD(9, 0, 15), + /* sd $9, ($15) */ + MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN) - 8), 15), + /* load R8 @ param_in[1] = data */ + MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* load R9 @ param_in[0] = address */ + MIPS64_SW(8, 0, 9), + /* sw $8, 0($9) */ + MIPS64_SYNCI(9, 0), + MIPS64_LD(9, 0, 15), + /* ld $9, ($15) */ + MIPS64_LD(8, 0, 15), + /* ld $8, ($15) */ + MIPS64_SYNC, + MIPS64_B(NEG16(13)), + /* b start */ + MIPS64_DMFC0(15, 31, 0), + /* move COP0 DeSave to $15 */ + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + /* TODO remove array */ + uint64_t param_in[1 + 1]; + param_in[0] = addr; + param_in[1] = *buf; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + ARRAY_SIZE(param_in), param_in, 0, NULL); +} + +static int mips64_pracc_write_mem32(struct mips_ejtag *ejtag_info, uint64_t addr, + unsigned count, uint32_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_write_u32(ejtag_info, addr + 4 * i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_write_u16(struct mips_ejtag *ejtag_info, uint64_t addr, + uint16_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* sd $9, ($15) */ + MIPS64_SD(9, 0, 15), + /* load R8 @ param_in[1] = data */ + MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN) - 8), 15), + /* load R9 @ param_in[0] = address */ + MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* sh $8, 0($9) */ + MIPS64_SH(8, 0, 9), + /* ld $9, ($15) */ + MIPS64_LD(9, 0, 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(12)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + uint64_t param_in[2]; + param_in[0] = addr; + param_in[1] = *buf; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + ARRAY_SIZE(param_in), param_in, 0, NULL); +} + +static int mips64_pracc_write_mem16(struct mips_ejtag *ejtag_info, + uint64_t addr, unsigned count, uint16_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_write_u16(ejtag_info, addr + 2 * i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +static int mips64_pracc_write_u8(struct mips_ejtag *ejtag_info, uint64_t addr, + uint8_t *buf) +{ + const uint32_t code[] = { + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $8, ($15) */ + MIPS64_SD(8, 0, 15), + /* sd $9, ($15) */ + MIPS64_SD(9, 0, 15), + /* load R8 @ param_in[1] = data */ + MIPS64_LD(8, NEG16((MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN) - 8), 15), + /* load R9 @ param_in[0] = address */ + MIPS64_LD(9, NEG16(MIPS64_PRACC_STACK-MIPS64_PRACC_PARAM_IN), 15), + /* sh $8, 0($9) */ + MIPS64_SB(8, 0, 9), + /* ld $9, ($15) */ + MIPS64_LD(9, 0, 15), + /* ld $8, ($15) */ + MIPS64_LD(8, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(12)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + /* TODO remove array */ + uint64_t param_in[2]; + param_in[0] = addr; + param_in[1] = *buf; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + ARRAY_SIZE(param_in), param_in, 0, NULL); +} + +static int mips64_pracc_write_mem8(struct mips_ejtag *ejtag_info, + uint64_t addr, unsigned count, uint8_t *buf) +{ + int retval = ERROR_OK; + + for (unsigned i = 0; i < count; i++) { + retval = mips64_pracc_write_u8(ejtag_info, addr + i, &buf[i]); + if (retval != ERROR_OK) + return retval; + } + return retval; +} + +int mips64_pracc_write_mem(struct mips_ejtag *ejtag_info, + uint64_t addr, unsigned size, + unsigned count, void *buf) +{ + switch (size) { + case 1: + return mips64_pracc_write_mem8(ejtag_info, addr, count, buf); + case 2: + return mips64_pracc_write_mem16(ejtag_info, addr, count, buf); + case 4: + return mips64_pracc_write_mem32(ejtag_info, addr, count, buf); + case 8: + return mips64_pracc_write_mem64(ejtag_info, addr, count, buf); + } + return ERROR_FAIL; +} + +int mips64_pracc_write_regs(struct mips_ejtag *ejtag_info, uint64_t *regs) +{ + const uint32_t code[] = { + /* move $2 to COP0 DeSave */ + MIPS64_DMTC0(2, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(2, UPPER16(MIPS64_PRACC_PARAM_IN)), + MIPS64_ORI(2, 2, LOWER16(MIPS64_PRACC_PARAM_IN)), + /* sd $0, 0*8($2) */ + MIPS64_LD(1, 1*8, 2), + /* sd $1, 1*8($2) */ + MIPS64_LD(15, 15*8, 2), + /* sd $11, ($15) */ + MIPS64_DMFC0(2, 31, 0), + MIPS64_DMTC0(15, 31, 0), + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + MIPS64_SD(1, 0, 15), + /* $11 = MIPS64_PRACC_PARAM_OUT */ + MIPS64_LUI(1, UPPER16(MIPS64_PRACC_PARAM_IN)), + MIPS64_ORI(1, 1, LOWER16(MIPS64_PRACC_PARAM_IN)), + MIPS64_LD(3, 3*8, 1), + MIPS64_LD(4, 4*8, 1), + MIPS64_LD(5, 5*8, 1), + MIPS64_LD(6, 6*8, 1), + MIPS64_LD(7, 7*8, 1), + MIPS64_LD(8, 8*8, 1), + MIPS64_LD(9, 9*8, 1), + MIPS64_LD(10, 10*8, 1), + MIPS64_LD(11, 11*8, 1), + MIPS64_LD(12, 12*8, 1), + MIPS64_LD(13, 13*8, 1), + MIPS64_LD(14, 14*8, 1), + MIPS64_LD(16, 16*8, 1), + MIPS64_LD(17, 17*8, 1), + MIPS64_LD(18, 18*8, 1), + MIPS64_LD(19, 19*8, 1), + MIPS64_LD(20, 20*8, 1), + MIPS64_LD(21, 21*8, 1), + MIPS64_LD(22, 22*8, 1), + MIPS64_LD(23, 23*8, 1), + MIPS64_LD(24, 24*8, 1), + MIPS64_LD(25, 25*8, 1), + MIPS64_LD(26, 26*8, 1), + MIPS64_LD(27, 27*8, 1), + MIPS64_LD(28, 28*8, 1), + MIPS64_LD(29, 29*8, 1), + MIPS64_LD(30, 30*8, 1), + MIPS64_LD(31, 31*8, 1), + MIPS64_LD(2, 32*8, 1), + MIPS64_MTLO(2), + MIPS64_LD(2, 33*8, 1), + MIPS64_MTHI(2), + MIPS64_LD(2, MIPS64_NUM_CORE_REGS * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_DEPC, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 2) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_ENTRYLO0, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 3) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_ENTRYLO1, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 4) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_CONTEXT, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 5) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_PAGEMASK, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 6) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_WIRED, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 8) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_COUNT, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 9) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_ENTRYHI, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 10) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_COMPARE, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 11) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_STATUS, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 12) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_CAUSE, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 13) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_EPC, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 15) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_CONFIG, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 16) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_LLA, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 21) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_XCONTEXT, 1), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 22) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_MEMCTRL, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 24) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 25) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 1), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 26) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 2), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 27) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_PERFCOUNT, 3), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 28) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_ECC, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 29) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_CACHERR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 30) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_TAGLO, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 31) * 8, 1), + MIPS64_MTC0(2, MIPS64_C0_TAGHI, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 32) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_DATAHI, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_REGS + 33) * 8, 1), + MIPS64_DMTC0(2, MIPS64_C0_EEPC, 0), + /* check if FPU is enabled, */ + MIPS64_MFC0(2, MIPS64_C0_STATUS, 0), + MIPS64_SRL(2, 2, 29), + MIPS64_ANDI(2, 2, 1), + /* skip FPU registers restoration if not */ + MIPS64_BEQ(0, 2, 77), + MIPS64_NOP, + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 33) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FIR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 32) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FCSR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 34) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FCONFIG, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 35) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FCCR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 36) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FEXR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 37) * 8, 1), + MIPS64_CTC1(2, MIPS64_C1_FENR, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 0) * 8, 1), + MIPS64_DMTC1(2, 0, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 1) * 8, 1), + MIPS64_DMTC1(2, 1, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 2) * 8, 1), + MIPS64_DMTC1(2, 2, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 3) * 8, 1), + MIPS64_DMTC1(2, 3, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 4) * 8, 1), + MIPS64_DMTC1(2, 4, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 5) * 8, 1), + MIPS64_DMTC1(2, 5, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 6) * 8, 1), + MIPS64_DMTC1(2, 6, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 7) * 8, 1), + MIPS64_DMTC1(2, 7, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 8) * 8, 1), + MIPS64_DMTC1(2, 8, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 9) * 8, 1), + MIPS64_DMTC1(2, 9, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 10) * 8, 1), + MIPS64_DMTC1(2, 10, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 11) * 8, 1), + MIPS64_DMTC1(2, 11, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 12) * 8, 1), + MIPS64_DMTC1(2, 12, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 13) * 8, 1), + MIPS64_DMTC1(2, 13, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 14) * 8, 1), + MIPS64_DMTC1(2, 14, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 15) * 8, 1), + MIPS64_DMTC1(2, 15, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 16) * 8, 1), + MIPS64_DMTC1(2, 16, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 17) * 8, 1), + MIPS64_DMTC1(2, 17, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 18) * 8, 1), + MIPS64_DMTC1(2, 18, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 19) * 8, 1), + MIPS64_DMTC1(2, 19, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 20) * 8, 1), + MIPS64_DMTC1(2, 20, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 21) * 8, 1), + MIPS64_DMTC1(2, 21, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 22) * 8, 1), + MIPS64_DMTC1(2, 22, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 23) * 8, 1), + MIPS64_DMTC1(2, 23, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 24) * 8, 1), + MIPS64_DMTC1(2, 24, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 25) * 8, 1), + MIPS64_DMTC1(2, 25, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 26) * 8, 1), + MIPS64_DMTC1(2, 26, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 27) * 8, 1), + MIPS64_DMTC1(2, 27, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 28) * 8, 1), + MIPS64_DMTC1(2, 28, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 29) * 8, 1), + MIPS64_DMTC1(2, 29, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 30) * 8, 1), + MIPS64_DMTC1(2, 30, 0), + MIPS64_LD(2, (MIPS64_NUM_CORE_C0_REGS + 31) * 8, 1), + MIPS64_DMTC1(2, 31, 0), + MIPS64_LD(2, 2 * 8, 1), + MIPS64_LD(1, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(181)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + MIPS64_NUM_REGS, regs, 0, NULL); +} + +int mips64_pracc_read_regs(struct mips_ejtag *ejtag_info, uint64_t *regs) +{ + const uint32_t code[] = { + /* move $2 to COP0 DeSave */ + MIPS64_DMTC0(2, 31, 0), + /* $2 = MIPS64_PRACC_PARAM_OUT */ + MIPS64_LUI(2, UPPER16(MIPS64_PRACC_PARAM_OUT)), + MIPS64_ORI(2, 2, LOWER16(MIPS64_PRACC_PARAM_OUT)), + /* sd $0, 0*8($2) */ + MIPS64_SD(0, 0*8, 2), + /* sd $1, 1*8($2) */ + MIPS64_SD(1, 1*8, 2), + /* sd $15, 15*8($2) */ + MIPS64_SD(15, 15*8, 2), + /* move COP0 DeSave to $2 */ + MIPS64_DMFC0(2, 31, 0), + /* move $15 to COP0 DeSave */ + MIPS64_DMTC0(15, 31, 0), + /* $15 = MIPS64_PRACC_STACK */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + /* sd $1, ($15) */ + MIPS64_SD(1, 0, 15), + /* sd $2, ($15) */ + MIPS64_SD(2, 0, 15), + /* $1 = MIPS64_PRACC_PARAM_OUT */ + MIPS64_LUI(1, UPPER16(MIPS64_PRACC_PARAM_OUT)), + MIPS64_ORI(1, 1, LOWER16(MIPS64_PRACC_PARAM_OUT)), + MIPS64_SD(2, 2 * 8, 1), + MIPS64_SD(3, 3 * 8, 1), + MIPS64_SD(4, 4 * 8, 1), + MIPS64_SD(5, 5 * 8, 1), + MIPS64_SD(6, 6 * 8, 1), + MIPS64_SD(7, 7 * 8, 1), + MIPS64_SD(8, 8 * 8, 1), + MIPS64_SD(9, 9 * 8, 1), + MIPS64_SD(10, 10 * 8, 1), + MIPS64_SD(11, 11 * 8, 1), + MIPS64_SD(12, 12 * 8, 1), + MIPS64_SD(13, 13 * 8, 1), + MIPS64_SD(14, 14 * 8, 1), + MIPS64_SD(16, 16 * 8, 1), + MIPS64_SD(17, 17 * 8, 1), + MIPS64_SD(18, 18 * 8, 1), + MIPS64_SD(19, 19 * 8, 1), + MIPS64_SD(20, 20 * 8, 1), + MIPS64_SD(21, 21 * 8, 1), + MIPS64_SD(22, 22 * 8, 1), + MIPS64_SD(23, 23 * 8, 1), + MIPS64_SD(24, 24 * 8, 1), + MIPS64_SD(25, 25 * 8, 1), + MIPS64_SD(26, 26 * 8, 1), + MIPS64_SD(27, 27 * 8, 1), + MIPS64_SD(28, 28 * 8, 1), + MIPS64_SD(29, 29 * 8, 1), + MIPS64_SD(30, 30 * 8, 1), + MIPS64_SD(31, 31 * 8, 1), + MIPS64_MFLO(2), + MIPS64_SD(2, 32 * 8, 1), + MIPS64_MFHI(2), + MIPS64_SD(2, 33 * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_DEPC, 0), + MIPS64_SD(2, MIPS64_NUM_CORE_REGS * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_RANDOM, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 1) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_ENTRYLO0, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 2) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_ENTRYLO1, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 3) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_CONTEXT, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 4) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PAGEMASK, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 5) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_WIRED, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 6) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_BADVADDR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 7) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_COUNT, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 8) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_ENTRYHI, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 9) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_COMPARE, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 10) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_STATUS, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 11) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_CAUSE, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 12) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_EPC, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 13) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PRID, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 14) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_CONFIG, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 15) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_LLA, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 16) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_XCONTEXT, 1), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 21) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_MEMCTRL, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 22) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_DEBUG, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 23) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 24) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 1), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 25) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 2), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 26) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_PERFCOUNT, 3), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 27) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_ECC, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 28) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_CACHERR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 29) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_TAGLO, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 30) * 8, 1), + MIPS64_MFC0(2, MIPS64_C0_TAGHI, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 31) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_DATAHI, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 32) * 8, 1), + MIPS64_DMFC0(2, MIPS64_C0_EEPC, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_REGS + 33) * 8, 1), + /* check if FPU is enabled, */ + MIPS64_MFC0(2, MIPS64_C0_STATUS, 0), + MIPS64_SRL(2, 2, 29), + MIPS64_ANDI(2, 2, 1), + /* skip FPU registers dump if not */ + MIPS64_BEQ(0, 2, 77), + MIPS64_NOP, + MIPS64_CFC1(2, MIPS64_C1_FIR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 33) * 8, 1), + MIPS64_CFC1(2, MIPS64_C1_FCSR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 32) * 8, 1), + MIPS64_CFC1(2, MIPS64_C1_FCONFIG, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 34) * 8, 1), + MIPS64_CFC1(2, MIPS64_C1_FCCR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 35) * 8, 1), + MIPS64_CFC1(2, MIPS64_C1_FEXR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 36) * 8, 1), + MIPS64_CFC1(2, MIPS64_C1_FENR, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 37) * 8, 1), + MIPS64_DMFC1(2, 0, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 0) * 8, 1), + MIPS64_DMFC1(2, 1, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 1) * 8, 1), + MIPS64_DMFC1(2, 2, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 2) * 8, 1), + MIPS64_DMFC1(2, 3, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 3) * 8, 1), + MIPS64_DMFC1(2, 4, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 4) * 8, 1), + MIPS64_DMFC1(2, 5, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 5) * 8, 1), + MIPS64_DMFC1(2, 6, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 6) * 8, 1), + MIPS64_DMFC1(2, 7, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 7) * 8, 1), + MIPS64_DMFC1(2, 8, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 8) * 8, 1), + MIPS64_DMFC1(2, 9, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 9) * 8, 1), + MIPS64_DMFC1(2, 10, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 10) * 8, 1), + MIPS64_DMFC1(2, 11, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 11) * 8, 1), + MIPS64_DMFC1(2, 12, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 12) * 8, 1), + MIPS64_DMFC1(2, 13, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 13) * 8, 1), + MIPS64_DMFC1(2, 14, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 14) * 8, 1), + MIPS64_DMFC1(2, 15, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 15) * 8, 1), + MIPS64_DMFC1(2, 16, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 16) * 8, 1), + MIPS64_DMFC1(2, 17, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 17) * 8, 1), + MIPS64_DMFC1(2, 18, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 18) * 8, 1), + MIPS64_DMFC1(2, 19, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 19) * 8, 1), + MIPS64_DMFC1(2, 20, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 20) * 8, 1), + MIPS64_DMFC1(2, 21, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 21) * 8, 1), + MIPS64_DMFC1(2, 22, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 22) * 8, 1), + MIPS64_DMFC1(2, 23, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 23) * 8, 1), + MIPS64_DMFC1(2, 24, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 24) * 8, 1), + MIPS64_DMFC1(2, 25, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 25) * 8, 1), + MIPS64_DMFC1(2, 26, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 26) * 8, 1), + MIPS64_DMFC1(2, 27, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 27) * 8, 1), + MIPS64_DMFC1(2, 28, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 28) * 8, 1), + MIPS64_DMFC1(2, 29, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 29) * 8, 1), + MIPS64_DMFC1(2, 30, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 30) * 8, 1), + MIPS64_DMFC1(2, 31, 0), + MIPS64_SD(2, (MIPS64_NUM_CORE_C0_REGS + 31) * 8, 1), + MIPS64_LD(2, 0, 15), + MIPS64_LD(1, 0, 15), + MIPS64_SYNC, + /* b start */ + MIPS64_B(NEG16(192)), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, + 0, NULL, MIPS64_NUM_REGS, regs); +} + +/* fastdata upload/download requires an initialized working area + * to load the download code; it should not be called otherwise + * fetch order from the fastdata area + * 1. start addr + * 2. end addr + * 3. data ... + */ +int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, + struct working_area *source, + bool write_t, uint64_t addr, + unsigned count, uint64_t *buf) +{ + uint32_t handler_code[] = { + /* caution when editing, table is modified below */ + /* r15 points to the start of this code */ + MIPS64_SD(8, MIPS64_FASTDATA_HANDLER_SIZE - 8, 15), + MIPS64_SD(9, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 2, 15), + MIPS64_SD(10, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 3, 15), + MIPS64_SD(11, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 4, 15), + /* start of fastdata area in t0 */ + MIPS64_LUI(8, UPPER16(MIPS64_PRACC_FASTDATA_AREA)), + MIPS64_ORI(8, 8, LOWER16(MIPS64_PRACC_FASTDATA_AREA)), + /* start addr in t1 */ + MIPS64_LD(9, 0, 8), + /* end addr to t2 */ + MIPS64_LD(10, 0, 8), + + /* loop: */ + /* lw t3,[t8 | r9] */ + /* 8 */ MIPS64_LD(11, 0, 0), + /* sw t3,[r9 | r8] */ + /* 9 */ MIPS64_SD(11, 0, 0), + /* bne $t2,t1,loop */ + MIPS64_BNE(10, 9, NEG16(3)), + /* addi t1,t1,4 */ + MIPS64_DADDIU(9, 9, 8), + + MIPS64_LD(8, MIPS64_FASTDATA_HANDLER_SIZE - 8, 15), + MIPS64_LD(9, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 2, 15), + MIPS64_LD(10, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 3, 15), + MIPS64_LD(11, MIPS64_FASTDATA_HANDLER_SIZE - 8 * 4, 15), + + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_TEXT)), + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_TEXT)), + /* jr start */ + MIPS64_JR(15), + /* move COP0 DeSave to $15 */ + MIPS64_DMFC0(15, 31, 0), + }; + + uint32_t jmp_code[] = { + /* addr of working area added below */ + /* 0 */ MIPS64_LUI(15, 0), + /* addr of working area added below */ + /* 1 */ MIPS64_ORI(15, 15, 0), + /* jump to ram program */ + MIPS64_JR(15), + MIPS64_NOP, + }; + + int retval; + unsigned i; + uint32_t ejtag_ctrl, address32; + uint64_t address, val; + + if (source->size < MIPS64_FASTDATA_HANDLER_SIZE) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + + if (write_t) { + /* load data from probe at fastdata area */ + handler_code[8] = MIPS64_LD(11, 0, 8); + /* store data to RAM @ r9 */ + handler_code[9] = MIPS64_SD(11, 0, 9); + } else { + /* load data from RAM @ r9 */ + handler_code[8] = MIPS64_LD(11, 0, 9); + /* store data to probe at fastdata area */ + handler_code[9] = MIPS64_SD(11, 0, 8); + } + + /* write program into RAM */ + if (write_t != ejtag_info->fast_access_save) { + mips64_pracc_write_mem(ejtag_info, source->address, 4, + ARRAY_SIZE(handler_code), handler_code); + /* save previous operation to speed to any consecutive read/writes */ + ejtag_info->fast_access_save = write_t; + } + + LOG_DEBUG("%s using " TARGET_ADDR_FMT " for write handler", __func__, + source->address); + LOG_DEBUG("daddiu: %08x", handler_code[11]); + + jmp_code[0] |= UPPER16(source->address); + jmp_code[1] |= LOWER16(source->address); + mips64_pracc_exec(ejtag_info, + ARRAY_SIZE(jmp_code), jmp_code, + 0, NULL, 0, NULL); + + /* next fetch to dmseg should be in FASTDATA_AREA, check */ + address = 0; + + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); + retval = mips_ejtag_drscan_32(ejtag_info, &address32); + if (retval != ERROR_OK) + return retval; + address = 0xffffffffff200000ull | address32; + if ((address & ~7ull) != MIPS64_PRACC_FASTDATA_AREA) { + LOG_ERROR("! @MIPS64_PRACC_FASTDATA_AREA (" TARGET_ADDR_FMT ")", address); + return ERROR_FAIL; + } + /* Send the load start address */ + val = addr; + LOG_DEBUG("start: " TARGET_ADDR_FMT, val); + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA); + mips64_ejtag_fastdata_scan(ejtag_info, 1, &val); + + retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); + if (retval != ERROR_OK) + return retval; + + /* Send the load end address */ + val = addr + (count - 1) * 8; + LOG_DEBUG("stop: " TARGET_ADDR_FMT, val); + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA); + mips64_ejtag_fastdata_scan(ejtag_info, 1, &val); + + /* like in legacy code */ + unsigned num_clocks = 0; + if (ejtag_info->mode != 0) + num_clocks = ((uint64_t)(ejtag_info->scan_delay) * jtag_get_speed_khz() + 500000) / 1000000; + LOG_DEBUG("num_clocks=%d", num_clocks); + for (i = 0; i < count; i++) { + jtag_add_clocks(num_clocks); + retval = mips64_ejtag_fastdata_scan(ejtag_info, write_t, buf++); + if (retval != ERROR_OK) { + LOG_ERROR("mips64_ejtag_fastdata_scan failed"); + return retval; + } + } + + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + LOG_ERROR("jtag_execute_queue failed"); + return retval; + } + + retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); + if (retval != ERROR_OK) { + LOG_ERROR("wait_for_pracc_rw failed"); + return retval; + } + + address = 0; + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); + retval = mips_ejtag_drscan_32(ejtag_info, &address32); + if (retval != ERROR_OK) { + LOG_ERROR("mips_ejtag_drscan_32 failed"); + return retval; + } + + address = 0xffffffffff200000ull | address32; + if ((address & ~7ull) != MIPS64_PRACC_TEXT) + LOG_ERROR("mini program did not return to start"); + + return retval; +} diff --git a/src/target/mips64_pracc.h b/src/target/mips64_pracc.h new file mode 100644 index 0000000..65ff6e6 --- /dev/null +++ b/src/target/mips64_pracc.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Support for processors implementing MIPS64 instruction set + * + * Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com> + * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru> + * Copyright (C) 2014-2019 by Peter Mamonov <pmamonov@gmail.com> + * + * Based on the work of: + * Copyright (C) 2008 by Spencer Oliver + * Copyright (C) 2008 by David T.L. Wong + * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev + */ + +#ifndef OPENOCD_TARGET_MIPS64_PRACC_H +#define OPENOCD_TARGET_MIPS64_PRACC_H + +#include "mips_ejtag.h" + +#define MIPS64_PRACC_TEXT 0xffffffffFF200200ull + +#define MIPS64_PRACC_STACK 0xffffffffFF204000ull +#define MIPS64_PRACC_PARAM_IN 0xffffffffFF201000ull +#define MIPS64_PRACC_PARAM_IN_SIZE 0x1000 +#define MIPS64_PRACC_PARAM_OUT (MIPS64_PRACC_PARAM_IN + MIPS64_PRACC_PARAM_IN_SIZE) +#define MIPS64_PRACC_PARAM_OUT_SIZE 0x1000 + +#undef UPPER16 +#undef LOWER16 +#define UPPER16(v) ((uint32_t)((v >> 16) & 0xFFFF)) +#define LOWER16(v) ((uint32_t)(v & 0xFFFF)) +#define MIPS64_PRACC_FASTDATA_AREA 0xffffffffFF200000 +#define MIPS64_PRACC_FASTDATA_SIZE 16 +#define MIPS64_FASTDATA_HANDLER_SIZE 0x80 + +/* FIXME: 16-bit NEG */ +#undef NEG16 +#define NEG16(v) ((uint32_t)(((~(v)) + 1) & 0xFFFF)) + +#define MIPS64_PRACC_ADDR_STEP 4 +#define MIPS64_PRACC_DATA_STEP 8 + +int mips64_pracc_read_mem(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned size, unsigned count, void *buf); +int mips64_pracc_write_mem(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned size, unsigned count, void *buf); + +int mips64_pracc_read_regs(struct mips_ejtag *ejtag_info, uint64_t *regs); +int mips64_pracc_write_regs(struct mips_ejtag *ejtag_info, uint64_t *regs); + +int mips64_pracc_exec(struct mips_ejtag *ejtag_info, + unsigned code_len, const uint32_t *code, + unsigned num_param_in, uint64_t *param_in, + unsigned num_param_out, uint64_t *param_out); + +int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, + struct working_area *source, + bool write_t, uint64_t addr, + unsigned count, uint64_t *buf); + +#endif /* OPENOCD_TARGET_MIPS64_PRACC_H */ diff --git a/src/target/mips_ejtag.c b/src/target/mips_ejtag.c index 03a0952..3735cbb 100644 --- a/src/target/mips_ejtag.c +++ b/src/target/mips_ejtag.c @@ -27,6 +27,8 @@ #include "mips32.h" #include "mips_ejtag.h" #include "mips32_dmaacc.h" +#include "mips64.h" +#include "mips64_pracc.h" void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, uint32_t new_instr) { @@ -38,7 +40,7 @@ void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, uint32_t new_instr) struct scan_field field; field.num_bits = tap->ir_length; - uint8_t t[4]; + uint8_t t[4] = { 0 }; field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); @@ -87,6 +89,36 @@ void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info, uint32_t ctrl, uint32 keep_alive(); } +int mips_ejtag_drscan_64(struct mips_ejtag *ejtag_info, uint64_t *data) +{ + struct jtag_tap *tap; + tap = ejtag_info->tap; + + if (tap == NULL) + return ERROR_FAIL; + struct scan_field field; + uint8_t t[8] = { 0 }, r[8]; + int retval; + + field.num_bits = 64; + field.out_value = t; + buf_set_u64(t, 0, field.num_bits, *data); + field.in_value = r; + + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + LOG_ERROR("register read failed"); + return retval; + } + + *data = buf_get_u64(field.in_value, 0, 64); + + keep_alive(); + + return ERROR_OK; +} + void mips_ejtag_drscan_32_queued(struct mips_ejtag *ejtag_info, uint32_t data_out, uint8_t *data_in) { assert(ejtag_info->tap != NULL); @@ -95,7 +127,7 @@ void mips_ejtag_drscan_32_queued(struct mips_ejtag *ejtag_info, uint32_t data_ou struct scan_field field; field.num_bits = 32; - uint8_t scan_out[4]; + uint8_t scan_out[4] = { 0 }; field.out_value = scan_out; buf_set_u32(scan_out, 0, field.num_bits, data_out); @@ -314,7 +346,7 @@ static void ejtag_main_print_imp(struct mips_ejtag *ejtag_info) EJTAG_IMP_HAS(EJTAG_IMP_ASID6) ? " ASID_6" : "", EJTAG_IMP_HAS(EJTAG_IMP_MIPS16) ? " MIPS16" : "", EJTAG_IMP_HAS(EJTAG_IMP_NODMA) ? " noDMA" : " DMA", - EJTAG_IMP_HAS(EJTAG_DCR_MIPS64) ? " MIPS64" : " MIPS32"); + EJTAG_IMP_HAS(EJTAG_IMP_MIPS64) ? " MIPS64" : " MIPS32"); switch (ejtag_info->ejtag_version) { case EJTAG_VERSION_20: @@ -422,3 +454,108 @@ int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_ return ERROR_OK; } + +int mips64_ejtag_config_step(struct mips_ejtag *ejtag_info, bool enable_step) +{ + const uint32_t code_enable[] = { + MIPS64_MTC0(1, 31, 0), /* move $1 to COP0 DeSave */ + MIPS64_MFC0(1, 23, 0), /* move COP0 Debug to $1 */ + MIPS64_ORI(1, 1, 0x0100), /* set SSt bit in debug reg */ + MIPS64_MTC0(1, 23, 0), /* move $1 to COP0 Debug */ + MIPS64_B(NEG16(5)), + MIPS64_MFC0(1, 31, 0), /* move COP0 DeSave to $1 */ + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + + const uint32_t code_disable[] = { + MIPS64_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */ + MIPS64_LUI(15, UPPER16(MIPS64_PRACC_STACK)), /* $15 = MIPS64_PRACC_STACK */ + MIPS64_ORI(15, 15, LOWER16(MIPS64_PRACC_STACK)), + MIPS64_SD(1, 0, 15), /* sw $1,($15) */ + MIPS64_SD(2, 0, 15), /* sw $2,($15) */ + MIPS64_MFC0(1, 23, 0), /* move COP0 Debug to $1 */ + MIPS64_LUI(2, 0xFFFF), /* $2 = 0xfffffeff */ + MIPS64_ORI(2, 2, 0xFEFF), + MIPS64_AND(1, 1, 2), + MIPS64_MTC0(1, 23, 0), /* move $1 to COP0 Debug */ + MIPS64_LD(2, 0, 15), + MIPS64_LD(1, 0, 15), + MIPS64_SYNC, + MIPS64_B(NEG16(14)), + MIPS64_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */ + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + const uint32_t *code = enable_step ? code_enable : code_disable; + unsigned code_len = enable_step ? ARRAY_SIZE(code_enable) : + ARRAY_SIZE(code_disable); + + return mips64_pracc_exec(ejtag_info, + code_len, code, 0, NULL, 0, NULL); +} + +int mips64_ejtag_exit_debug(struct mips_ejtag *ejtag_info) +{ + const uint32_t code[] = { + MIPS64_DRET, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + MIPS64_NOP, + }; + LOG_DEBUG("enter mips64_pracc_exec"); + return mips64_pracc_exec(ejtag_info, + ARRAY_SIZE(code), code, 0, NULL, 0, NULL); +} + +int mips64_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, bool write_t, uint64_t *data) +{ + struct jtag_tap *tap; + + tap = ejtag_info->tap; + assert(tap != NULL); + + struct scan_field fields[2]; + uint8_t spracc = 0; + uint8_t t[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + + /* fastdata 1-bit register */ + fields[0].num_bits = 1; + fields[0].out_value = &spracc; + fields[0].in_value = NULL; + + /* processor access data register 64 bit */ + fields[1].num_bits = 64; + fields[1].out_value = t; + + if (write_t) { + fields[1].in_value = NULL; + buf_set_u64(t, 0, 64, *data); + } else + fields[1].in_value = (uint8_t *) data; + + jtag_add_dr_scan(tap, 2, fields, TAP_IDLE); + + if (!write_t && data) + jtag_add_callback(mips_le_to_h_u64, + (jtag_callback_data_t) data); + keep_alive(); + + return ERROR_OK; +} diff --git a/src/target/mips_ejtag.h b/src/target/mips_ejtag.h index c64e858..ace3d28 100644 --- a/src/target/mips_ejtag.h +++ b/src/target/mips_ejtag.h @@ -130,7 +130,7 @@ /* v2.0 - 1:4 Number of Break Channels. */ #define EJTAG_V20_IMP_BCHANNELS_MASK 0xf #define EJTAG_V20_IMP_BCHANNELS_SHIFT 1 -#define EJTAG_DCR_MIPS64 (1 << 0) +#define EJTAG_IMP_MIPS64 (1 << 0) /* Debug Control Register DCR */ #define EJTAG_DCR 0xFF300000 @@ -182,6 +182,20 @@ #define EJTAG_VERSION_41 4 #define EJTAG_VERSION_51 5 +/* + * Additional defines for MIPS64 EJTAG + */ +#define EJTAG64_DCR 0xFFFFFFFFFF300000ull +#define EJTAG64_DCR_ENM (1llu << 29) +#define EJTAG64_DCR_DB (1llu << 17) +#define EJTAG64_DCR_IB (1llu << 16) +#define EJTAG64_DCR_INTE (1llu << 4) +#define EJTAG64_DCR_MP (1llu << 2) +#define EJTAG64_V25_DBA0 0xFFFFFFFFFF302100ull +#define EJTAG64_V25_DBS 0xFFFFFFFFFF302000ull +#define EJTAG64_V25_IBA0 0xFFFFFFFFFF301100ull +#define EJTAG64_V25_IBS 0xFFFFFFFFFF301000ull + struct mips_ejtag { struct jtag_tap *tap; uint32_t impcode; @@ -224,17 +238,21 @@ struct mips_ejtag { void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, uint32_t new_instr); int mips_ejtag_enter_debug(struct mips_ejtag *ejtag_info); int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info); +int mips64_ejtag_exit_debug(struct mips_ejtag *ejtag_info); int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info); void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info, uint32_t ctrl, uint32_t data, uint8_t *in_scan_buf); +int mips_ejtag_drscan_64(struct mips_ejtag *ejtag_info, uint64_t *data); void mips_ejtag_drscan_32_out(struct mips_ejtag *ejtag_info, uint32_t data); int mips_ejtag_drscan_32(struct mips_ejtag *ejtag_info, uint32_t *data); void mips_ejtag_drscan_8_out(struct mips_ejtag *ejtag_info, uint8_t data); int mips_ejtag_drscan_8(struct mips_ejtag *ejtag_info, uint8_t *data); int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_t *data); +int mips64_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, bool write_t, uint64_t *data); int mips_ejtag_init(struct mips_ejtag *ejtag_info); int mips_ejtag_config_step(struct mips_ejtag *ejtag_info, int enable_step); +int mips64_ejtag_config_step(struct mips_ejtag *ejtag_info, bool enable_step); static inline void mips_le_to_h_u32(jtag_callback_data_t arg) { @@ -242,4 +260,10 @@ static inline void mips_le_to_h_u32(jtag_callback_data_t arg) *((uint32_t *)arg) = le_to_h_u32(in); } +static inline void mips_le_to_h_u64(jtag_callback_data_t arg) +{ + uint8_t *in = (uint8_t *)arg; + *((uint64_t *)arg) = le_to_h_u64(in); +} + #endif /* OPENOCD_TARGET_MIPS_EJTAG_H */ diff --git a/src/target/mips_mips64.c b/src/target/mips_mips64.c new file mode 100644 index 0000000..3a592f7 --- /dev/null +++ b/src/target/mips_mips64.c @@ -0,0 +1,1193 @@ +/* + * MIPS64 generic target support + * + * Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com> + * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru> + * Copyright (C) 2014-2019 by Peter Mamonov <pmamonov@gmail.com> + * + * Based on the work of: + * Copyright (C) 2008 by Spencer Oliver + * Copyright (C) 2008 by David T.L. Wong + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "breakpoints.h" +#include "mips32.h" +#include "mips64.h" +#include "mips_mips64.h" +#include "target_type.h" +#include "register.h" + +static int mips_mips64_unset_breakpoint(struct target *target, + struct breakpoint *breakpoint); + +static uint64_t mips64_extend_sign(uint64_t addr) +{ + if (addr >> 32) + return addr; + if (addr >> 31) + return addr | (ULLONG_MAX << 32); + return addr; +} + +static int mips_mips64_examine_debug_reason(struct target *target) +{ + if ((target->debug_reason != DBG_REASON_DBGRQ) + && (target->debug_reason != DBG_REASON_SINGLESTEP)) + target->debug_reason = DBG_REASON_BREAKPOINT; + + return ERROR_OK; +} + +static int mips_mips64_debug_entry(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + struct reg *pc = &mips64->core_cache->reg_list[MIPS64_PC]; + + mips64_save_context(target); + + /* make sure stepping disabled, SSt bit in CP0 debug register cleared */ + mips64_ejtag_config_step(ejtag_info, 0); + + /* make sure break unit configured */ + mips64_configure_break_unit(target); + + /* attempt to find halt reason */ + mips_mips64_examine_debug_reason(target); + + LOG_DEBUG("entered debug state at PC 0x%" PRIx64 ", target->state: %s", + *(uint64_t *)pc->value, target_state_name(target)); + + return ERROR_OK; +} + +static int mips_mips64_poll(struct target *target) +{ + int retval; + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl; + + /* read ejtag control reg */ + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); + mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); + + /* clear this bit before handling polling + * as after reset registers will read zero */ + if (ejtag_ctrl & EJTAG_CTRL_ROCC) { + /* we have detected a reset, clear flag + * otherwise ejtag will not work */ + ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_ROCC; + + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); + mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); + LOG_DEBUG("Reset Detected"); + } + + /* check for processor halted */ + if (ejtag_ctrl & EJTAG_CTRL_BRKST) { + if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) { + target->state = TARGET_HALTED; + retval = mips_mips64_debug_entry(target); + if (retval != ERROR_OK) + return retval; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } else if (target->state == TARGET_DEBUG_RUNNING) { + target->state = TARGET_HALTED; + retval = mips_mips64_debug_entry(target); + if (retval != ERROR_OK) + return retval; + + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); + } + } else { + target->state = TARGET_RUNNING; + } + + return ERROR_OK; +} + +static int mips_mips64_halt(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + + LOG_DEBUG("target->state: %s", + target_state_name(target)); + + if (target->state == TARGET_HALTED) { + LOG_DEBUG("target was already halted"); + return ERROR_OK; + } + + if (target->state == TARGET_UNKNOWN) + LOG_WARNING("target was in unknown state when halt was requested"); + + if (target->state == TARGET_RESET) { + if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) { + LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST"); + return ERROR_TARGET_FAILURE; + } else { + /* we came here in a reset_halt or reset_init sequence + * debug entry was already prepared in mips64_prepare_reset_halt() + */ + target->debug_reason = DBG_REASON_DBGRQ; + + return ERROR_OK; + } + } + + /* break processor */ + mips_ejtag_enter_debug(ejtag_info); + + target->debug_reason = DBG_REASON_DBGRQ; + + return ERROR_OK; +} + +static int mips_mips64_assert_reset(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + int retval; + + LOG_DEBUG("target->state: %s", + target_state_name(target)); + + enum reset_types jtag_reset_config = jtag_get_reset_config(); + if (!(jtag_reset_config & RESET_HAS_SRST)) { + LOG_ERROR("Can't assert SRST"); + return ERROR_FAIL; + } + + if (target->reset_halt) + /* use hardware to catch reset */ + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_EJTAGBOOT); + else + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_NORMALBOOT); + + /* here we should issue a srst only, but we may have to assert trst as well */ + if (jtag_reset_config & RESET_SRST_PULLS_TRST) + jtag_add_reset(1, 1); + else + jtag_add_reset(0, 1); + + target->state = TARGET_RESET; + jtag_add_sleep(5000); + + retval = mips64_invalidate_core_regs(target); + if (retval != ERROR_OK) + return retval; + + if (target->reset_halt) { + retval = target_halt(target); + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + +static int mips_mips64_deassert_reset(struct target *target) +{ + LOG_DEBUG("target->state: %s", + target_state_name(target)); + + /* deassert reset lines */ + jtag_add_reset(0, 0); + + return ERROR_OK; +} + +static int mips_mips64_soft_reset_halt(struct target *target) +{ + /* TODO */ + return ERROR_OK; +} + +static int mips_mips64_single_step_core(struct target *target) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + int retval; + + /* configure single step mode */ + mips64_ejtag_config_step(ejtag_info, 1); + + /* disable interrupts while stepping */ + retval = mips64_enable_interrupts(target, false); + if (retval != ERROR_OK) + return retval; + + /* exit debug mode */ + retval = mips64_ejtag_exit_debug(ejtag_info); + if (retval != ERROR_OK) + return retval; + + mips_mips64_debug_entry(target); + + return ERROR_OK; +} + +/* TODO: HW breakpoints are in EJTAG spec. Should we share it for MIPS32? */ +static int mips_mips64_set_hwbp(struct target *target, struct breakpoint *bp) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips64_comparator *c, *cl = mips64->inst_break_list; + uint64_t bp_value; + int retval, bp_num = 0; + + while (cl[bp_num].used && (bp_num < mips64->num_inst_bpoints)) + bp_num++; + + if (bp_num >= mips64->num_inst_bpoints) { + LOG_DEBUG("ERROR Can not find free FP Comparator(bpid: %d)", + bp->unique_id); + LOG_WARNING("ERROR Can not find free FP Comparator"); + exit(-1); + } + + c = &cl[bp_num]; + c->used = true; + c->bp_value = bp->address; + bp_value = bp->address; + + /* Instruction Breakpoint Address n (IBAn) Register */ + retval = target_write_u64(target, c->reg_address, bp_value); + if (retval != ERROR_OK) + return retval; + + /* TODO: use defines */ + /* Instruction Breakpoint Address Mask n (IBMn) Register */ + retval = target_write_u64(target, c->reg_address + 0x08, 0); + if (retval != ERROR_OK) + return retval; + + /* Instruction Breakpoint Control n (IBCn) Register */ + retval = target_write_u64(target, c->reg_address + 0x18, 1); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("bpid: %d, bp_num %i bp_value 0x%" PRIx64 "", bp->unique_id, + bp_num, c->bp_value); + + return ERROR_OK; +} + +/* TODO: is it MIPS64 or MIPS32 instruction. If MIPS32, can it be shared with + * MIPS32 code? */ +static int mips_mips64_set_sdbbp(struct target *target, struct breakpoint *bp) +{ + uint32_t verify; + int retval; + + retval = target_read_memory(target, + bp->address, bp->length, 1, + bp->orig_instr); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, bp->address, MIPS64_SDBBP); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, bp->address, &verify); + if (retval != ERROR_OK) + return retval; + + if (verify != MIPS64_SDBBP) { + LOG_ERROR("Unable to set 32bit breakpoint at address %16" PRIx64, + bp->address); + retval = ERROR_FAIL; + } + + return retval; +} + +/* TODO do MIPS64 support MIPS16 instructions? Can it be shared with MIPS32 + * code? */ +static int mips_mips16_set_sdbbp(struct target *target, struct breakpoint *bp) +{ + uint32_t isa_req = bp->length & 1; + uint16_t verify; + int retval; + + retval = target_read_memory(target, + bp->address, bp->length, 1, + bp->orig_instr); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u16(target, bp->address, MIPS16_SDBBP(isa_req)); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u16(target, bp->address, &verify); + if (retval != ERROR_OK) + return retval; + + if (verify != MIPS16_SDBBP(isa_req)) { + LOG_ERROR("Unable to set 16bit breakpoint at address %16" PRIx64, + bp->address); + retval = ERROR_FAIL; + } + + return retval; +} + +static int mips_mips64_set_breakpoint(struct target *target, + struct breakpoint *bp) +{ + int retval; + + if (bp->set) { + LOG_WARNING("breakpoint already set"); + return ERROR_OK; + } + + if (bp->type == BKPT_HARD) { + retval = mips_mips64_set_hwbp(target, bp); + } else { + LOG_DEBUG("bpid: %d", bp->unique_id); + + switch (bp->length) { + case MIPS64_SDBBP_SIZE: + retval = mips_mips64_set_sdbbp(target, bp); + break; + case MIPS16_SDBBP_SIZE: + retval = mips_mips16_set_sdbbp(target, bp); + break; + default: + retval = ERROR_FAIL; + } + } + + if (retval != ERROR_OK) { + LOG_ERROR("can't unset breakpoint. Some thing wrong happened"); + return retval; + } + + bp->set = true; + + return ERROR_OK; +} + +static int mips_mips64_enable_breakpoints(struct target *target) +{ + struct breakpoint *bp = target->breakpoints; + int retval = ERROR_OK; + + /* set any pending breakpoints */ + while (bp) { + if (!bp->set) { + retval = mips_mips64_set_breakpoint(target, bp); + if (retval != ERROR_OK) + return retval; + } + bp = bp->next; + } + + return ERROR_OK; +} + +/* TODO: HW data breakpoints are in EJTAG spec. Should we share it for MIPS32? */ +static int mips_mips64_set_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + uint64_t wp_value; + struct mips64_common *mips64 = target->arch_info; + struct mips64_comparator *c, *cl = mips64->data_break_list; + int retval, wp_num = 0; + + /* + * watchpoint enabled, ignore all byte lanes in value register + * and exclude both load and store accesses from watchpoint + * condition evaluation + */ + int enable = EJTAG_DBCn_NOSB | EJTAG_DBCn_NOLB | EJTAG_DBCn_BE + | (0xff << EJTAG_DBCn_BLM_SHIFT); + + if (watchpoint->set) { + LOG_WARNING("watchpoint already set"); + return ERROR_OK; + } + + while (cl[wp_num].used && (wp_num < mips64->num_data_bpoints)) + wp_num++; + + if (wp_num >= mips64->num_data_bpoints) { + LOG_ERROR("ERROR Can not find free comparator"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + if (watchpoint->length != 4) { + LOG_ERROR("Only watchpoints of length 4 are supported"); + return ERROR_TARGET_UNALIGNED_ACCESS; + } + + if (watchpoint->address % 4) { + LOG_ERROR("Watchpoints address should be word aligned"); + return ERROR_TARGET_UNALIGNED_ACCESS; + } + + switch (watchpoint->rw) { + case WPT_READ: + enable &= ~EJTAG_DBCn_NOLB; + break; + case WPT_WRITE: + enable &= ~EJTAG_DBCn_NOSB; + break; + case WPT_ACCESS: + enable &= ~(EJTAG_DBCn_NOLB | EJTAG_DBCn_NOSB); + break; + default: + LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); + } + + c = &cl[wp_num]; + watchpoint->set = wp_num + 1; + c->used = true; + c->bp_value = watchpoint->address; + + wp_value = watchpoint->address; + if (wp_value & 0x80000000) + wp_value |= ULLONG_MAX << 32; + + retval = target_write_u64(target, c->reg_address, wp_value); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u64(target, c->reg_address + 0x08, 0); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u64(target, c->reg_address + 0x10, 0); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u64(target, c->reg_address + 0x18, enable); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u64(target, c->reg_address + 0x20, 0); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("wp_num %i bp_value 0x%" PRIx64 "", wp_num, c->bp_value); + + return ERROR_OK; +} + +static int mips_mips64_enable_watchpoints(struct target *target) +{ + struct watchpoint *watchpoint = target->watchpoints; + int retval; + + /* set any pending watchpoints */ + while (watchpoint) { + if (watchpoint->set == 0) { + retval = mips_mips64_set_watchpoint(target, watchpoint); + if (retval != ERROR_OK) + return retval; + } + watchpoint = watchpoint->next; + } + + return ERROR_OK; +} + +static int mips_mips64_unset_hwbp(struct target *target, struct breakpoint *bp) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips64_comparator *comparator_list = mips64->inst_break_list; + int bp_num; + + bp_num = bp->set - 1; + + if ((bp_num < 0) || (bp_num >= mips64->num_inst_bpoints)) { + LOG_DEBUG("Invalid FP Comparator number in breakpoint (bpid: %d)", + bp->unique_id); + return ERROR_OK; + } + + LOG_DEBUG("bpid: %d - releasing hw: %d", bp->unique_id, bp_num); + comparator_list[bp_num].used = false; + comparator_list[bp_num].bp_value = 0; + + return target_write_u64(target, + comparator_list[bp_num].reg_address + 0x18, 0); +} + +static int mips_mips64_unset_sdbbp(struct target *target, struct breakpoint *bp) +{ + uint8_t buf[MIPS64_SDBBP_SIZE]; + uint32_t instr; + int retval; + + retval = target_read_memory(target, bp->address, MIPS64_SDBBP_SIZE, 1, + &buf[0]); + if (retval != ERROR_OK) + return retval; + + instr = target_buffer_get_u32(target, &buf[0]); + if (instr != MIPS64_SDBBP) + return ERROR_OK; + + return target_write_memory(target, bp->address, MIPS64_SDBBP_SIZE, 1, + bp->orig_instr); +} + +static int mips_mips16_unset_sdbbp(struct target *target, struct breakpoint *bp) +{ + uint8_t buf[MIPS16_SDBBP_SIZE]; + uint16_t instr; + int retval; + + retval = target_read_memory(target, bp->address, MIPS16_SDBBP_SIZE, 1, + &buf[0]); + if (retval != ERROR_OK) + return retval; + + instr = target_buffer_get_u16(target, &buf[0]); + if (instr != MIPS16_SDBBP(bp->length & 1)) + return ERROR_OK; + + return target_write_memory(target, bp->address, MIPS16_SDBBP_SIZE, 1, + bp->orig_instr); +} + +static int mips_mips64_unset_breakpoint(struct target *target, + struct breakpoint *bp) +{ + /* get pointers to arch-specific information */ + int retval; + + if (!bp->set) { + LOG_WARNING("breakpoint not set"); + return ERROR_OK; + } + + if (bp->type == BKPT_HARD) { + retval = mips_mips64_unset_hwbp(target, bp); + } else { + LOG_DEBUG("bpid: %d", bp->unique_id); + + switch (bp->length) { + case MIPS64_SDBBP_SIZE: + retval = mips_mips64_unset_sdbbp(target, bp); + break; + case MIPS16_SDBBP_SIZE: + retval = mips_mips16_unset_sdbbp(target, bp); + break; + default: + retval = ERROR_FAIL; + } + } + if (retval != ERROR_OK) { + LOG_ERROR("can't unset breakpoint. Some thing wrong happened"); + return retval; + } + + bp->set = false; + + return ERROR_OK; +} + +static int mips_mips64_resume(struct target *target, int current, + uint64_t address, int handle_breakpoints, + int debug_execution) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + int retval = ERROR_OK; + uint64_t resume_pc; + struct reg *pc; + + if (mips64->mips64mode32) + address = mips64_extend_sign(address); + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted %d", target->state); + return ERROR_TARGET_NOT_HALTED; + } + + if (!debug_execution) { + target_free_all_working_areas(target); + retval = mips_mips64_enable_breakpoints(target); + if (retval != ERROR_OK) + return retval; + + retval = mips_mips64_enable_watchpoints(target); + if (retval != ERROR_OK) + return retval; + } + + pc = &mips64->core_cache->reg_list[MIPS64_PC]; + /* current = 1: continue on current pc, otherwise continue at <address> */ + if (!current) { + buf_set_u64(pc->value, 0, 64, address); + pc->dirty = 1; + pc->valid = 1; + } + + resume_pc = buf_get_u64(pc->value, 0, 64); + + retval = mips64_restore_context(target); + if (retval != ERROR_OK) + return retval; + + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) { + struct breakpoint *bp; + + /* Single step past breakpoint at current address */ + bp = breakpoint_find(target, (uint64_t) resume_pc); + if (bp) { + LOG_DEBUG("unset breakpoint at 0x%16.16" PRIx64 "", + bp->address); + retval = mips_mips64_unset_breakpoint(target, bp); + if (retval != ERROR_OK) + return retval; + + retval = mips_mips64_single_step_core(target); + if (retval != ERROR_OK) + return retval; + + retval = mips_mips64_set_breakpoint(target, bp); + if (retval != ERROR_OK) + return retval; + } + } + + /* enable interrupts if we are running */ + retval = mips64_enable_interrupts(target, !debug_execution); + if (retval != ERROR_OK) + return retval; + + /* exit debug mode */ + retval = mips64_ejtag_exit_debug(ejtag_info); + if (retval != ERROR_OK) + return retval; + + target->debug_reason = DBG_REASON_NOTHALTED; + + /* registers are now invalid */ + retval = mips64_invalidate_core_regs(target); + if (retval != ERROR_OK) + return retval; + + if (!debug_execution) { + target->state = TARGET_RUNNING; + retval = target_call_event_callbacks(target, + TARGET_EVENT_RESUMED); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("target resumed at 0x%" PRIx64 "", resume_pc); + } else { + target->state = TARGET_DEBUG_RUNNING; + retval = target_call_event_callbacks(target, + TARGET_EVENT_DEBUG_RESUMED); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("target debug resumed at 0x%" PRIx64 "", resume_pc); + } + + return ERROR_OK; +} + +static int mips_mips64_step(struct target *target, int current, + uint64_t address, int handle_breakpoints) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + struct reg *pc = &mips64->core_cache->reg_list[MIPS64_PC]; + struct breakpoint *bp = NULL; + int retval = ERROR_OK; + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (mips64->mips64mode32) + address = mips64_extend_sign(address); + + /* current = 1: continue on current pc, otherwise continue at + * <address> */ + if (!current) { + buf_set_u64(pc->value, 0, 64, address); + pc->dirty = 1; + pc->valid = 1; + } + + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) { + bp = breakpoint_find(target, buf_get_u64(pc->value, 0, 64)); + if (bp) { + retval = mips_mips64_unset_breakpoint(target, bp); + if (retval != ERROR_OK) + return retval; + } + } + + retval = mips64_restore_context(target); + if (retval != ERROR_OK) + return retval; + + /* configure single step mode */ + retval = mips64_ejtag_config_step(ejtag_info, 1); + if (retval != ERROR_OK) + return retval; + + target->debug_reason = DBG_REASON_SINGLESTEP; + + retval = target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + if (retval != ERROR_OK) + return retval; + + /* disable interrupts while stepping */ + retval = mips64_enable_interrupts(target, false); + if (retval != ERROR_OK) + return retval; + + /* exit debug mode */ + retval = mips64_ejtag_exit_debug(ejtag_info); + if (retval != ERROR_OK) + return retval; + + /* registers are now invalid */ + retval = mips64_invalidate_core_regs(target); + if (retval != ERROR_OK) + return retval; + + if (bp) { + retval = mips_mips64_set_breakpoint(target, bp); + if (retval != ERROR_OK) + return retval; + } + + LOG_DEBUG("target stepped "); + + retval = mips_mips64_debug_entry(target); + if (retval != ERROR_OK) + return retval; + + return target_call_event_callbacks(target, TARGET_EVENT_HALTED); +} + +static int mips_mips64_add_breakpoint(struct target *target, + struct breakpoint *bp) +{ + struct mips64_common *mips64 = target->arch_info; + + if (mips64->mips64mode32) + bp->address = mips64_extend_sign(bp->address); + + if (bp->type == BKPT_HARD) { + if (mips64->num_inst_bpoints_avail < 1) { + LOG_INFO("no hardware breakpoint available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + mips64->num_inst_bpoints_avail--; + } + + return mips_mips64_set_breakpoint(target, bp); +} + +static int mips_mips64_remove_breakpoint(struct target *target, + struct breakpoint *bp) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + int retval = ERROR_OK; + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (bp->set) + retval = mips_mips64_unset_breakpoint(target, bp); + + if (bp->type == BKPT_HARD) + mips64->num_inst_bpoints_avail++; + + return retval; +} + +static int mips_mips64_unset_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + struct mips64_comparator *comparator_list = mips64->data_break_list; + + if (!watchpoint->set) { + LOG_WARNING("watchpoint not set"); + return ERROR_OK; + } + + int wp_num = watchpoint->set - 1; + if ((wp_num < 0) || (wp_num >= mips64->num_data_bpoints)) { + LOG_DEBUG("Invalid FP Comparator number in watchpoint"); + return ERROR_OK; + } + comparator_list[wp_num].used = false; + comparator_list[wp_num].bp_value = 0; + target_write_u64(target, comparator_list[wp_num].reg_address + 0x18, 0); + watchpoint->set = 0; + + return ERROR_OK; +} + +static int mips_mips64_add_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + struct mips64_common *mips64 = target->arch_info; + + if (mips64->num_data_bpoints_avail < 1) { + LOG_INFO("no hardware watchpoints available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + mips64->num_data_bpoints_avail--; + + return mips_mips64_set_watchpoint(target, watchpoint); +} + +static int mips_mips64_remove_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + /* get pointers to arch-specific information */ + struct mips64_common *mips64 = target->arch_info; + int retval = ERROR_OK; + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (watchpoint->set) + retval = mips_mips64_unset_watchpoint(target, watchpoint); + + mips64->num_data_bpoints_avail++; + + return retval; +} + +static int mips_mips64_read_memory(struct target *target, uint64_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + int retval; + void *t; + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted %d", target->state); + return ERROR_TARGET_NOT_HALTED; + } + + if (mips64->mips64mode32) + address = mips64_extend_sign(address); + + /* sanitize arguments */ + if (((size != 8) && (size != 4) && (size != 2) && (size != 1)) + || !count || !buffer) + return ERROR_COMMAND_ARGUMENT_INVALID; + + if (((size == 8) && (address & 0x7)) || ((size == 4) && (address & 0x3)) + || ((size == 2) && (address & 0x1))) + return ERROR_TARGET_UNALIGNED_ACCESS; + + if (size > 1) { + t = calloc(count, size); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + } else + t = buffer; + + LOG_DEBUG("address: 0x%16.16" PRIx64 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + address, size, count); + retval = mips64_pracc_read_mem(ejtag_info, address, size, count, + (void *)t); + + if (ERROR_OK != retval) { + LOG_ERROR("mips64_pracc_read_mem filed"); + goto read_done; + } + + switch (size) { + case 8: + target_buffer_set_u64_array(target, buffer, count, t); + break; + case 4: + target_buffer_set_u32_array(target, buffer, count, t); + break; + case 2: + target_buffer_set_u16_array(target, buffer, count, t); + break; + } + +read_done: + if (size > 1) + free(t); + + return retval; +} + +static int mips_mips64_bulk_write_memory(struct target *target, + target_addr_t address, uint32_t count, + const uint8_t *buffer) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + struct working_area *fast_data_area; + int retval; + + LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32 "", + address, count); + + if (address & 0x7) + return ERROR_TARGET_UNALIGNED_ACCESS; + + if (!mips64->fast_data_area) { + /* Get memory for block write handler + * we preserve this area between calls and gain a speed increase + * of about 3kb/sec when writing flash + * this will be released/nulled by the system when the target is resumed or reset */ + retval = target_alloc_working_area(target, + MIPS64_FASTDATA_HANDLER_SIZE, + &mips64->fast_data_area); + if (retval != ERROR_OK) { + LOG_ERROR("No working area available"); + return retval; + } + + /* reset fastadata state so the algo get reloaded */ + ejtag_info->fast_access_save = -1; + } + + fast_data_area = mips64->fast_data_area; + + if (address <= fast_data_area->address + fast_data_area->size && + fast_data_area->address <= address + count) { + LOG_ERROR("fast_data (" TARGET_ADDR_FMT ") is within write area " + "(" TARGET_ADDR_FMT "-" TARGET_ADDR_FMT ").", + fast_data_area->address, address, address + count); + LOG_ERROR("Change work-area-phys or load_image address!"); + return ERROR_FAIL; + } + + /* mips32_pracc_fastdata_xfer requires uint32_t in host endianness, */ + /* but byte array represents target endianness */ + uint64_t *t; + + t = calloc(count, sizeof(uint64_t)); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + target_buffer_get_u64_array(target, buffer, count, t); + + retval = mips64_pracc_fastdata_xfer(ejtag_info, mips64->fast_data_area, + true, address, count, t); + + if (retval != ERROR_OK) + LOG_ERROR("Fastdata access Failed"); + + free(t); + + return retval; +} + +static int mips_mips64_write_memory(struct target *target, uint64_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + struct mips64_common *mips64 = target->arch_info; + struct mips_ejtag *ejtag_info = &mips64->ejtag_info; + int retval; + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (mips64->mips64mode32) + address = mips64_extend_sign(address); + + /* sanitize arguments */ + if (((size != 8) && (size != 4) && (size != 2) && (size != 1)) + || !count || !buffer) + return ERROR_COMMAND_ARGUMENT_INVALID; + + if (((size == 8) && (address & 0x7)) || ((size == 4) && (address & 0x3)) + || ((size == 2) && (address & 0x1))) + return ERROR_TARGET_UNALIGNED_ACCESS; + + + + if (size == 8 && count > 8) { + retval = mips_mips64_bulk_write_memory(target, address, count, + buffer); + if (retval == ERROR_OK) + return ERROR_OK; + + LOG_WARNING("Falling back to non-bulk write"); + } + + void *t = NULL; + if (size > 1) { + t = calloc(count, size); + if (!t) { + LOG_ERROR("unable to allocate t for write buffer"); + return ERROR_FAIL; + } + + switch (size) { + case 8: + target_buffer_get_u64_array(target, buffer, count, + (uint64_t *)t); + break; + case 4: + target_buffer_get_u32_array(target, buffer, count, + (uint32_t *)t); + break; + case 2: + target_buffer_get_u16_array(target, buffer, count, + (uint16_t *)t); + break; + } + buffer = t; + } + + LOG_DEBUG("address: 0x%16.16" PRIx64 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + address, size, count); + + retval = mips64_pracc_write_mem(ejtag_info, address, size, count, + (void *)buffer); + free(t); + + return retval; +} + +static int mips_mips64_init_target(struct command_context *cmd_ctx, + struct target *target) +{ + return mips64_build_reg_cache(target); +} + +static int mips_mips64_target_create(struct target *target, Jim_Interp *interp) +{ + struct mips_mips64_common *mips_mips64; + struct mips64_common *mips64; + + mips_mips64 = calloc(1, sizeof(*mips_mips64)); + if (!mips_mips64) { + LOG_ERROR("unable to allocate mips_mips64"); + return ERROR_FAIL; + } + + mips_mips64->common_magic = MIPS64_COMMON_MAGIC; + + mips64 = &mips_mips64->mips64_common; + mips64->arch_info = mips_mips64; + target->arch_info = mips64; + + return mips64_init_arch_info(target, mips64, target->tap); +} + +static int mips_mips64_examine(struct target *target) +{ + int retval; + struct mips64_common *mips64 = target->arch_info; + + retval = mips_ejtag_init(&mips64->ejtag_info); + if (retval != ERROR_OK) + return retval; + + return mips64_examine(target); +} + +static int mips_mips64_checksum_memory(struct target *target, uint64_t address, + uint32_t size, uint32_t *checksum) +{ + return ERROR_FAIL; /* use bulk read method */ +} + +COMMAND_HANDLER(handle_mips64mode32) +{ + struct target *target = get_current_target(CMD_CTX); + struct mips64_common *mips64 = target->arch_info; + + if (CMD_ARGC > 0) + COMMAND_PARSE_BOOL(CMD_ARGV[0], mips64->mips64mode32, "on", "off"); + + if (mips64->mips64mode32) + command_print(CMD, "enabled"); + else + command_print(CMD, "disabled"); + + return ERROR_OK; +} + + +static const struct command_registration mips64_commands_handlers[] = { + { + .name = "mips64mode32", + .mode = COMMAND_EXEC, + .help = "Enable/disable 32 bit mode", + .usage = "[1|0]", + .handler = handle_mips64mode32 + }, + COMMAND_REGISTRATION_DONE +}; + +struct target_type mips_mips64_target = { + .name = "mips_mips64", + + .poll = mips_mips64_poll, + .arch_state = mips64_arch_state, + + .target_request_data = NULL, + + .halt = mips_mips64_halt, + .resume = mips_mips64_resume, + .step = mips_mips64_step, + + .assert_reset = mips_mips64_assert_reset, + .deassert_reset = mips_mips64_deassert_reset, + .soft_reset_halt = mips_mips64_soft_reset_halt, + + .get_gdb_reg_list = mips64_get_gdb_reg_list, + + .read_memory = mips_mips64_read_memory, + .write_memory = mips_mips64_write_memory, + .checksum_memory = mips_mips64_checksum_memory, + .blank_check_memory = NULL, + + .run_algorithm = mips64_run_algorithm, + + .add_breakpoint = mips_mips64_add_breakpoint, + .remove_breakpoint = mips_mips64_remove_breakpoint, + .add_watchpoint = mips_mips64_add_watchpoint, + .remove_watchpoint = mips_mips64_remove_watchpoint, + + .target_create = mips_mips64_target_create, + .init_target = mips_mips64_init_target, + .examine = mips_mips64_examine, + + .commands = mips64_commands_handlers, +}; diff --git a/src/target/mips_mips64.h b/src/target/mips_mips64.h new file mode 100644 index 0000000..69fb2a6 --- /dev/null +++ b/src/target/mips_mips64.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * MIPS64 generic target support * + * + * Copyright (C) 2014 by Andrey Sidorov <anysidorov@gmail.com> + * Copyright (C) 2014 by Aleksey Kuleshov <rndfax@yandex.ru> + * Copyright (C) 2014-2019 by Peter Mamonov <pmamonov@gmail.com> + * + * Based on the work of: + * Copyright (C) 2008 by Spencer Oliver + * Copyright (C) 2008 by David T.L. Wong + */ + +#ifndef OPENOCD_TARGET_MIPS_MIPS64_H +#define OPENOCD_TARGET_MIPS_MIPS64_H + +#include "helper/types.h" + +struct mips_mips64_common { + int common_magic; + struct mips64_common mips64_common; +}; + +#endif /* OPENOCD_TARGET_MIPS_MIPS64_H */ diff --git a/src/target/nds32.c b/src/target/nds32.c index 4115ea4..f40ce53 100644 --- a/src/target/nds32.c +++ b/src/target/nds32.c @@ -2361,7 +2361,7 @@ int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fil fileio_info->param_4 = reg_r2; target->type->read_buffer(target, reg_r0, 256, filename); - fileio_info->param_2 = strlen((char *)filename) + 1; + fileio_info->param_2 = strlen((char *)filename); } break; case NDS32_SYSCALL_CLOSE: @@ -2399,7 +2399,7 @@ int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fil /* reserve fileio_info->param_2 for length of path */ target->type->read_buffer(target, reg_r0, 256, filename); - fileio_info->param_2 = strlen((char *)filename) + 1; + fileio_info->param_2 = strlen((char *)filename); } break; case NDS32_SYSCALL_RENAME: @@ -2413,10 +2413,10 @@ int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fil /* reserve fileio_info->param_4 for length of new path */ target->type->read_buffer(target, reg_r0, 256, filename); - fileio_info->param_2 = strlen((char *)filename) + 1; + fileio_info->param_2 = strlen((char *)filename); target->type->read_buffer(target, reg_r1, 256, filename); - fileio_info->param_4 = strlen((char *)filename) + 1; + fileio_info->param_4 = strlen((char *)filename); } break; case NDS32_SYSCALL_FSTAT: @@ -2458,7 +2458,7 @@ int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fil /* reserve fileio_info->param_2 for length of old path */ target->type->read_buffer(target, reg_r0, 256, command); - fileio_info->param_2 = strlen((char *)command) + 1; + fileio_info->param_2 = strlen((char *)command); } break; case NDS32_SYSCALL_ERRNO: diff --git a/src/target/nds32.h b/src/target/nds32.h index 141dbf4..3670fd2 100644 --- a/src/target/nds32.h +++ b/src/target/nds32.h @@ -82,7 +82,7 @@ enum nds32_syscall_id { NDS32_SYSCALL_ERRNO = 6001, }; -#define NDS32_COMMON_MAGIC (int)0xADE5ADE5 +#define NDS32_COMMON_MAGIC 0xADE5ADE5U struct nds32_edm { @@ -235,7 +235,7 @@ struct nds32_misc_config { * Represents a generic Andes core. */ struct nds32 { - int common_magic; + uint32_t common_magic; struct reg_cache *core_cache; /** Handle for the debug module. */ diff --git a/src/target/nds32_cmd.c b/src/target/nds32_cmd.c index 1accf6f..d7d040e 100644 --- a/src/target/nds32_cmd.c +++ b/src/target/nds32_cmd.c @@ -1007,7 +1007,7 @@ static const struct command_registration nds32_exec_command_handlers[] = { .handler = handle_nds32_global_stop_command, .mode = COMMAND_ANY, .usage = "['on'|'off']", - .help = "turn on/off global stop. After turning on, every load/store" \ + .help = "turn on/off global stop. After turning on, every load/store " "instructions will be stopped to check memory access.", }, { @@ -1015,7 +1015,7 @@ static const struct command_registration nds32_exec_command_handlers[] = { .handler = handle_nds32_soft_reset_halt_command, .mode = COMMAND_ANY, .usage = "['on'|'off']", - .help = "as issuing rest-halt, to use soft-reset-halt or not." \ + .help = "as issuing rest-halt, to use soft-reset-halt or not." "the feature is for backward-compatible.", }, { @@ -1123,4 +1123,3 @@ const struct command_registration nds32_command_handlers[] = { }, COMMAND_REGISTRATION_DONE }; - diff --git a/src/target/nds32_disassembler.c b/src/target/nds32_disassembler.c index f27aba2..0cfd197 100644 --- a/src/target/nds32_disassembler.c +++ b/src/target/nds32_disassembler.c @@ -493,7 +493,7 @@ static int nds32_parse_mem(struct nds32 *nds32, uint32_t opcode, uint32_t addres switch (sub_opcode & 0x7) { case 0: /* LB */ nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), \ + &(instruction->info.ra), &(instruction->info.rb), &(instruction->info.imm)); instruction->type = NDS32_INSN_LOAD_STORE; nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra); diff --git a/src/target/openrisc/or1k.c b/src/target/openrisc/or1k.c index 1e5db8c..44825d0 100644 --- a/src/target/openrisc/or1k.c +++ b/src/target/openrisc/or1k.c @@ -1207,8 +1207,8 @@ int or1k_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *file } static int or1k_checksum_memory(struct target *target, target_addr_t address, - uint32_t count, uint32_t *checksum) { - + uint32_t count, uint32_t *checksum) +{ return ERROR_FAIL; } diff --git a/src/target/openrisc/or1k_tap_vjtag.c b/src/target/openrisc/or1k_tap_vjtag.c index 607451a..db10f10 100644 --- a/src/target/openrisc/or1k_tap_vjtag.c +++ b/src/target/openrisc/or1k_tap_vjtag.c @@ -149,7 +149,7 @@ static int or1k_tap_vjtag_init(struct or1k_jtag *jtag_info) * into the USER1 DR is sufficient to cover the most conservative case for m and n. */ - uint8_t t[4]; + uint8_t t[4] = { 0 }; struct scan_field field; struct jtag_tap *tap = jtag_info->tap; diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index ff67d30..f1b3c66 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -279,7 +279,7 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) { struct scan_field field; uint8_t in_value[4]; - uint8_t out_value[4]; + uint8_t out_value[4] = { 0 }; buf_set_u32(out_value, 0, 32, out); @@ -421,7 +421,7 @@ static dbus_status_t dbus_scan(struct target *target, uint16_t *address_in, { riscv011_info_t *info = get_info(target); uint8_t in[8] = {0}; - uint8_t out[8]; + uint8_t out[8] = {0}; struct scan_field field = { .num_bits = info->addrbits + DBUS_OP_SIZE + DBUS_DATA_SIZE, .out_value = out, diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 9522e5e..2ea8fdf 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -69,7 +69,7 @@ static int write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); static int riscv013_test_sba_config_reg(struct target *target, target_addr_t legal_address, uint32_t num_words, target_addr_t illegal_address, bool run_sbbusyerror_test); -void write_memory_sba_simple(struct target *target, target_addr_t addr, uint32_t* write_data, +void write_memory_sba_simple(struct target *target, target_addr_t addr, uint32_t *write_data, uint32_t write_size, uint32_t sbcs); void read_memory_sba_simple(struct target *target, target_addr_t addr, uint32_t *rd_buf, uint32_t read_size, uint32_t sbcs); @@ -425,7 +425,7 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) { struct scan_field field; uint8_t in_value[4]; - uint8_t out_value[4]; + uint8_t out_value[4] = { 0 }; if (bscan_tunnel_ir_width != 0) return dtmcontrol_scan_via_bscan(target, out); @@ -495,6 +495,7 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, } memset(in, 0, num_bytes); + memset(out, 0, num_bytes); assert(info->abits != 0); @@ -724,10 +725,8 @@ uint32_t abstract_register_size(unsigned width) return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 2); case 64: return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 3); - break; case 128: return set_field(0, AC_ACCESS_REGISTER_AARSIZE, 4); - break; default: LOG_ERROR("Unsupported register width: %d", width); return 0; @@ -2351,11 +2350,9 @@ static target_addr_t sb_read_address(struct target *target) target_addr_t address = 0; uint32_t v; if (sbasize > 32) { -#if BUILD_TARGET64 dmi_read(target, &v, DMI_SBADDRESS1); address |= v; address <<= 32; -#endif } dmi_read(target, &v, DMI_SBADDRESS0); address |= v; @@ -2372,11 +2369,7 @@ static int sb_write_address(struct target *target, target_addr_t address) if (sbasize > 64) dmi_write(target, DMI_SBADDRESS2, 0); if (sbasize > 32) -#if BUILD_TARGET64 dmi_write(target, DMI_SBADDRESS1, address >> 32); -#else - dmi_write(target, DMI_SBADDRESS1, 0); -#endif return dmi_write(target, DMI_SBADDRESS0, address); } @@ -4684,13 +4677,13 @@ int riscv013_test_compliance(struct target *target) But at any rate, this is not legal and should cause an error. */ COMPLIANCE_WRITE(target, DMI_COMMAND, 0xAAAAAAAA); COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTCS); - COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, \ + COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, "Illegal COMMAND should result in UNSUPPORTED"); COMPLIANCE_WRITE(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); COMPLIANCE_WRITE(target, DMI_COMMAND, 0x55555555); COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTCS); - COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, \ + COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, "Illegal COMMAND should result in UNSUPPORTED"); COMPLIANCE_WRITE(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 415ba9a..6640c2d 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -417,7 +417,7 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) { struct scan_field field; uint8_t in_value[4]; - uint8_t out_value[4]; + uint8_t out_value[4] = { 0 }; if (bscan_tunnel_ir_width != 0) return dtmcontrol_scan_via_bscan(target, out); @@ -761,7 +761,7 @@ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) return ERROR_FAIL; } - uint8_t buff[4]; + uint8_t buff[4] = { 0 }; buf_set_u32(buff, 0, breakpoint->length * CHAR_BIT, breakpoint->length == 4 ? ebreak() : ebreak_c()); int const retval = target_write_memory(target, breakpoint->address, 2, breakpoint->length / 2, buff); @@ -995,12 +995,9 @@ static int oldriscv_step(struct target *target, int current, uint32_t address, return tt->step(target, current, address, handle_breakpoints); } -static int old_or_new_riscv_step( - struct target *target, - int current, - target_addr_t address, - int handle_breakpoints -){ +static int old_or_new_riscv_step(struct target *target, int current, + target_addr_t address, int handle_breakpoints) +{ RISCV_INFO(r); LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); if (r->is_halted == NULL) @@ -1795,7 +1792,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, /* Disable Interrupts before attempting to run the algorithm. */ uint64_t current_mstatus; - uint8_t mstatus_bytes[8]; + uint8_t mstatus_bytes[8] = { 0 }; LOG_DEBUG("Disabling Interrupts"); struct reg *reg_mstatus = register_get_by_name(target->reg_cache, @@ -1872,7 +1869,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, reg_mstatus->type->set(reg_mstatus, mstatus_bytes); /* Restore registers */ - uint8_t buf[8]; + uint8_t buf[8] = { 0 }; buf_set_u64(buf, 0, info->xlen[0], saved_pc); if (reg_pc->type->set(reg_pc, buf) != ERROR_OK) return ERROR_FAIL; @@ -2196,12 +2193,9 @@ int riscv_openocd_poll(struct target *target) return ERROR_OK; } -int riscv_openocd_step( - struct target *target, - int current, - target_addr_t address, - int handle_breakpoints -) { +int riscv_openocd_step(struct target *target, int current, + target_addr_t address, int handle_breakpoints) +{ LOG_DEBUG("stepping rtos hart"); if (!current) @@ -2751,13 +2745,13 @@ static const struct command_registration riscv_exec_command_handlers[] = { .name = "test_sba_config_reg", .handler = riscv_test_sba_config_reg, .mode = COMMAND_ANY, - .usage = "riscv test_sba_config_reg legal_address num_words" + .usage = "riscv test_sba_config_reg legal_address num_words " "illegal_address run_sbbusyerror_test[on/off]", - .help = "Perform a series of tests on the SBCS register." - "Inputs are a legal, 128-byte aligned address and a number of words to" - "read/write starting at that address (i.e., address range [legal address," - "legal_address+word_size*num_words) must be legally readable/writable)" - ", an illegal, 128-byte aligned address for error flag/handling cases," + .help = "Perform a series of tests on the SBCS register. " + "Inputs are a legal, 128-byte aligned address and a number of words to " + "read/write starting at that address (i.e., address range [legal address, " + "legal_address+word_size*num_words) must be legally readable/writable), " + "an illegal, 128-byte aligned address for error flag/handling cases, " "and whether sbbusyerror test should be run." }, { @@ -2832,11 +2826,6 @@ static const struct command_registration riscv_exec_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -extern __COMMAND_HANDLER(handle_common_semihosting_command); -extern __COMMAND_HANDLER(handle_common_semihosting_fileio_command); -extern __COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command); -extern __COMMAND_HANDLER(handle_common_semihosting_cmdline); - /* * To be noted that RISC-V targets use the same semihosting commands as * ARM targets. @@ -2850,37 +2839,7 @@ extern __COMMAND_HANDLER(handle_common_semihosting_cmdline); * protocol, then a command like `riscv semihosting enable` will make * sense, but for now all semihosting commands are prefixed with `arm`. */ -static const struct command_registration arm_exec_command_handlers[] = { - { - .name = "semihosting", - .handler = handle_common_semihosting_command, - .mode = COMMAND_EXEC, - .usage = "['enable'|'disable']", - .help = "activate support for semihosting operations", - }, - { - .name = "semihosting_cmdline", - .handler = handle_common_semihosting_cmdline, - .mode = COMMAND_EXEC, - .usage = "arguments", - .help = "command line arguments to be passed to program", - }, - { - .name = "semihosting_fileio", - .handler = handle_common_semihosting_fileio_command, - .mode = COMMAND_EXEC, - .usage = "['enable'|'disable']", - .help = "activate support for semihosting fileio operations", - }, - { - .name = "semihosting_resexit", - .handler = handle_common_semihosting_resumable_exit_command, - .mode = COMMAND_EXEC, - .usage = "['enable'|'disable']", - .help = "activate support for semihosting resumable exit", - }, - COMMAND_REGISTRATION_DONE -}; +extern const struct command_registration semihosting_common_handlers[]; const struct command_registration riscv_command_handlers[] = { { @@ -2895,7 +2854,7 @@ const struct command_registration riscv_command_handlers[] = { .mode = COMMAND_ANY, .help = "ARM Command Group", .usage = "", - .chain = arm_exec_command_handlers + .chain = semihosting_common_handlers }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index ce6a791..a02f2df 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -944,6 +944,8 @@ int semihosting_common(struct target *target) uint8_t *fn1 = malloc(len1+1); uint8_t *fn2 = malloc(len2+1); if (!fn1 || !fn2) { + free(fn1); + free(fn2); semihosting->result = -1; semihosting->sys_errno = ENOMEM; } else { @@ -1459,7 +1461,7 @@ static void semihosting_set_field(struct target *target, uint64_t value, /* ------------------------------------------------------------------------- * Common semihosting commands handlers. */ -__COMMAND_HANDLER(handle_common_semihosting_command) +static __COMMAND_HANDLER(handle_common_semihosting_command) { struct target *target = get_current_target(CMD_CTX); @@ -1500,8 +1502,7 @@ __COMMAND_HANDLER(handle_common_semihosting_command) return ERROR_OK; } - -__COMMAND_HANDLER(handle_common_semihosting_fileio_command) +static __COMMAND_HANDLER(handle_common_semihosting_fileio_command) { struct target *target = get_current_target(CMD_CTX); @@ -1531,7 +1532,7 @@ __COMMAND_HANDLER(handle_common_semihosting_fileio_command) return ERROR_OK; } -__COMMAND_HANDLER(handle_common_semihosting_cmdline) +static __COMMAND_HANDLER(handle_common_semihosting_cmdline) { struct target *target = get_current_target(CMD_CTX); unsigned int i; @@ -1564,7 +1565,7 @@ __COMMAND_HANDLER(handle_common_semihosting_cmdline) return ERROR_OK; } -__COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command) +static __COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command) { struct target *target = get_current_target(CMD_CTX); @@ -1593,3 +1594,35 @@ __COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command) return ERROR_OK; } + +const struct command_registration semihosting_common_handlers[] = { + { + "semihosting", + .handler = handle_common_semihosting_command, + .mode = COMMAND_EXEC, + .usage = "['enable'|'disable']", + .help = "activate support for semihosting operations", + }, + { + "semihosting_cmdline", + .handler = handle_common_semihosting_cmdline, + .mode = COMMAND_EXEC, + .usage = "arguments", + .help = "command line arguments to be passed to program", + }, + { + "semihosting_fileio", + .handler = handle_common_semihosting_fileio_command, + .mode = COMMAND_EXEC, + .usage = "['enable'|'disable']", + .help = "activate support for semihosting fileio operations", + }, + { + "semihosting_resexit", + .handler = handle_common_semihosting_resumable_exit_command, + .mode = COMMAND_EXEC, + .usage = "['enable'|'disable']", + .help = "activate support for semihosting resumable exit", + }, + COMMAND_REGISTRATION_DONE +}; diff --git a/src/target/startup.tcl b/src/target/startup.tcl index 4d4426f..976cd2a 100644 --- a/src/target/startup.tcl +++ b/src/target/startup.tcl @@ -66,7 +66,9 @@ proc ocd_process_reset_inner { MODE } { if {![using_jtag] || [jtag tapisenabled [$t cget -chain-position]]} { $t invoke-event examine-start set err [catch "$t arp_examine allow-defer"] - if { $err == 0 } { + if { $err } { + $t invoke-event examine-fail + } else { $t invoke-event examine-end } } @@ -221,9 +223,3 @@ proc cortex_a8 args { echo "DEPRECATED! use 'cortex_a' not 'cortex_a8'" eval cortex_a $args } - -# deprecated ftdi cmds -proc ftdi_location args { - echo "DEPRECATED! use 'adapter usb location' not 'ftdi_location'" - eval adapter usb location $args -} diff --git a/src/target/stm8.c b/src/target/stm8.c index fcfc170..ce8cfaa 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -1,20 +1,20 @@ /* - OpenOCD STM8 target driver - Copyright (C) 2017 Ake Rehnman - ake.rehnman(at)gmail.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 3 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/>. +* OpenOCD STM8 target driver +* Copyright (C) 2017 Ake Rehnman +* ake.rehnman(at)gmail.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 @@ -25,10 +25,9 @@ #include "target.h" #include "target_type.h" #include "hello.h" +#include "jtag/interface.h" #include "jtag/jtag.h" -#include "jtag/hla/hla_transport.h" -#include "jtag/hla/hla_interface.h" -#include "jtag/hla/hla_layout.h" +#include "jtag/swim.h" #include "register.h" #include "breakpoints.h" #include "algorithm.h" @@ -46,6 +45,8 @@ static int stm8_set_breakpoint(struct target *target, static void stm8_enable_watchpoints(struct target *target); static int stm8_unset_watchpoint(struct target *target, struct watchpoint *watchpoint); +static int (*adapter_speed)(int speed); +extern struct adapter_driver *adapter_driver; static const struct { unsigned id; @@ -179,68 +180,31 @@ struct stm8_comparator { enum hw_break_type type; }; -static inline struct hl_interface_s *target_to_adapter(struct target *target) -{ - return target->tap->priv; -} - static int stm8_adapter_read_memory(struct target *target, uint32_t addr, int size, int count, void *buf) { - int ret; - struct hl_interface_s *adapter = target_to_adapter(target); - - ret = adapter->layout->api->read_mem(adapter->handle, - addr, size, count, buf); - if (ret != ERROR_OK) - return ret; - return ERROR_OK; + return swim_read_mem(addr, size, count, buf); } static int stm8_adapter_write_memory(struct target *target, uint32_t addr, int size, int count, const void *buf) { - int ret; - struct hl_interface_s *adapter = target_to_adapter(target); - - ret = adapter->layout->api->write_mem(adapter->handle, - addr, size, count, buf); - if (ret != ERROR_OK) - return ret; - return ERROR_OK; + return swim_write_mem(addr, size, count, buf); } static int stm8_write_u8(struct target *target, uint32_t addr, uint8_t val) { - int ret; uint8_t buf[1]; - struct hl_interface_s *adapter = target_to_adapter(target); buf[0] = val; - ret = adapter->layout->api->write_mem(adapter->handle, addr, 1, 1, buf); - if (ret != ERROR_OK) - return ret; - return ERROR_OK; + return swim_write_mem(addr, 1, 1, buf); } static int stm8_read_u8(struct target *target, uint32_t addr, uint8_t *val) { - int ret; - struct hl_interface_s *adapter = target_to_adapter(target); - - ret = adapter->layout->api->read_mem(adapter->handle, addr, 1, 1, val); - if (ret != ERROR_OK) - return ret; - return ERROR_OK; -} - -static int stm8_set_speed(struct target *target, int speed) -{ - struct hl_interface_s *adapter = target_to_adapter(target); - adapter->layout->api->speed(adapter->handle, speed, 0); - return ERROR_OK; + return swim_read_mem(addr, 1, 1, val); } /* @@ -355,7 +319,7 @@ static int stm8_set_hwbreak(struct target *target, if ((comparator_list[0].type != HWBRK_EXEC) && (comparator_list[1].type != HWBRK_EXEC)) { - if ((comparator_list[0].type != comparator_list[1].type)) { + if (comparator_list[0].type != comparator_list[1].type) { LOG_ERROR("data hw breakpoints must be of same type"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -835,8 +799,35 @@ static int stm8_read_memory(struct target *target, target_addr_t address, return retval; } +static int stm8_speed(int speed) +{ + int retval; + uint8_t csr; + + LOG_DEBUG("stm8_speed: %d", speed); + + csr = SAFE_MASK | SWIM_DM; + if (speed >= SWIM_FREQ_HIGH) + csr |= HS; + + LOG_DEBUG("writing B0 to SWIM_CSR (SAFE_MASK + SWIM_DM + HS:%d)", csr & HS ? 1 : 0); + retval = stm8_write_u8(NULL, SWIM_CSR, csr); + if (retval != ERROR_OK) + return retval; + return adapter_speed(speed); +} + static int stm8_init(struct command_context *cmd_ctx, struct target *target) { + /* + * FIXME: this is a temporarily hack that needs better implementation. + * Being the only overwrite of adapter_driver, it prevents declaring const + * the struct adapter_driver. + * intercept adapter_driver->speed() calls + */ + adapter_speed = adapter_driver->speed; + adapter_driver->speed = stm8_speed; + stm8_build_reg_cache(target); return ERROR_OK; @@ -923,16 +914,13 @@ static int stm8_halt(struct target *target) static int stm8_reset_assert(struct target *target) { int res = ERROR_OK; - struct hl_interface_s *adapter = target_to_adapter(target); struct stm8_common *stm8 = target_to_stm8(target); bool use_srst_fallback = true; enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_HAS_SRST) { - jtag_add_reset(0, 1); - res = adapter->layout->api->assert_srst(adapter->handle, 0); - + res = adapter_assert_reset(); if (res == ERROR_OK) /* hardware srst supported */ use_srst_fallback = false; @@ -943,7 +931,7 @@ static int stm8_reset_assert(struct target *target) if (use_srst_fallback) { LOG_DEBUG("Hardware srst not supported, falling back to swim reset"); - res = adapter->layout->api->reset(adapter->handle); + res = swim_system_reset(); if (res != ERROR_OK) return res; } @@ -966,21 +954,14 @@ static int stm8_reset_assert(struct target *target) static int stm8_reset_deassert(struct target *target) { int res; - struct hl_interface_s *adapter = target_to_adapter(target); - enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_HAS_SRST) { - res = adapter->layout->api->assert_srst(adapter->handle, 1); + res = adapter_deassert_reset(); if ((res != ERROR_OK) && (res != ERROR_COMMAND_NOTFOUND)) return res; } - /* virtual deassert reset, we need it for the internal - * jtag state machine - */ - jtag_add_reset(0, 0); - /* The cpu should now be stalled. If halt was requested let poll detect the stall */ if (target->reset_halt) @@ -1704,34 +1685,26 @@ static int stm8_examine(struct target *target) uint8_t csr1, csr2; /* get pointers to arch-specific information */ struct stm8_common *stm8 = target_to_stm8(target); - struct hl_interface_s *adapter = target_to_adapter(target); + enum reset_types jtag_reset_config = jtag_get_reset_config(); if (!target_was_examined(target)) { if (!stm8->swim_configured) { - /* set SWIM_CSR = 0xa0 (enable mem access & mask reset) */ - LOG_DEBUG("writing A0 to SWIM_CSR (SAFE_MASK + SWIM_DM)"); - retval = stm8_write_u8(target, SWIM_CSR, SAFE_MASK + SWIM_DM); - if (retval != ERROR_OK) - return retval; - /* set high speed */ - LOG_DEBUG("writing B0 to SWIM_CSR (SAFE_MASK + SWIM_DM + HS)"); - retval = stm8_write_u8(target, SWIM_CSR, SAFE_MASK + SWIM_DM + HS); - if (retval != ERROR_OK) - return retval; - retval = stm8_set_speed(target, 1); - if (retval == ERROR_OK) - stm8->swim_configured = true; + stm8->swim_configured = true; /* Now is the time to deassert reset if connect_under_reset. Releasing reset line will cause the option bytes to load. The core will still be stalled. */ - if (adapter->param.connect_under_reset) - stm8_reset_deassert(target); + if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { + if (jtag_reset_config & RESET_SRST_NO_GATING) + stm8_reset_deassert(target); + else + LOG_WARNING("\'srst_nogate\' reset_config option is required"); + } } else { LOG_INFO("trying to reconnect"); - retval = adapter->layout->api->state(adapter->handle); + retval = swim_reconnect(); if (retval != ERROR_OK) { LOG_ERROR("reconnect failed"); return ERROR_FAIL; diff --git a/src/target/stm8.h b/src/target/stm8.h index 39fac3e..da7f1f1 100644 --- a/src/target/stm8.h +++ b/src/target/stm8.h @@ -1,20 +1,20 @@ /* - OpenOCD STM8 target driver - Copyright (C) 2017 Ake Rehnman - ake.rehnman(at)gmail.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 3 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/>. +* OpenOCD STM8 target driver +* Copyright (C) 2017 Ake Rehnman +* ake.rehnman(at)gmail.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_TARGET_STM8_H diff --git a/src/target/target.c b/src/target/target.c index 5ac66c4..bccafbf 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -94,6 +94,7 @@ extern struct target_type cortexr4_target; extern struct target_type arm11_target; extern struct target_type ls1_sap_target; extern struct target_type mips_m4k_target; +extern struct target_type mips_mips64_target; extern struct target_type avr_target; extern struct target_type dsp563xx_target; extern struct target_type dsp5680xx_target; @@ -110,6 +111,7 @@ extern struct target_type stm8_target; extern struct target_type riscv_target; extern struct target_type mem_ap_target; extern struct target_type esirisc_target; +extern struct target_type arcv2_target; static struct target_type *target_types[] = { &arm7tdmi_target, @@ -145,9 +147,9 @@ static struct target_type *target_types[] = { &riscv_target, &mem_ap_target, &esirisc_target, -#if BUILD_TARGET64 + &arcv2_target, &aarch64_target, -#endif + &mips_mips64_target, NULL, }; @@ -201,6 +203,8 @@ static const Jim_Nvp nvp_target_event[] = { { .value = TARGET_EVENT_RESUMED, .name = "resumed" }, { .value = TARGET_EVENT_RESUME_START, .name = "resume-start" }, { .value = TARGET_EVENT_RESUME_END, .name = "resume-end" }, + { .value = TARGET_EVENT_STEP_START, .name = "step-start" }, + { .value = TARGET_EVENT_STEP_END, .name = "step-end" }, { .name = "gdb-start", .value = TARGET_EVENT_GDB_START }, { .name = "gdb-end", .value = TARGET_EVENT_GDB_END }, @@ -215,6 +219,7 @@ static const Jim_Nvp nvp_target_event[] = { { .value = TARGET_EVENT_RESET_END, .name = "reset-end" }, { .value = TARGET_EVENT_EXAMINE_START, .name = "examine-start" }, + { .value = TARGET_EVENT_EXAMINE_FAIL, .name = "examine-fail" }, { .value = TARGET_EVENT_EXAMINE_END, .name = "examine-end" }, { .value = TARGET_EVENT_DEBUG_HALTED, .name = "debug-halted" }, @@ -704,13 +709,17 @@ static int default_check_reset(struct target *target) return ERROR_OK; } +/* Equvivalent Tcl code arp_examine_one is in src/target/startup.tcl + * Keep in sync */ int target_examine_one(struct target *target) { target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START); int retval = target->type->examine(target); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_FAIL); return retval; + } target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END); @@ -1247,7 +1256,17 @@ bool target_supports_gdb_connection(struct target *target) int target_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { - return target->type->step(target, current, address, handle_breakpoints); + int retval; + + target_call_event_callbacks(target, TARGET_EVENT_STEP_START); + + retval = target->type->step(target, current, address, handle_breakpoints); + if (retval != ERROR_OK) + return retval; + + target_call_event_callbacks(target, TARGET_EVENT_STEP_END); + + return retval; } int target_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) @@ -1687,7 +1706,7 @@ static int target_call_timer_callbacks_check_time(int checktime) * next item; initially, that's a standalone "root of the * list" variable. */ struct target_timer_callback **callback = &target_timer_callbacks; - while (*callback) { + while (callback && *callback) { if ((*callback)->removed) { struct target_timer_callback *p = *callback; *callback = (*callback)->next; @@ -2047,6 +2066,8 @@ static void target_destroy(struct target *target) target->smp = 0; } + rtos_destroy(target); + free(target->gdb_port_override); free(target->type); free(target->trace_info); @@ -2290,7 +2311,7 @@ static int target_read_buffer_default(struct target *target, target_addr_t addre return ERROR_OK; } -int target_checksum_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t* crc) +int target_checksum_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t *crc) { uint8_t *buffer; int retval; @@ -3158,7 +3179,7 @@ COMMAND_HANDLER(handle_step_command) struct target *target = get_current_target(CMD_CTX); - return target->type->step(target, current_pc, addr, 1); + return target_step(target, current_pc, addr, 1); } void target_handle_md_output(struct command_invocation *cmd, @@ -3360,8 +3381,8 @@ COMMAND_HANDLER(handle_mw_command) target_addr_t address; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); - target_addr_t value; - COMMAND_PARSE_ADDRESS(CMD_ARGV[1], value); + uint64_t value; + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], value); unsigned count = 1; if (CMD_ARGC == 3) @@ -3660,14 +3681,7 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver data = malloc(buf_cnt); - /* Can we use 32bit word accesses? */ - int size = 1; - int count = buf_cnt; - if ((count % 4) == 0) { - size *= 4; - count /= 4; - } - retval = target_read_memory(target, image.sections[i].base_address, size, count, data); + retval = target_read_buffer(target, image.sections[i].base_address, buf_cnt, data); if (retval == ERROR_OK) { uint32_t t; for (t = 0; t < buf_cnt; t++) { @@ -3849,11 +3863,16 @@ COMMAND_HANDLER(handle_rbp_command) if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - target_addr_t addr; - COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); - struct target *target = get_current_target(CMD_CTX); - breakpoint_remove(target, addr); + + if (!strcmp(CMD_ARGV[0], "all")) { + breakpoint_remove_all(target); + } else { + target_addr_t addr; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); + + breakpoint_remove(target, addr); + } return ERROR_OK; } @@ -5017,7 +5036,7 @@ static int jim_target_examine(Jim_Interp *interp, int argc, Jim_Obj *const *argv if (goi.argc > 0 && strcmp(Jim_GetString(argv[1], NULL), "allow-defer") == 0) { /* consume it */ - struct Jim_Obj *obj; + Jim_Obj *obj; int e = Jim_GetOpt_Obj(&goi, &obj); if (e != JIM_OK) return e; @@ -5187,7 +5206,6 @@ static int jim_target_wait_state(Jim_Interp *interp, int argc, Jim_Obj *const *a "target: %s wait %s fails (%#s) %s", target_name(target), n->name, eObj, target_strerror_safe(e)); - Jim_FreeNewObj(interp, eObj); return JIM_ERR; } return JIM_OK; @@ -6241,7 +6259,7 @@ static const struct command_registration target_exec_command_handlers[] = { .name = "halt", .handler = handle_halt_command, .mode = COMMAND_EXEC, - .help = "request target to halt, then wait up to the specified" + .help = "request target to halt, then wait up to the specified " "number of milliseconds (default 5000) for it to complete", .usage = "[milliseconds]", }, @@ -6257,7 +6275,7 @@ static const struct command_registration target_exec_command_handlers[] = { .handler = handle_reset_command, .mode = COMMAND_EXEC, .usage = "[run|halt|init]", - .help = "Reset all targets into the specified mode." + .help = "Reset all targets into the specified mode. " "Default reset mode is run, if not given.", }, { @@ -6342,7 +6360,7 @@ static const struct command_registration target_exec_command_handlers[] = { .handler = handle_rbp_command, .mode = COMMAND_EXEC, .help = "remove breakpoint", - .usage = "address", + .usage = "'all' | address", }, { .name = "wp", diff --git a/src/target/target.h b/src/target/target.h index 8907714..5744000 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -32,6 +32,7 @@ #define OPENOCD_TARGET_TARGET_H #include <helper/list.h> +#include <jim.h> struct reg; struct trace; @@ -258,6 +259,8 @@ enum target_event { TARGET_EVENT_RESUMED, /* target resumed to normal execution */ TARGET_EVENT_RESUME_START, TARGET_EVENT_RESUME_END, + TARGET_EVENT_STEP_START, + TARGET_EVENT_STEP_END, TARGET_EVENT_GDB_START, /* debugger started execution (step/run) */ TARGET_EVENT_GDB_END, /* debugger stopped execution (step/run) */ @@ -275,6 +278,7 @@ enum target_event { TARGET_EVENT_DEBUG_RESUMED, /* target resumed to execute on behalf of the debugger */ TARGET_EVENT_EXAMINE_START, + TARGET_EVENT_EXAMINE_FAIL, TARGET_EVENT_EXAMINE_END, TARGET_EVENT_GDB_ATTACH, @@ -290,8 +294,8 @@ enum target_event { struct target_event_action { enum target_event event; - struct Jim_Interp *interp; - struct Jim_Obj *body; + Jim_Interp *interp; + Jim_Obj *body; struct target_event_action *next; }; @@ -763,6 +767,7 @@ void target_handle_md_output(struct command_invocation *cmd, #define ERROR_TARGET_NOT_RUNNING (-310) #define ERROR_TARGET_NOT_EXAMINED (-311) #define ERROR_TARGET_DUPLICATE_BREAKPOINT (-312) +#define ERROR_TARGET_ALGO_EXIT (-313) extern bool get_target_reset_nag(void); diff --git a/src/target/xscale.c b/src/target/xscale.c index 1a099c9..edab4f9 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -129,7 +129,7 @@ static const struct xscale_reg xscale_reg_arch_info[] = { /* convenience wrapper to access XScale specific registers */ static int xscale_set_reg_u32(struct reg *reg, uint32_t value) { - uint8_t buf[4]; + uint8_t buf[4] = { 0 }; buf_set_u32(buf, 0, 32, value); @@ -154,9 +154,9 @@ static int xscale_jtag_set_instr(struct jtag_tap *tap, uint32_t new_instr, tap_s if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { struct scan_field field; - uint8_t scratch[4]; + uint8_t scratch[4] = { 0 }; - memset(&field, 0, sizeof field); + memset(&field, 0, sizeof(field)); field.num_bits = tap->ir_length; field.out_value = scratch; buf_set_u32(scratch, 0, field.num_bits, new_instr); @@ -186,7 +186,7 @@ static int xscale_read_dcsr(struct target *target) buf_set_u32(&field0, 1, 1, xscale->hold_rst); buf_set_u32(&field0, 2, 1, xscale->external_debug_break); - memset(&fields, 0, sizeof fields); + memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 3; fields[0].out_value = &field0; @@ -259,7 +259,7 @@ static int xscale_receive(struct target *target, uint32_t *buffer, int num_words path[1] = TAP_DRCAPTURE; path[2] = TAP_DRSHIFT; - memset(&fields, 0, sizeof fields); + memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 3; uint8_t tmp; @@ -367,7 +367,7 @@ static int xscale_read_tx(struct target *target, int consume) noconsume_path[4] = TAP_DREXIT2; noconsume_path[5] = TAP_DRSHIFT; - memset(&fields, 0, sizeof fields); + memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 3; fields[0].in_value = &field0_in; @@ -442,7 +442,7 @@ static int xscale_write_rx(struct target *target) XSCALE_DBGRX << xscale->xscale_variant, TAP_IDLE); - memset(&fields, 0, sizeof fields); + memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 3; fields[0].out_value = &field0_out; @@ -514,7 +514,7 @@ static int xscale_send(struct target *target, const uint8_t *buffer, int count, TAP_IDLE); static const uint8_t t0; - uint8_t t1[4]; + uint8_t t1[4] = { 0 }; static const uint8_t t2 = 1; struct scan_field fields[3] = { { .num_bits = 3, .out_value = &t0 }, @@ -598,7 +598,7 @@ static int xscale_write_dcsr(struct target *target, int hold_rst, int ext_dbg_br buf_set_u32(&field0, 1, 1, xscale->hold_rst); buf_set_u32(&field0, 2, 1, xscale->external_debug_break); - memset(&fields, 0, sizeof fields); + memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 3; fields[0].out_value = &field0; @@ -645,8 +645,8 @@ static unsigned int parity(unsigned int v) static int xscale_load_ic(struct target *target, uint32_t va, uint32_t buffer[8]) { struct xscale_common *xscale = target_to_xscale(target); - uint8_t packet[4]; - uint8_t cmd; + uint8_t packet[4] = { 0 }; + uint8_t cmd = 0; int word; struct scan_field fields[2]; @@ -666,7 +666,7 @@ static int xscale_load_ic(struct target *target, uint32_t va, uint32_t buffer[8] /* virtual address of desired cache line */ buf_set_u32(packet, 0, 27, va >> 5); - memset(&fields, 0, sizeof fields); + memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 6; fields[0].out_value = &cmd; @@ -699,8 +699,8 @@ static int xscale_load_ic(struct target *target, uint32_t va, uint32_t buffer[8] static int xscale_invalidate_ic_line(struct target *target, uint32_t va) { struct xscale_common *xscale = target_to_xscale(target); - uint8_t packet[4]; - uint8_t cmd; + uint8_t packet[4] = { 0 }; + uint8_t cmd = 0; struct scan_field fields[2]; xscale_jtag_set_instr(target->tap, @@ -713,7 +713,7 @@ static int xscale_invalidate_ic_line(struct target *target, uint32_t va) /* virtual address of desired cache line */ buf_set_u32(packet, 0, 27, va >> 5); - memset(&fields, 0, sizeof fields); + memset(&fields, 0, sizeof(fields)); fields[0].num_bits = 6; fields[0].out_value = &cmd; @@ -1551,7 +1551,7 @@ static int xscale_deassert_reset(struct target *target) * coprocessors, trace data, etc. */ address = xscale->handler_address; - for (unsigned binary_size = sizeof xscale_debug_handler; + for (unsigned binary_size = sizeof(xscale_debug_handler); binary_size > 0; binary_size -= buf_cnt, buffer += buf_cnt) { uint32_t cache_line[8]; @@ -2981,7 +2981,7 @@ static int xscale_init_arch_info(struct target *target, /* prepare ARMv4/5 specific information */ arm->arch_info = xscale; - arm->core_type = ARM_MODE_ANY; + arm->core_type = ARM_CORE_TYPE_STD; arm->read_core_reg = xscale_read_core_reg; arm->write_core_reg = xscale_write_core_reg; arm->full_context = xscale_full_context; @@ -3004,7 +3004,7 @@ static int xscale_target_create(struct target *target, Jim_Interp *interp) { struct xscale_common *xscale; - if (sizeof xscale_debug_handler > 0x800) { + if (sizeof(xscale_debug_handler) > 0x800) { LOG_ERROR("debug_handler.bin: larger than 2kb"); return ERROR_FAIL; } @@ -3227,7 +3227,6 @@ COMMAND_HANDLER(xscale_handle_vector_catch_command) if (retval != ERROR_OK) return retval; - dcsr_value = buf_get_u32(dcsr_reg->value, 0, 32); if (CMD_ARGC > 0) { if (CMD_ARGC == 1) { if (strcmp(CMD_ARGV[0], "all") == 0) { diff --git a/src/transport/transport.c b/src/transport/transport.c index 77db9e2..010ea7c 100644 --- a/src/transport/transport.c +++ b/src/transport/transport.c @@ -290,7 +290,6 @@ static int jim_transport_select(Jim_Interp *interp, int argc, Jim_Obj * const *a } Jim_SetResultString(interp, session->name, -1); return JIM_OK; - break; case 2: /* assign */ if (session) { if (!strcmp(session->name, argv[1]->bytes)) { @@ -327,7 +326,6 @@ static int jim_transport_select(Jim_Interp *interp, int argc, Jim_Obj * const *a LOG_ERROR("Debug adapter doesn't support '%s' transport", argv[1]->bytes); return JIM_ERR; - break; default: Jim_WrongNumArgs(interp, 1, argv, "[too many parameters]"); return JIM_ERR; diff --git a/src/transport/transport.h b/src/transport/transport.h index 140ef50..809564e 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -96,6 +96,9 @@ bool transports_are_declared(void); bool transport_is_jtag(void); bool transport_is_swd(void); +bool transport_is_dapdirect_jtag(void); +bool transport_is_dapdirect_swd(void); +bool transport_is_swim(void); #if BUILD_HLADAPTER bool transport_is_hla(void); diff --git a/src/xsvf/xsvf.c b/src/xsvf/xsvf.c index e574c6f..bec32f2 100644 --- a/src/xsvf/xsvf.c +++ b/src/xsvf/xsvf.c @@ -918,8 +918,10 @@ COMMAND_HANDLER(handle_xsvf_command) struct scan_field field; result = svf_add_statemove(loop_state); - if (result != ERROR_OK) + if (result != ERROR_OK) { + free(dr_in_mask); return result; + } jtag_add_clocks(loop_clocks); jtag_add_sleep(loop_usecs); |