From 0dba1815e6362cc08e983f8f09af0224ad5ae693 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Tue, 3 Apr 2018 19:13:40 +0200 Subject: [PATCH 01/30] arm_adi_v5: Add ability to ignore the CSYSPWRUPACK bit The CTRL/STAT register in the ARM DAP DP has a debug power up ack bit and a system power up ack bit. Some devices do not set the system power up ack bit until sometime later. To avoid having the initial target examination fail due to this or to have a sticky bit error report claim power failure due to this a user can now specify that this bit should be ignored. Change-Id: I2451234bbe904984e29562ef6f616cc6d6f60732 Signed-off-by: Eric Katzfey Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/3710 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- doc/openocd.texi | 17 ++++++++++++++++- src/target/adi_v5_jtag.c | 8 +++++--- src/target/arm_adi_v5.c | 14 ++++++++------ src/target/arm_adi_v5.h | 4 ++++ src/target/arm_dap.c | 5 +++++ 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index d0a3d49b8..f51ff2442 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -3779,6 +3779,11 @@ a TAP doesn't conform to the JTAG specification. to verify that instruction scans work correctly. Such scans are not used by OpenOCD except to verify that there seems to be no problems with JTAG scan chain operations. +@item @code{-ignore-syspwrupack} +@*Specify this to ignore the CSYSPWRUPACK bit in the ARM DAP DP CTRL/STAT +register during initial examination and when checking the sticky error bit. +This bit is normally checked after setting the CSYSPWRUPREQ bit, but some +devices do not set the ack bit until sometime later. @end itemize @end deffn @@ -4014,11 +4019,21 @@ instead of "@option{-chain-position} @var{dotted.name}" when the target is creat The @command{dap} command group supports the following sub-commands: -@deffn Command {dap create} dap_name @option{-chain-position} dotted.name +@deffn Command {dap create} dap_name @option{-chain-position} dotted.name configparams... Declare a DAP instance named @var{dap_name} linked to the JTAG tap @var{dotted.name}. This also creates a new command (@command{dap_name}) which is used for various purposes including additional configuration. There can only be one DAP for each JTAG tap in the system. + +A DAP may also provide optional @var{configparams}: + +@itemize @bullet +@item @code{-ignore-syspwrupack} +@*Specify this to ignore the CSYSPWRUPACK bit in the ARM DAP DP CTRL/STAT +register during initial examination and when checking the sticky error bit. +This bit is normally checked after setting the CSYSPWRUPREQ bit, but some +devices do not set the ack bit until sometime later. +@end itemize @end deffn @deffn Command {dap names} diff --git a/src/target/adi_v5_jtag.c b/src/target/adi_v5_jtag.c index dc0237900..8c206115d 100644 --- a/src/target/adi_v5_jtag.c +++ b/src/target/adi_v5_jtag.c @@ -553,7 +553,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) static int jtagdp_transaction_endcheck(struct adiv5_dap *dap) { int retval; - uint32_t ctrlstat; + uint32_t ctrlstat, pwrmask; /* too expensive to call keep_alive() here */ @@ -571,8 +571,10 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap) if (ctrlstat & SSTICKYERR) { LOG_DEBUG("jtag-dp: CTRL/STAT 0x%" PRIx32, ctrlstat); /* Check power to debug regions */ - if ((ctrlstat & (CDBGPWRUPREQ | CDBGPWRUPACK | CSYSPWRUPREQ | CSYSPWRUPACK)) != - (CDBGPWRUPREQ | CDBGPWRUPACK | CSYSPWRUPREQ | CSYSPWRUPACK)) { + pwrmask = CDBGPWRUPREQ | CDBGPWRUPACK | CSYSPWRUPREQ; + if (!dap->ignore_syspwrupack) + pwrmask |= CSYSPWRUPACK; + if ((ctrlstat & pwrmask) != pwrmask) { LOG_ERROR("Debug regions are unpowered, an unexpected reset might have happened"); dap->do_reconnect = true; } diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 2b7d7b22d..f9b51cdec 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -676,12 +676,14 @@ int dap_dp_init(struct adiv5_dap *dap) if (retval != ERROR_OK) return retval; - LOG_DEBUG("DAP: wait CSYSPWRUPACK"); - retval = dap_dp_poll_register(dap, DP_CTRL_STAT, - CSYSPWRUPACK, CSYSPWRUPACK, - DAP_POWER_DOMAIN_TIMEOUT); - if (retval != ERROR_OK) - return retval; + if (!dap->ignore_syspwrupack) { + LOG_DEBUG("DAP: wait CSYSPWRUPACK"); + retval = dap_dp_poll_register(dap, DP_CTRL_STAT, + CSYSPWRUPACK, CSYSPWRUPACK, + DAP_POWER_DOMAIN_TIMEOUT); + if (retval != ERROR_OK) + return retval; + } retval = dap_queue_dp_read(dap, DP_CTRL_STAT, NULL); if (retval != ERROR_OK) diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index aa5fa42fe..bc5611650 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -244,6 +244,10 @@ struct adiv5_dap { * should be performed before the next access. */ bool do_reconnect; + + /** Flag saying whether to ignore the syspwrupack flag in DAP. Some devices + * do not set this bit until later in the bringup sequence */ + bool ignore_syspwrupack; }; /** diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c index 692feb322..797feb5ba 100644 --- a/src/target/arm_dap.c +++ b/src/target/arm_dap.c @@ -141,10 +141,12 @@ int dap_cleanup_all(void) enum dap_cfg_param { CFG_CHAIN_POSITION, + CFG_IGNORE_SYSPWRUPACK, }; static const Jim_Nvp nvp_config_opts[] = { { .name = "-chain-position", .value = CFG_CHAIN_POSITION }, + { .name = "-ignore-syspwrupack", .value = CFG_IGNORE_SYSPWRUPACK }, { .name = NULL, .value = -1 } }; @@ -177,6 +179,9 @@ static int dap_configure(Jim_GetOptInfo *goi, struct arm_dap_object *dap) /* loop for more */ break; } + case CFG_IGNORE_SYSPWRUPACK: + dap->dap.ignore_syspwrupack = true; + break; default: break; } From 2e2bb14b276f5bd973308dcfabd1b8018e187243 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 6 Mar 2018 14:10:04 -0800 Subject: [PATCH 02/30] Add gdb_report_register_access_error command With this option enabled (it's disabled by default) errors accessing registers are returned to gdb. Otherwise they are ignored and success is reported to gdb. (This is the current behavior.) We want this for RISC-V, but there's still some cleanup that needs to be done before that can be upstreamed. Signed-off-by: Tim Newsome Change-Id: I7e56109ea52d18b780c14a07fb35f9e6e8979da4 Reviewed-on: http://openocd.zylin.com/4452 Reviewed-by: Steven Stallion Reviewed-by: Matthias Welwarsky Tested-by: jenkins --- doc/openocd.texi | 7 ++++++ src/server/gdb_server.c | 56 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index f51ff2442..967c637ae 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2200,6 +2200,13 @@ The default behaviour is @option{disable}; use @option{enable} see these errors reported. @end deffn +@deffn {Config Command} gdb_report_register_access_error (@option{enable}|@option{disable}) +Specifies whether register accesses requested by GDB register read/write +packets report errors or not. +The default behaviour is @option{disable}; +use @option{enable} see these errors reported. +@end deffn + @deffn {Config Command} gdb_target_description (@option{enable}|@option{disable}) Set to @option{enable} to cause OpenOCD to send the target descriptions to gdb via qXfer:features:read packet. The default behaviour is @option{enable}. diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 428547b46..a3783af84 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -130,6 +130,9 @@ static int gdb_flash_program = 1; * Disabled by default. */ static int gdb_report_data_abort; +/* If set, errors when accessing registers are reported to gdb. Disabled by + * default. */ +static int gdb_report_register_access_error; /* set if we are sending target descriptions to gdb * via qXfer:features:read packet */ @@ -1187,8 +1190,15 @@ static int gdb_get_registers_packet(struct connection *connection, reg_packet_p = reg_packet; for (i = 0; i < reg_list_size; i++) { - if (!reg_list[i]->valid) - reg_list[i]->type->get(reg_list[i]); + if (!reg_list[i]->valid) { + retval = reg_list[i]->type->get(reg_list[i]); + if (retval != ERROR_OK && gdb_report_register_access_error) { + LOG_DEBUG("Couldn't get register %s.", reg_list[i]->name); + free(reg_packet); + free(reg_list); + return gdb_error(connection, retval); + } + } gdb_str_to_target(target, reg_packet_p, reg_list[i]); reg_packet_p += DIV_ROUND_UP(reg_list[i]->size, 8) * 2; } @@ -1249,7 +1259,13 @@ static int gdb_set_registers_packet(struct connection *connection, bin_buf = malloc(DIV_ROUND_UP(reg_list[i]->size, 8)); gdb_target_to_reg(target, packet_p, chars, bin_buf); - reg_list[i]->type->set(reg_list[i], bin_buf); + retval = reg_list[i]->type->set(reg_list[i], bin_buf); + if (retval != ERROR_OK && gdb_report_register_access_error) { + LOG_DEBUG("Couldn't set register %s.", reg_list[i]->name); + free(reg_list); + free(bin_buf); + return gdb_error(connection, retval); + } /* advance packet pointer */ packet_p += chars; @@ -1289,8 +1305,14 @@ static int gdb_get_register_packet(struct connection *connection, return ERROR_SERVER_REMOTE_CLOSED; } - if (!reg_list[reg_num]->valid) - reg_list[reg_num]->type->get(reg_list[reg_num]); + if (!reg_list[reg_num]->valid) { + retval = reg_list[reg_num]->type->get(reg_list[reg_num]); + if (retval != ERROR_OK && gdb_report_register_access_error) { + LOG_DEBUG("Couldn't get register %s.", reg_list[reg_num]->name); + free(reg_list); + return gdb_error(connection, retval); + } + } reg_packet = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1); /* plus one for string termination null */ @@ -1344,7 +1366,13 @@ static int gdb_set_register_packet(struct connection *connection, gdb_target_to_reg(target, separator + 1, chars, bin_buf); - reg_list[reg_num]->type->set(reg_list[reg_num], bin_buf); + retval = reg_list[reg_num]->type->set(reg_list[reg_num], bin_buf); + if (retval != ERROR_OK && gdb_report_register_access_error) { + LOG_DEBUG("Couldn't set register %s.", reg_list[reg_num]->name); + free(bin_buf); + free(reg_list); + return gdb_error(connection, retval); + } gdb_put_packet(connection, "OK", 2); @@ -3468,6 +3496,15 @@ COMMAND_HANDLER(handle_gdb_report_data_abort_command) return ERROR_OK; } +COMMAND_HANDLER(handle_gdb_report_register_access_error) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_report_register_access_error); + return ERROR_OK; +} + /* gdb_breakpoint_override */ COMMAND_HANDLER(handle_gdb_breakpoint_override_command) { @@ -3589,6 +3626,13 @@ static const struct command_registration gdb_command_handlers[] = { .help = "enable or disable reporting data aborts", .usage = "('enable'|'disable')" }, + { + .name = "gdb_report_register_access_error", + .handler = handle_gdb_report_register_access_error, + .mode = COMMAND_CONFIG, + .help = "enable or disable reporting register access errors", + .usage = "('enable'|'disable')" + }, { .name = "gdb_breakpoint_override", .handler = handle_gdb_breakpoint_override_command, From 414213a5ead0e34dec7f72748dbd5c721cb92c09 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Fri, 23 Feb 2018 00:03:20 +0100 Subject: [PATCH 03/30] target/arm_adi_v5: extend apcsw command to accept arbitrary bits apcsw command was limited to SPROT bit only. Now user can manipulate any bit except size and addrinc fields. Can be used e.g. to set bus signal 'cacheable' on Cortex-M7 Change-Id: Ia1c22b208e46d1653136f6faa5a7aaab036de7aa Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4431 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- doc/openocd.texi | 45 ++++++++++++++++++++++++++++++++++++++--- src/target/arm_adi_v5.c | 40 ++++++++++++++++++++++-------------- src/target/arm_adi_v5.h | 9 ++++++--- src/target/arm_dap.c | 2 ++ 4 files changed, 75 insertions(+), 21 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 967c637ae..1243438a4 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4070,6 +4070,7 @@ defaulting to the currently selected AP. Displays ID register from AP @var{num}, defaulting to the currently selected AP. @end deffn +@anchor{DAP subcommand apreg} @deffn Command {$dap_name apreg} ap_num reg [value] Displays content of a register @var{reg} from AP @var{ap_num} or set a new value @var{value}. @@ -4091,9 +4092,47 @@ memory bus access [0-255], giving additional time to respond to reads. If @var{value} is defined, first assigns that. @end deffn -@deffn Command {$dap_name apcsw} [0 / 1] -fix CSW_SPROT from register AP_REG_CSW on selected dap. -Defaulting to 0. +@deffn Command {$dap_name apcsw} [value [mask]] +Displays or changes CSW bit pattern for MEM-AP transfers. + +At the begin of each memory access the CSW pattern is extended (bitwise or-ed) +by @dfn{Size} and @dfn{AddrInc} bit-fields according to transfer requirements +and the result is written to the real CSW register. All bits except dynamically +updated fields @dfn{Size} and @dfn{AddrInc} can be changed by changing +the CSW pattern. Refer to ARM ADI v5 manual chapter 7.6.4 and appendix A +for details. + +Use @var{value} only syntax if you want to set the new CSW pattern as a whole. +The example sets HPROT1 bit (required by Cortex-M) and clears the rest of +the pattern: +@example +kx.dap apcsw 0x2000000 +@end example + +If @var{mask} is also used, the CSW pattern is changed only on bit positions +where the mask bit is 1. The following example sets HPROT3 (cacheable) +and leaves the rest of the pattern intact. It configures memory access through +DCache on Cortex-M7. +@example +set CSW_HPROT3_CACHEABLE [expr 1 << 27] +samv.dap apcsw $CSW_HPROT3_CACHEABLE $CSW_HPROT3_CACHEABLE +@end example + +Another example clears SPROT bit and leaves the rest of pattern intact: +@example +set CSW_SPROT [expr 1 << 30] +samv.dap apcsw 0 $CSW_SPROT +@end example + +@emph{Note:} If you want to check the real value of CSW, not CSW pattern, use +@code{xxx.dap apreg 0}. @xref{DAP subcommand apreg,,}. + +@emph{Warning:} Some of the CSW bits are vital for working memory transfer. +If you set a wrong CSW pattern and MEM-AP stopped working, use the following +example with a proper dap name: +@example +xxx.dap apcsw default +@end example @end deffn @deffn Command {$dap_name ti_be_32_quirks} [@option{enable}] diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index f9b51cdec..e2d9b5e66 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -97,8 +97,7 @@ static uint32_t max_tar_block_size(uint32_t tar_autoincr_block, uint32_t address static int mem_ap_setup_csw(struct adiv5_ap *ap, uint32_t csw) { - csw = csw | CSW_DBGSWENABLE | CSW_MASTER_DEBUG | CSW_HPROT | - ap->csw_default; + csw |= ap->csw_default; if (csw != ap->csw_value) { /* LOG_DEBUG("DAP: Set CSW %x",csw); */ @@ -1647,22 +1646,33 @@ COMMAND_HANDLER(dap_apcsw_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint32_t apcsw = dap->ap[dap->apsel].csw_default; - uint32_t sprot = 0; + uint32_t csw_val, csw_mask; switch (CMD_ARGC) { case 0: - command_print(CMD_CTX, "apsel %" PRIi32 " selected, csw 0x%8.8" PRIx32, - (dap->apsel), apcsw); - break; + command_print(CMD_CTX, "ap %" PRIi32 " selected, csw 0x%8.8" PRIx32, + dap->apsel, apcsw); + return ERROR_OK; case 1: - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], sprot); - /* AP address is in bits 31:24 of DP_SELECT */ - if (sprot > 1) - return ERROR_COMMAND_SYNTAX_ERROR; - if (sprot) - apcsw |= CSW_SPROT; + if (strcmp(CMD_ARGV[0], "default") == 0) + csw_val = CSW_DEFAULT; else - apcsw &= ~CSW_SPROT; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], csw_val); + + 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; + } + apcsw = csw_val; + break; + case 2: + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], csw_val); + 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; + } + apcsw = (apcsw & ~csw_mask) | (csw_val & csw_mask); break; default: return ERROR_COMMAND_SYNTAX_ERROR; @@ -1786,8 +1796,8 @@ const struct command_registration dap_instance_commands[] = { .name = "apcsw", .handler = dap_apcsw_command, .mode = COMMAND_EXEC, - .help = "Set csw access bit ", - .usage = "[sprot]", + .help = "Set CSW default bits", + .usage = "[value [mask]]", }, { diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index bc5611650..22c316630 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -112,13 +112,16 @@ #define CSW_ADDRINC_PACKED (2UL << 4) #define CSW_DEVICE_EN (1UL << 6) #define CSW_TRIN_PROG (1UL << 7) +/* all fields in bits 12 and above are implementation-defined! */ #define CSW_SPIDEN (1UL << 23) -/* 30:24 - implementation-defined! */ -#define CSW_HPROT (1UL << 25) /* ? */ -#define CSW_MASTER_DEBUG (1UL << 29) /* ? */ +#define CSW_HPROT1 (1UL << 25) /* AHB: Privileged */ +#define CSW_MASTER_DEBUG (1UL << 29) /* AHB: set HMASTER signals to AHB-AP ID */ #define CSW_SPROT (1UL << 30) #define CSW_DBGSWENABLE (1UL << 31) +/* initial value of csw_default used for MEM-AP transfers */ +#define CSW_DEFAULT (CSW_HPROT1 | CSW_MASTER_DEBUG | CSW_DBGSWENABLE) + /* Fields of the MEM-AP's IDR register */ #define IDR_REV (0xFUL << 28) #define IDR_JEP106 (0x7FFUL << 17) diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c index 797feb5ba..8c081800f 100644 --- a/src/target/arm_dap.c +++ b/src/target/arm_dap.c @@ -55,6 +55,8 @@ static void dap_instance_init(struct adiv5_dap *dap) dap->ap[i].memaccess_tck = 255; /* Number of bits for tar autoincrement, impl. dep. at least 10 */ dap->ap[i].tar_autoincr_block = (1<<10); + /* default CSW value */ + dap->ap[i].csw_default = CSW_DEFAULT; } INIT_LIST_HEAD(&dap->cmd_journal); } From db456e209feaecae53094051f3710fef73418a71 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Fri, 6 Apr 2018 12:38:12 +0200 Subject: [PATCH 04/30] target: free target SMP list on shutdown On SMP targets, the "target smp" command creates a list of targets that belong to the SMP cluster. Free this list when a target gets destroyed on shutdown. For simplicity, the complete list is free'd as soon as the first target of the SMP cluster is destroyed instead of individually removing targets from the list. Change-Id: Ie217ae1efb2e819c288ff3b1155aeaf0a19b06be Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4481 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/target.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/target/target.c b/src/target/target.c index ac2e1d030..729a31bf5 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1910,6 +1910,18 @@ static void target_destroy(struct target *target) free(target->working_areas); } + /* release the targets SMP list */ + if (target->smp) { + struct target_list *head = target->head; + while (head != NULL) { + struct target_list *pos = head->next; + head->target->smp = 0; + free(head); + head = pos; + } + target->smp = 0; + } + free(target->type); free(target->trace_info); free(target->fileio_info); From 4f2c3e6c4f82fbbf9c5d7e8a234c949d11ef5ae7 Mon Sep 17 00:00:00 2001 From: Armin van der Togt Date: Thu, 2 Mar 2017 10:39:26 +0100 Subject: [PATCH 05/30] rtos: Fix XPSR_OFFSET for cortex_m4f stacking Structures rtos_standard_Cortex_M4F_stacking and rtos_standard_Cortex_M4F_FPU_stacking in rtos_standard_stackings.c where using rtos_standard_Cortex_M3_stack_align for the stack-align function. This function calls rtos_Cortex_M_stack_align with XPSR_OFFSET = 0x3c. This offset is correct for cortex-M3 but not for cortex-M4F and cortex-M4F with fpu. This patch adds stack_align functions for M4F an M4F_FPU Change-Id: If6a90b1898fccbb85619a10f3aef5277dd88ce47 Signed-off-by: Armin van der Togt Reviewed-on: http://openocd.zylin.com/4037 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/rtos/rtos_standard_stackings.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/rtos/rtos_standard_stackings.c b/src/rtos/rtos_standard_stackings.c index 0176c01ab..931cfc7ed 100644 --- a/src/rtos/rtos_standard_stackings.c +++ b/src/rtos/rtos_standard_stackings.c @@ -229,6 +229,25 @@ static int64_t rtos_standard_Cortex_M3_stack_align(struct target *target, stack_ptr, XPSR_OFFSET); } +static int64_t rtos_standard_Cortex_M4F_stack_align(struct target *target, + const uint8_t *stack_data, const struct rtos_register_stacking *stacking, + int64_t stack_ptr) +{ + const int XPSR_OFFSET = 0x40; + return rtos_Cortex_M_stack_align(target, stack_data, stacking, + stack_ptr, XPSR_OFFSET); +} + +static int64_t rtos_standard_Cortex_M4F_FPU_stack_align(struct target *target, + const uint8_t *stack_data, const struct rtos_register_stacking *stacking, + int64_t stack_ptr) +{ + const int XPSR_OFFSET = 0x80; + return rtos_Cortex_M_stack_align(target, stack_data, stacking, + stack_ptr, XPSR_OFFSET); +} + + const struct rtos_register_stacking rtos_standard_Cortex_M3_stacking = { 0x40, /* stack_registers_size */ -1, /* stack_growth_direction */ @@ -241,7 +260,7 @@ const struct rtos_register_stacking rtos_standard_Cortex_M4F_stacking = { 0x44, /* stack_registers_size 4 more for LR*/ -1, /* stack_growth_direction */ ARMV7M_NUM_CORE_REGS, /* num_output_registers */ - rtos_standard_Cortex_M3_stack_align, /* stack_alignment */ + rtos_standard_Cortex_M4F_stack_align, /* stack_alignment */ rtos_standard_Cortex_M4F_stack_offsets /* register_offsets */ }; @@ -249,7 +268,7 @@ const struct rtos_register_stacking rtos_standard_Cortex_M4F_FPU_stacking = { 0xcc, /* stack_registers_size 4 more for LR + 48 more for FPU S0-S15 register*/ -1, /* stack_growth_direction */ ARMV7M_NUM_CORE_REGS, /* num_output_registers */ - rtos_standard_Cortex_M3_stack_align, /* stack_alignment */ + rtos_standard_Cortex_M4F_FPU_stack_align, /* stack_alignment */ rtos_standard_Cortex_M4F_FPU_stack_offsets /* register_offsets */ }; From dbd7e80eb47d37bb8bfc1c55f19c61f5ee561393 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 27 Feb 2018 09:44:07 +0100 Subject: [PATCH 06/30] gdb_server: gdb_memory_map() rework Use sector sizes instead of bank size. Detect a gap between sectors and emit xml blocks accordingly. Detect sector overflow over the bank size. Change-Id: If0e0e44b0c3b93067b4d717c9c7b07c08582e57b Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4436 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/server/gdb_server.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index a3783af84..d329bfeb3 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1808,7 +1808,7 @@ static int gdb_memory_map(struct connection *connection, int offset; int length; char *separator; - uint32_t ram_start = 0; + target_addr_t ram_start = 0; int i; int target_flash_banks = 0; @@ -1823,9 +1823,6 @@ static int gdb_memory_map(struct connection *connection, /* Sort banks in ascending order. We need to report non-flash * memory as ram (or rather read/write) by default for GDB, since * it has no concept of non-cacheable read/write memory (i/o etc). - * - * FIXME Most non-flash addresses are *NOT* RAM! Don't lie. - * Current versions of GDB assume unlisted addresses are RAM... */ banks = malloc(sizeof(struct flash_bank *)*flash_get_bank_count()); @@ -1848,14 +1845,13 @@ static int gdb_memory_map(struct connection *connection, for (i = 0; i < target_flash_banks; i++) { int j; unsigned sector_size = 0; - uint32_t start; + unsigned group_len = 0; p = banks[i]; - start = p->base; if (ram_start < p->base) xml_printf(&retval, &xml, &pos, &size, - "\n", ram_start, p->base - ram_start); @@ -1866,27 +1862,35 @@ static int gdb_memory_map(struct connection *connection, * regions with 8KB, 32KB, and 64KB sectors; etc. */ for (j = 0; j < p->num_sectors; j++) { - unsigned group_len; /* Maybe start a new group of sectors. */ if (sector_size == 0) { + if (p->sectors[j].offset + p->sectors[j].size > p->size) { + LOG_WARNING("The flash sector at offset 0x%08" PRIx32 + " overflows the end of %s bank.", + p->sectors[j].offset, p->name); + LOG_WARNING("The rest of bank will not show in gdb memory map."); + break; + } + target_addr_t start; start = p->base + p->sectors[j].offset; xml_printf(&retval, &xml, &pos, &size, "sectors[j].size; + group_len = sector_size; + } else { + group_len += sector_size; /* equal to p->sectors[j].size */ } /* Does this finish a group of sectors? * If not, continue an already-started group. */ - if (j == p->num_sectors - 1) - group_len = (p->base + p->size) - start; - else if (p->sectors[j + 1].size != sector_size) - group_len = p->base + p->sectors[j + 1].offset - - start; - else + if (j < p->num_sectors - 1 + && p->sectors[j + 1].size == sector_size + && p->sectors[j + 1].offset == p->sectors[j].offset + sector_size + && p->sectors[j + 1].offset + p->sectors[j + 1].size <= p->size) continue; xml_printf(&retval, &xml, &pos, &size, @@ -1904,7 +1908,7 @@ static int gdb_memory_map(struct connection *connection, if (ram_start != 0) xml_printf(&retval, &xml, &pos, &size, - "\n", ram_start, 0-ram_start); /* ELSE a flash chip could be at the very end of the 32 bit address @@ -1912,11 +1916,11 @@ static int gdb_memory_map(struct connection *connection, */ free(banks); - banks = NULL; xml_printf(&retval, &xml, &pos, &size, "\n"); if (retval != ERROR_OK) { + free(xml); gdb_error(connection, retval); return retval; } From 70b15f989f09428a85d6e52d8a03dc902081eb01 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Wed, 21 Mar 2018 18:40:36 +0300 Subject: [PATCH 07/30] configure: disable all drivers when zy1000 is enabled This also fixes the transport_is_hla FIXME. Change-Id: I33960f373f11e3e203f9aed9c6d02bf7ca48ac97 Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/4473 Tested-by: jenkins Reviewed-by: Tomas Vanek --- configure.ac | 3 +++ src/transport/transport.h | 5 +---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index f4f66ab43..312fda8b2 100644 --- a/configure.ac +++ b/configure.ac @@ -634,6 +634,9 @@ PKG_CHECK_MODULES([LIBJAYLINK], [libjaylink >= 0.2], m4_define([PROCESS_ADAPTERS], [ m4_foreach([adapter], [$1], [ + AS_IF([test "x$build_zy1000" = "xyes"], [ + ADAPTER_VAR([adapter])=no + ]) AS_IF([test $2], [ AS_IF([test "x$ADAPTER_VAR([adapter])" != "xno"], [ AC_DEFINE([BUILD_]ADAPTER_SYM([adapter]), [1], [1 if you want the ]ADAPTER_DESC([adapter]).) diff --git a/src/transport/transport.h b/src/transport/transport.h index d0a77ddfb..140ef503d 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -97,10 +97,7 @@ bool transports_are_declared(void); bool transport_is_jtag(void); bool transport_is_swd(void); -/* FIXME: ZY1000 test build on jenkins is configured with enabled hla adapters - * but jtag/hla/hla_*.c files are not compiled. To workaround the problem we assume hla - * is broken if BUILD_ZY1000 is set */ -#if BUILD_HLADAPTER && !BUILD_ZY1000 +#if BUILD_HLADAPTER bool transport_is_hla(void); #else static inline bool transport_is_hla(void) From 6e356cbfe27c1718d784f7aa36efb483a523fb64 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Tue, 16 Jan 2018 15:11:18 +0300 Subject: [PATCH 08/30] HACKING: document practices to improve code quality Change-Id: I58a7d978b7d5bca3037c4535f06746b9f4411950 Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/4343 Tested-by: jenkins --- HACKING | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/HACKING b/HACKING index 0bea65a75..0d24957e1 100644 --- a/HACKING +++ b/HACKING @@ -29,12 +29,58 @@ The procedure to create a patch is essentially: - correct the patch and re-send it according to review feedback Your patch (or commit) should be a "good patch": focus it on a single -issue, and make it be easily reviewable. Don't make +issue, and make it easily reviewable. Don't make it so large that it's hard to review; split large -patches into smaller ones. (That can also help -track down bugs later on.) All patches should +patches into smaller ones (this will also help +to track down bugs later). All patches should be "clean", which includes preserving the existing -coding style and updating documentation as needed. +coding style and updating documentation as needed. When adding a new +command, the corresponding documentation should be added to +@c doc/openocd.texi in the same commit. OpenOCD runs on both Little +Endian and Big Endian hosts so the code can't count on specific byte +ordering (in other words, must be endian-clean). + +There are several additional methods of improving the quality of your +patch: + +- Runtime testing with Valgrind Memcheck + + This helps to spot memory leaks, undefined behaviour due to + uninitialized data or wrong indexing, memory corruption, etc. + +- Clang Static Analyzer + + Using this tool uncovers many different kinds of bugs in C code, + with problematic execution paths fully explained. It is a part of + standard Clang installation. + + To generate a report, run this in the OpenOCD source directory: + @code + mkdir build-scanbuild; cd build-scanbuild + scan-build ../configure + scan-build make CFLAGS="-std=gnu99 -I. -I../../jimtcl" + @endcode + +- Runtime testing with sanitizers + + Both GCC and LLVM/Clang include advanced instrumentation options to + detect undefined behaviour and many kinds of memory + errors. Available with @c -fsanitize=* command arguments. + + Example usage: + @code + mkdir build-sanitizers; cd build-sanitizers + ../configure CC=clang CFLAGS="-fno-omit-frame-pointer \ + -fsanitize=address -fsanitize=undefined -ggdb3" + make + export ASAN_OPTIONS=detect_stack_use_after_return=1 + src/openocd -s ../tcl -f /path/to/openocd.cfg + @endcode + +Please consider performing these additonal checks where appropriate +(especially Clang Static Analyzer for big portions of new code) and +mention the results (e.g. "Valgrind-clean, no new Clang analyzer +warnings") in the commit message. Say in the commit message if it's a bugfix (describe the bug) or a new feature. Don't expect patches to merge immediately From f00d9bb1d7e6d52e62e7cfc402fda96f3544d911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Sat, 7 Apr 2018 21:39:45 +0200 Subject: [PATCH 09/30] tcl/target: Add Renesas R-Car R8A7791 M2W target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add configuration for the Renesas R-Car R8A7791 M2W target. This is an SoC with two Cortex A15 ARMv7a cores, both cores are supported. This patch is based on initial submission by Adam Bass and improvements by Niklas Söderlund. Change-Id: I297da62b9ce71ad222a401d98e6bcb8502427673 Signed-off-by: Marek Vasut Cc: Adam Bass Cc: Niklas Söderlund Reviewed-on: http://openocd.zylin.com/4485 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/target/renesas_r8a7791.cfg | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tcl/target/renesas_r8a7791.cfg diff --git a/tcl/target/renesas_r8a7791.cfg b/tcl/target/renesas_r8a7791.cfg new file mode 100644 index 000000000..f93cbb8f1 --- /dev/null +++ b/tcl/target/renesas_r8a7791.cfg @@ -0,0 +1,27 @@ +# Renesas R-Car M2 +# https://www.renesas.com/en-us/solutions/automotive/products/rcar-m2.html + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x4ba00477 +} + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME r8a7791 +} + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $_DAP_TAPID + +# Configuring only one core using DAP. +# Base addresses of cores: +# core 0 - 0x800B0000 +# core 1 - 0x800B2000 +set _TARGETNAME $_CHIPNAME.ca15. +dap create ${_CHIPNAME}.dap -chain-position $_CHIPNAME.cpu +target create ${_TARGETNAME}0 cortex_a -dap ${_CHIPNAME}.dap -coreid 0 -dbgbase 0x800B0000 +target create ${_TARGETNAME}1 cortex_a -dap ${_CHIPNAME}.dap -coreid 1 -dbgbase 0x800B2000 -defer-examine + +targets ${_TARGETNAME}0 From eb8912ec38c0fd6867d2b5a88b40549f791ce7bb Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 23 Nov 2017 09:18:24 +0100 Subject: [PATCH 10/30] target, flash: prepare infrastructure for multi-block blank check 'flash erase_check' command runs a check algorithm on a target if possible. The algorithm is run repeatedly for each flash sector. Unfortunately every start and stop of the algorithm impose not negligible overhead. In practice it means checking is faster than plain read only for sectors of size approx 4 kByte or bigger. And checking sectors as short as 512 bytes runs approx 4 times slower than plain read. The patch changes API call target_blank_check_memory() and related to take an array of sectors (or arbitrary memory blocks). Changes in target-specific checking routines are kept minimal. They use only the first block from the array and process it by the unchanged algorithm. default_flash_blank_check() routine repeats target_blank_check_memory() until all blocks are checked, so it works with both multi-block and single-block based checkers. Change-Id: I0e6c60f2d71364c9c07c09416b04de9268807f5e Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4297 Tested-by: jenkins Reviewed-by: Andreas Bolsch --- src/flash/nor/at91sam7.c | 48 +--------------------------------------- src/flash/nor/core.c | 45 +++++++++++++++++++++++-------------- src/target/arm.h | 2 +- src/target/armv4_5.c | 13 ++++++----- src/target/armv7m.c | 13 ++++++----- src/target/armv7m.h | 2 +- src/target/mips32.c | 17 +++++++++----- src/target/mips32.h | 2 +- src/target/stm8.c | 13 ++++++----- src/target/target.c | 10 ++++----- src/target/target.h | 9 +++++++- src/target/target_type.h | 5 +++-- 12 files changed, 83 insertions(+), 96 deletions(-) diff --git a/src/flash/nor/at91sam7.c b/src/flash/nor/at91sam7.c index 03f771c87..9de829327 100644 --- a/src/flash/nor/at91sam7.c +++ b/src/flash/nor/at91sam7.c @@ -639,14 +639,6 @@ static int at91sam7_read_part_info(struct flash_bank *bank) static int at91sam7_erase_check(struct flash_bank *bank) { - struct target *target = bank->target; - uint16_t retval; - uint32_t blank; - uint16_t fast_check; - uint8_t *buffer; - uint16_t nSector; - uint16_t nByte; - if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; @@ -656,45 +648,7 @@ static int at91sam7_erase_check(struct flash_bank *bank) at91sam7_read_clock_info(bank); at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH); - fast_check = 1; - for (nSector = 0; nSector < bank->num_sectors; nSector++) { - retval = target_blank_check_memory(target, - bank->base + bank->sectors[nSector].offset, - bank->sectors[nSector].size, - &blank, bank->erased_value); - if (retval != ERROR_OK) { - fast_check = 0; - break; - } - if (blank == 0xFF) - bank->sectors[nSector].is_erased = 1; - else - bank->sectors[nSector].is_erased = 0; - } - - if (fast_check) - return ERROR_OK; - - LOG_USER("Running slow fallback erase check - add working memory"); - - buffer = malloc(bank->sectors[0].size); - for (nSector = 0; nSector < bank->num_sectors; nSector++) { - bank->sectors[nSector].is_erased = 1; - retval = target_read_memory(target, bank->base + bank->sectors[nSector].offset, 4, - bank->sectors[nSector].size/4, buffer); - if (retval != ERROR_OK) - return retval; - - for (nByte = 0; nByte < bank->sectors[nSector].size; nByte++) { - if (buffer[nByte] != 0xFF) { - bank->sectors[nSector].is_erased = 0; - break; - } - } - } - free(buffer); - - return ERROR_OK; + return default_flash_blank_check(bank); } static int at91sam7_protect_check(struct flash_bank *bank) diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c index 636d50c51..707dcff18 100644 --- a/src/flash/nor/core.c +++ b/src/flash/nor/core.c @@ -339,36 +339,49 @@ int default_flash_blank_check(struct flash_bank *bank) struct target *target = bank->target; int i; int retval; - int fast_check = 0; - uint32_t blank; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - for (i = 0; i < bank->num_sectors; i++) { - uint32_t address = bank->base + bank->sectors[i].offset; - uint32_t size = bank->sectors[i].size; + struct target_memory_check_block *block_array; + block_array = malloc(bank->num_sectors * sizeof(struct target_memory_check_block)); + if (block_array == NULL) + return default_flash_mem_blank_check(bank); - retval = target_blank_check_memory(target, address, size, &blank, bank->erased_value); - if (retval != ERROR_OK) { - fast_check = 0; + for (i = 0; i < bank->num_sectors; i++) { + block_array[i].address = bank->base + bank->sectors[i].offset; + block_array[i].size = bank->sectors[i].size; + block_array[i].result = UINT32_MAX; /* erase state unknown */ + } + + bool fast_check = true; + for (i = 0; i < bank->num_sectors; ) { + retval = target_blank_check_memory(target, + block_array + i, bank->num_sectors - i, + bank->erased_value); + if (retval < 1) { + /* Run slow fallback if the first run gives no result + * otherwise use possibly incomplete results */ + if (i == 0) + fast_check = false; break; } - if (blank == bank->erased_value) - bank->sectors[i].is_erased = 1; - else - bank->sectors[i].is_erased = 0; - fast_check = 1; + i += retval; /* add number of blocks done this round */ } - if (!fast_check) { + if (fast_check) { + for (i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_erased = block_array[i].result; + retval = ERROR_OK; + } else { LOG_USER("Running slow fallback erase check - add working memory"); - return default_flash_mem_blank_check(bank); + retval = default_flash_mem_blank_check(bank); } + free(block_array); - return ERROR_OK; + return retval; } /* Manipulate given flash region, selecting the bank according to target diff --git a/src/target/arm.h b/src/target/arm.h index 62fbb7368..dd25d53be 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -308,7 +308,7 @@ int armv4_5_run_algorithm_inner(struct target *target, int arm_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); int arm_blank_check_memory(struct target *target, - target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value); + struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value); void arm_set_cpsr(struct arm *arm, uint32_t cpsr); struct reg *arm_reg_current(struct arm *arm, unsigned regnum); diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index a6fadaa0b..06994ca7b 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -1663,7 +1663,7 @@ cleanup: * */ int arm_blank_check_memory(struct target *target, - target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value) + struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value) { struct working_area *check_algorithm; struct reg_param reg_params[3]; @@ -1706,10 +1706,10 @@ int arm_blank_check_memory(struct target *target, arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); - buf_set_u32(reg_params[0].value, 0, 32, address); + buf_set_u32(reg_params[0].value, 0, 32, blocks[0].address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); - buf_set_u32(reg_params[1].value, 0, 32, count); + buf_set_u32(reg_params[1].value, 0, 32, blocks[0].size); init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, erased_value); @@ -1724,7 +1724,7 @@ int arm_blank_check_memory(struct target *target, 10000, &arm_algo); if (retval == ERROR_OK) - *blank = buf_get_u32(reg_params[2].value, 0, 32); + blocks[0].result = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); @@ -1733,7 +1733,10 @@ int arm_blank_check_memory(struct target *target, cleanup: target_free_working_area(target, check_algorithm); - return retval; + if (retval != ERROR_OK) + return retval; + + return 1; /* only one block has been checked */ } static int arm_full_context(struct target *target) diff --git a/src/target/armv7m.c b/src/target/armv7m.c index a8ddfe894..696f85cb2 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -733,7 +733,7 @@ cleanup: /** Checks whether a memory region is erased. */ int armv7m_blank_check_memory(struct target *target, - target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value) + struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value) { struct working_area *erase_check_algorithm; struct reg_param reg_params[3]; @@ -774,10 +774,10 @@ int armv7m_blank_check_memory(struct target *target, armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); - buf_set_u32(reg_params[0].value, 0, 32, address); + buf_set_u32(reg_params[0].value, 0, 32, blocks->address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); - buf_set_u32(reg_params[1].value, 0, 32, count); + buf_set_u32(reg_params[1].value, 0, 32, blocks->size); init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, erased_value); @@ -793,7 +793,7 @@ int armv7m_blank_check_memory(struct target *target, &armv7m_info); if (retval == ERROR_OK) - *blank = buf_get_u32(reg_params[2].value, 0, 32); + blocks->result = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); @@ -802,7 +802,10 @@ int armv7m_blank_check_memory(struct target *target, cleanup: target_free_working_area(target, erase_check_algorithm); - return retval; + if (retval != ERROR_OK) + return retval; + + return 1; /* only one block checked */ } int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found) diff --git a/src/target/armv7m.h b/src/target/armv7m.h index 6f5d6f995..01bf19e5c 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -225,7 +225,7 @@ int armv7m_restore_context(struct target *target); int armv7m_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); int armv7m_blank_check_memory(struct target *target, - target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value); + struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value); int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found); diff --git a/src/target/mips32.c b/src/target/mips32.c index 93fb4e646..b5dbea312 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -827,7 +827,8 @@ int mips32_checksum_memory(struct target *target, target_addr_t address, /** Checks whether a memory region is erased. */ int mips32_blank_check_memory(struct target *target, - target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value) + struct target_memory_check_block *blocks, int num_blocks, + uint8_t erased_value) { struct working_area *erase_check_algorithm; struct reg_param reg_params[3]; @@ -866,16 +867,16 @@ int mips32_blank_check_memory(struct target *target, int retval = target_write_buffer(target, erase_check_algorithm->address, sizeof(erase_check_code), erase_check_code_8); if (retval != ERROR_OK) - return retval; + goto cleanup; mips32_info.common_magic = MIPS32_COMMON_MAGIC; mips32_info.isa_mode = isa ? MIPS32_ISA_MMIPS32 : MIPS32_ISA_MIPS32; init_reg_param(®_params[0], "r4", 32, PARAM_OUT); - buf_set_u32(reg_params[0].value, 0, 32, address); + buf_set_u32(reg_params[0].value, 0, 32, blocks[0].address); init_reg_param(®_params[1], "r5", 32, PARAM_OUT); - buf_set_u32(reg_params[1].value, 0, 32, count); + buf_set_u32(reg_params[1].value, 0, 32, blocks[0].size); init_reg_param(®_params[2], "r6", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, erased_value); @@ -884,15 +885,19 @@ int mips32_blank_check_memory(struct target *target, erase_check_algorithm->address + (sizeof(erase_check_code) - 4), 10000, &mips32_info); if (retval == ERROR_OK) - *blank = buf_get_u32(reg_params[2].value, 0, 32); + blocks[0].result = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); +cleanup: target_free_working_area(target, erase_check_algorithm); - return retval; + if (retval != ERROR_OK) + return retval; + + return 1; /* only one block has been checked */ } static int mips32_verify_pointer(struct command_context *cmd_ctx, diff --git a/src/target/mips32.h b/src/target/mips32.h index 928598f4c..4dc164e1b 100644 --- a/src/target/mips32.h +++ b/src/target/mips32.h @@ -428,6 +428,6 @@ int mips32_get_gdb_reg_list(struct target *target, int mips32_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); int mips32_blank_check_memory(struct target *target, - target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value); + struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value); #endif /* OPENOCD_TARGET_MIPS32_H */ diff --git a/src/target/stm8.c b/src/target/stm8.c index 4556fd987..5a3438a64 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -1750,7 +1750,7 @@ static int stm8_examine(struct target *target) /** Checks whether a memory region is erased. */ static int stm8_blank_check_memory(struct target *target, - target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value) + struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value) { struct working_area *erase_check_algorithm; struct reg_param reg_params[2]; @@ -1778,10 +1778,10 @@ static int stm8_blank_check_memory(struct target *target, stm8_info.common_magic = STM8_COMMON_MAGIC; init_mem_param(&mem_params[0], 0x0, 3, PARAM_OUT); - buf_set_u32(mem_params[0].value, 0, 24, address); + buf_set_u32(mem_params[0].value, 0, 24, blocks[0].address); init_mem_param(&mem_params[1], 0x3, 3, PARAM_OUT); - buf_set_u32(mem_params[1].value, 0, 24, count); + buf_set_u32(mem_params[1].value, 0, 24, blocks[0].size); init_reg_param(®_params[0], "a", 32, PARAM_IN_OUT); buf_set_u32(reg_params[0].value, 0, 32, erased_value); @@ -1795,7 +1795,7 @@ static int stm8_blank_check_memory(struct target *target, 10000, &stm8_info); if (retval == ERROR_OK) - *blank = (*(reg_params[0].value) == 0xff); + blocks[0].result = (*(reg_params[0].value) == 0xff); destroy_mem_param(&mem_params[0]); destroy_mem_param(&mem_params[1]); @@ -1803,7 +1803,10 @@ static int stm8_blank_check_memory(struct target *target, target_free_working_area(target, erase_check_algorithm); - return retval; + if (retval != ERROR_OK) + return retval; + + return 1; /* only one block has been checked */ } static int stm8_checksum_memory(struct target *target, target_addr_t address, diff --git a/src/target/target.c b/src/target/target.c index 729a31bf5..75555c167 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -2251,21 +2251,19 @@ int target_checksum_memory(struct target *target, target_addr_t address, uint32_ return retval; } -int target_blank_check_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t* blank, +int target_blank_check_memory(struct target *target, + struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value) { - int retval; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } - if (target->type->blank_check_memory == 0) + if (target->type->blank_check_memory == NULL) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - retval = target->type->blank_check_memory(target, address, size, blank, erased_value); - - return retval; + return target->type->blank_check_memory(target, blocks, num_blocks, erased_value); } int target_read_u64(struct target *target, target_addr_t address, uint64_t *value) diff --git a/src/target/target.h b/src/target/target.h index 7a8a80f30..c5fb55ba7 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -312,6 +312,12 @@ struct target_timer_callback { struct target_timer_callback *next; }; +struct target_memory_check_block { + target_addr_t address; + uint32_t size; + uint32_t result; +}; + int target_register_commands(struct command_context *cmd_ctx); int target_examine(void); @@ -585,7 +591,8 @@ int target_read_buffer(struct target *target, int target_checksum_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t *crc); int target_blank_check_memory(struct target *target, - target_addr_t address, uint32_t size, uint32_t *blank, uint8_t erased_value); + struct target_memory_check_block *blocks, int num_blocks, + uint8_t erased_value); int target_wait_state(struct target *target, enum target_state state, int ms); /** diff --git a/src/target/target_type.h b/src/target/target_type.h index 0ab22bd5c..fbbd57d98 100644 --- a/src/target/target_type.h +++ b/src/target/target_type.h @@ -130,8 +130,9 @@ struct target_type { int (*checksum_memory)(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); - int (*blank_check_memory)(struct target *target, target_addr_t address, - uint32_t count, uint32_t *blank, uint8_t erased_value); + int (*blank_check_memory)(struct target *target, + struct target_memory_check_block *blocks, int num_blocks, + uint8_t erased_value); /* * target break-/watchpoint control From a867e36f78be231bfdf5161ff7172bcf69aa6280 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 23 Nov 2017 11:17:53 +0100 Subject: [PATCH 11/30] target armv7m: multi-block erase check Tested on PSoC6 (Cortex-M0+ core), onboard KitProg2 in CMSIS-DAP mode, adapter_khz=1000. Plain read: flash read_bank 0 /dev/null takes 48 seconds. erase_check without this change: flash erase_check 0 takes horrible 149 seconds!! And the same command with the change applied takes 1.8 seconds. Quite a difference. Remove the erase-value=0 version of algorithm as the new one can check for any value. If the target is an insane slow clocked CPU (under 1MHz) algo timeouts. Blocks checked so far are returned and the next call uses increased timeout. Change-Id: Ic0899011256d2114112e67c0b51fab4f6230d9cd Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4298 Tested-by: jenkins Reviewed-by: Jonas Norling Reviewed-by: Andreas Bolsch --- contrib/loaders/erase_check/Makefile | 2 +- .../erase_check/armv7m_0_erase_check.inc | 2 - .../erase_check/armv7m_0_erase_check.s | 45 ------ .../erase_check/armv7m_erase_check.inc | 4 +- .../loaders/erase_check/armv7m_erase_check.s | 48 +++++-- src/target/armv7m.c | 134 +++++++++++++----- 6 files changed, 137 insertions(+), 98 deletions(-) delete mode 100644 contrib/loaders/erase_check/armv7m_0_erase_check.inc delete mode 100644 contrib/loaders/erase_check/armv7m_0_erase_check.s diff --git a/contrib/loaders/erase_check/Makefile b/contrib/loaders/erase_check/Makefile index 427fa0c07..1a0fd9e3f 100644 --- a/contrib/loaders/erase_check/Makefile +++ b/contrib/loaders/erase_check/Makefile @@ -12,7 +12,7 @@ STM8_OBJCOPY ?= $(STM8_CROSS_COMPILE)objcopy STM8_AFLAGS = -arm: armv4_5_erase_check.inc armv7m_erase_check.inc armv7m_0_erase_check.inc +arm: armv4_5_erase_check.inc armv7m_erase_check.inc armv4_5_%.elf: armv4_5_%.s $(ARM_AS) $(ARM_AFLAGS) $< -o $@ diff --git a/contrib/loaders/erase_check/armv7m_0_erase_check.inc b/contrib/loaders/erase_check/armv7m_0_erase_check.inc deleted file mode 100644 index 76115ec17..000000000 --- a/contrib/loaders/erase_check/armv7m_0_erase_check.inc +++ /dev/null @@ -1,2 +0,0 @@ -/* Autogenerated with ../../../src/helper/bin2char.sh */ -0x03,0x78,0x01,0x30,0x1a,0x43,0x01,0x39,0xfa,0xd1,0x00,0xbe, diff --git a/contrib/loaders/erase_check/armv7m_0_erase_check.s b/contrib/loaders/erase_check/armv7m_0_erase_check.s deleted file mode 100644 index 6b1e92a85..000000000 --- a/contrib/loaders/erase_check/armv7m_0_erase_check.s +++ /dev/null @@ -1,45 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2014 by Jeff Ciesielski * - * jeffciesielski@gmail.com * - * * - * Based on the armv7m erase checker by: * - * Copyright (C) 2010 by Spencer Oliver * - * spen@spen-soft.co.uk * - * * - * 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. * - * * - ***************************************************************************/ - -/* - parameters: - r0 - address in - r1 - byte count - r2 - mask - result out -*/ - - .text - .syntax unified - .cpu cortex-m0 - .thumb - .thumb_func - - .align 2 - -loop: - ldrb r3, [r0] - adds r0, #1 - orrs r2, r2, r3 - subs r1, r1, #1 - bne loop -end: - bkpt #0 - - .end diff --git a/contrib/loaders/erase_check/armv7m_erase_check.inc b/contrib/loaders/erase_check/armv7m_erase_check.inc index 1fe25cd51..4ee96e19e 100644 --- a/contrib/loaders/erase_check/armv7m_erase_check.inc +++ b/contrib/loaders/erase_check/armv7m_erase_check.inc @@ -1,2 +1,4 @@ /* Autogenerated with ../../../src/helper/bin2char.sh */ -0x03,0x78,0x01,0x30,0x1a,0x40,0x01,0x39,0xfa,0xd1,0x00,0xbe, +0x02,0x68,0x12,0x42,0x0d,0xd0,0x43,0x68,0x1c,0x68,0x04,0x33,0x8c,0x42,0x05,0xd1, +0x01,0x3a,0xf9,0xd1,0x01,0x24,0x04,0x60,0x08,0x30,0xf1,0xe7,0x00,0x24,0xfa,0xe7, +0x00,0x00,0x00,0xbe, diff --git a/contrib/loaders/erase_check/armv7m_erase_check.s b/contrib/loaders/erase_check/armv7m_erase_check.s index 886e3e280..3303c8778 100644 --- a/contrib/loaders/erase_check/armv7m_erase_check.s +++ b/contrib/loaders/erase_check/armv7m_erase_check.s @@ -20,9 +20,8 @@ /* parameters: - r0 - address in - r1 - byte count - r2 - mask - result out + r0 - pointer to struct { uint32_t size_in_result_out, uint32_t addr } + r1 - value to check */ .text @@ -33,13 +32,42 @@ .align 2 -loop: - ldrb r3, [r0] - adds r0, #1 - ands r2, r2, r3 - subs r1, r1, #1 - bne loop -end: +BLOCK_SIZE_RESULT = 0 +BLOCK_ADDRESS = 4 +SIZEOF_STRUCT_BLOCK = 8 + +start: +block_loop: + ldr r2, [r0, #BLOCK_SIZE_RESULT] /* get size */ + tst r2, r2 + beq done + + ldr r3, [r0, #BLOCK_ADDRESS] /* get address */ + +word_loop: + ldr r4, [r3] /* read word */ + adds r3, #4 + + cmp r4, r1 + bne not_erased + + subs r2, #1 + bne word_loop + + movs r4, #1 /* block is erased */ +save_result: + str r4, [r0, #BLOCK_SIZE_RESULT] + adds r0, #SIZEOF_STRUCT_BLOCK + b block_loop + +not_erased: + movs r4, #0 + b save_result + +/* Avoid padding at .text segment end. Otherwise exit point check fails. */ + .skip ( . - start + 2) & 2, 0 + +done: bkpt #0 .end diff --git a/src/target/armv7m.c b/src/target/armv7m.c index 696f85cb2..7b7893f64 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -731,34 +731,23 @@ cleanup: return retval; } -/** Checks whether a memory region is erased. */ +/** Checks an array of memory regions whether they are erased. */ int armv7m_blank_check_memory(struct target *target, struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value) { struct working_area *erase_check_algorithm; - struct reg_param reg_params[3]; + struct working_area *erase_check_params; + struct reg_param reg_params[2]; struct armv7m_algorithm armv7m_info; - const uint8_t *code; - uint32_t code_size; int retval; + static bool timed_out; + static const uint8_t erase_check_code[] = { #include "../../contrib/loaders/erase_check/armv7m_erase_check.inc" }; - static const uint8_t zero_erase_check_code[] = { -#include "../../contrib/loaders/erase_check/armv7m_0_erase_check.inc" - }; - switch (erased_value) { - case 0x00: - code = zero_erase_check_code; - code_size = sizeof(zero_erase_check_code); - break; - case 0xff: - default: - code = erase_check_code; - code_size = sizeof(erase_check_code); - } + const uint32_t code_size = sizeof(erase_check_code); /* make sure we have a working area */ if (target_alloc_working_area(target, code_size, @@ -766,46 +755,113 @@ int armv7m_blank_check_memory(struct target *target, return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; retval = target_write_buffer(target, erase_check_algorithm->address, - code_size, code); + code_size, erase_check_code); if (retval != ERROR_OK) - goto cleanup; + goto cleanup1; + + /* prepare blocks array for algo */ + struct algo_block { + union { + uint32_t size; + uint32_t result; + }; + uint32_t address; + }; + + uint32_t avail = target_get_working_area_avail(target); + int blocks_to_check = avail / sizeof(struct algo_block) - 1; + if (num_blocks < blocks_to_check) + blocks_to_check = num_blocks; + + struct algo_block *params = malloc((blocks_to_check+1)*sizeof(struct algo_block)); + if (params == NULL) { + retval = ERROR_FAIL; + goto cleanup1; + } + + int i; + uint32_t total_size = 0; + for (i = 0; i < blocks_to_check; i++) { + total_size += blocks[i].size; + target_buffer_set_u32(target, (uint8_t *)&(params[i].size), + blocks[i].size / sizeof(uint32_t)); + target_buffer_set_u32(target, (uint8_t *)&(params[i].address), + blocks[i].address); + } + target_buffer_set_u32(target, (uint8_t *)&(params[blocks_to_check].size), 0); + + uint32_t param_size = (blocks_to_check + 1) * sizeof(struct algo_block); + if (target_alloc_working_area(target, param_size, + &erase_check_params) != ERROR_OK) { + retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + goto cleanup2; + } + + retval = target_write_buffer(target, erase_check_params->address, + param_size, (uint8_t *)params); + if (retval != ERROR_OK) + goto cleanup3; + + uint32_t erased_word = erased_value | (erased_value << 8) + | (erased_value << 16) | (erased_value << 24); + + LOG_DEBUG("Starting erase check of %d blocks, parameters@" + TARGET_ADDR_FMT, blocks_to_check, erase_check_params->address); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); - buf_set_u32(reg_params[0].value, 0, 32, blocks->address); + buf_set_u32(reg_params[0].value, 0, 32, erase_check_params->address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); - buf_set_u32(reg_params[1].value, 0, 32, blocks->size); + buf_set_u32(reg_params[1].value, 0, 32, erased_word); - init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); - buf_set_u32(reg_params[2].value, 0, 32, erased_value); + /* assume CPU clk at least 1 MHz */ + int timeout = (timed_out ? 30000 : 2000) + total_size * 3 / 1000; retval = target_run_algorithm(target, - 0, - NULL, - 3, - reg_params, - erase_check_algorithm->address, - erase_check_algorithm->address + (code_size - 2), - 10000, - &armv7m_info); + 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + erase_check_algorithm->address, + erase_check_algorithm->address + (code_size - 2), + timeout, + &armv7m_info); - if (retval == ERROR_OK) - blocks->result = buf_get_u32(reg_params[2].value, 0, 32); + timed_out = retval == ERROR_TARGET_TIMEOUT; + if (retval != ERROR_OK && !timed_out) + goto cleanup4; + retval = target_read_buffer(target, erase_check_params->address, + param_size, (uint8_t *)params); + if (retval != ERROR_OK) + goto cleanup4; + + for (i = 0; i < blocks_to_check; i++) { + uint32_t result = target_buffer_get_u32(target, + (uint8_t *)&(params[i].result)); + if (result != 0 && result != 1) + break; + + blocks[i].result = result; + } + if (i && timed_out) + LOG_INFO("Slow CPU clock: %d blocks checked, %d remain. Continuing...", i, num_blocks-i); + + retval = i; /* return number of blocks really checked */ + +cleanup4: destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); - destroy_reg_param(®_params[2]); -cleanup: +cleanup3: + target_free_working_area(target, erase_check_params); +cleanup2: + free(params); +cleanup1: target_free_working_area(target, erase_check_algorithm); - if (retval != ERROR_OK) - return retval; - - return 1; /* only one block checked */ + return retval; } int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found) From c8c20b7c0bfbc802faf46598ac585707be99d153 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sat, 10 Feb 2018 13:07:56 +0100 Subject: [PATCH 12/30] flash/nor: handle flash write alignment/padding in the infrastructure Most of flash drivers have to ensure proper flash write block alignment and padding. As there was no support for it in the flash infrastructure, each driver does it its own way. Sometimes this part of code is not properly tested and contains bugs. flash_write(_unlock) joins all image sections targeted to one flash bank using padded areas as a glue. This solves alignment problems on section boundaries but imposes other problems. Introduce new flash bank parameters write_start_alignment, write_end_alignment and minimal_write_gap. New flash drivers can just properly set these values instead of handling alignment by its own. Adapt infrastructure (namely flash_write_unlock(), handle_flash_fill_command() and handle_flash_write_bank_command()) to prepare write data padded to an alignment required by the flash bank. Rework flash_write_unlock() to discontinue write block when the gap between sections is bigger than minimum specified in minimal_write_gap. minimal_write_gap is set to one sector by default. Change-Id: I4368dd402dfaf51c193bcbf1332cffff092b239b Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4399 Tested-by: jenkins Reviewed-by: Andreas Bolsch --- src/flash/nor/core.c | 194 +++++++++++++++++++++++++++++++--------- src/flash/nor/core.h | 35 ++++++++ src/flash/nor/tcl.c | 208 ++++++++++++++++++++++++++----------------- 3 files changed, 314 insertions(+), 123 deletions(-) diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c index 707dcff18..f05c68b82 100644 --- a/src/flash/nor/core.c +++ b/src/flash/nor/core.c @@ -4,6 +4,7 @@ * Copyright (C) 2008 by Spencer Oliver * * Copyright (C) 2009 Zachary T Welch * * Copyright (C) 2010 by Antonio Borneo * + * Copyright (C) 2017-2018 Tomas Vanek * * * * 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 * @@ -600,6 +601,87 @@ static int compare_section(const void *a, const void *b) return -1; } +/** + * Get aligned start address of a flash write region + */ +target_addr_t flash_write_align_start(struct flash_bank *bank, target_addr_t addr) +{ + if (addr < bank->base || addr >= bank->base + bank->size + || bank->write_start_alignment <= 1) + return addr; + + if (bank->write_start_alignment == FLASH_WRITE_ALIGN_SECTOR) { + uint32_t offset = addr - bank->base; + uint32_t aligned = 0; + int sect; + for (sect = 0; sect < bank->num_sectors; sect++) { + if (bank->sectors[sect].offset > offset) + break; + + aligned = bank->sectors[sect].offset; + } + return bank->base + aligned; + } + + return addr & ~(bank->write_start_alignment - 1); +} + +/** + * Get aligned end address of a flash write region + */ +target_addr_t flash_write_align_end(struct flash_bank *bank, target_addr_t addr) +{ + if (addr < bank->base || addr >= bank->base + bank->size + || bank->write_end_alignment <= 1) + return addr; + + if (bank->write_end_alignment == FLASH_WRITE_ALIGN_SECTOR) { + uint32_t offset = addr - bank->base; + uint32_t aligned = 0; + int sect; + for (sect = 0; sect < bank->num_sectors; sect++) { + aligned = bank->sectors[sect].offset + bank->sectors[sect].size - 1; + if (aligned >= offset) + break; + } + return bank->base + aligned; + } + + return addr | (bank->write_end_alignment - 1); +} + +/** + * Check if gap between sections is bigger than minimum required to discontinue flash write + */ +static bool flash_write_check_gap(struct flash_bank *bank, + target_addr_t addr1, target_addr_t addr2) +{ + if (bank->minimal_write_gap == FLASH_WRITE_CONTINUOUS + || addr1 < bank->base || addr1 >= bank->base + bank->size + || addr2 < bank->base || addr2 >= bank->base + bank->size) + return false; + + if (bank->minimal_write_gap == FLASH_WRITE_GAP_SECTOR) { + int sect; + uint32_t offset1 = addr1 - bank->base; + /* find the sector following the one containing addr1 */ + for (sect = 0; sect < bank->num_sectors; sect++) { + if (bank->sectors[sect].offset > offset1) + break; + } + if (sect >= bank->num_sectors) + return false; + + uint32_t offset2 = addr2 - bank->base; + return bank->sectors[sect].offset + bank->sectors[sect].size <= offset2; + } + + target_addr_t aligned1 = flash_write_align_end(bank, addr1); + target_addr_t aligned2 = flash_write_align_start(bank, addr2); + return aligned1 + bank->minimal_write_gap < aligned2; +} + + int flash_write_unlock(struct target *target, struct image *image, uint32_t *written, int erase, bool unlock) { @@ -639,7 +721,7 @@ int flash_write_unlock(struct target *target, struct image *image, /* loop until we reach end of the image */ while (section < image->num_sections) { - uint32_t buffer_size; + uint32_t buffer_idx; uint8_t *buffer; int section_last; target_addr_t run_address = sections[section]->base_address + section_offset; @@ -676,43 +758,37 @@ int flash_write_unlock(struct target *target, struct image *image, break; } - /* FIXME This needlessly touches sectors BETWEEN the - * sections it's writing. Without auto erase, it just - * writes ones. That WILL INVALIDATE data in cases - * like Stellaris Tempest chips, corrupting internal - * ECC codes; and at least FreeScale suggests issues - * with that approach (in HC11 documentation). - * - * With auto erase enabled, data in those sectors will - * be needlessly destroyed; and some of the limited - * number of flash erase cycles will be wasted... - * - * In both cases, the extra writes slow things down. - */ - /* if we have multiple sections within our image, * flash programming could fail due to alignment issues * attempt to rebuild a consecutive buffer for the flash loader */ target_addr_t run_next_addr = run_address + run_size; - if (sections[section_last + 1]->base_address < run_next_addr) { + target_addr_t next_section_base = sections[section_last + 1]->base_address; + if (next_section_base < run_next_addr) { LOG_ERROR("Section at " TARGET_ADDR_FMT " overlaps section ending at " TARGET_ADDR_FMT, - sections[section_last + 1]->base_address, - run_next_addr); + next_section_base, run_next_addr); LOG_ERROR("Flash write aborted."); retval = ERROR_FAIL; goto done; } - pad_bytes = sections[section_last + 1]->base_address - run_next_addr; - padding[section_last] = pad_bytes; - run_size += sections[++section_last]->size; - run_size += pad_bytes; - + pad_bytes = next_section_base - run_next_addr; + if (pad_bytes) { + if (flash_write_check_gap(c, run_next_addr - 1, next_section_base)) { + LOG_INFO("Flash write discontinued at " TARGET_ADDR_FMT + ", next section at " TARGET_ADDR_FMT, + run_next_addr, next_section_base); + break; + } + } if (pad_bytes > 0) - LOG_INFO("Padding image section %d with %d bytes", - section_last-1, - pad_bytes); + LOG_INFO("Padding image section %d at " TARGET_ADDR_FMT + " with %d bytes", + section_last, run_next_addr, pad_bytes); + + padding[section_last] = pad_bytes; + run_size += pad_bytes; + run_size += sections[++section_last]->size; } if (run_address + run_size - 1 > c->base + c->size - 1) { @@ -725,10 +801,38 @@ int flash_write_unlock(struct target *target, struct image *image, assert(run_size > 0); } - /* If we're applying any sector automagic, then pad this - * (maybe-combined) segment to the end of its last sector. - */ - if (unlock || erase) { + uint32_t padding_at_start = 0; + if (c->write_start_alignment || c->write_end_alignment) { + /* align write region according to bank requirements */ + target_addr_t aligned_start = flash_write_align_start(c, run_address); + padding_at_start = run_address - aligned_start; + if (padding_at_start > 0) { + LOG_WARNING("Section start address " TARGET_ADDR_FMT + " breaks the required alignment of flash bank %s", + run_address, c->name); + LOG_WARNING("Padding %d bytes from " TARGET_ADDR_FMT, + padding_at_start, aligned_start); + + run_address -= padding_at_start; + run_size += padding_at_start; + } + + target_addr_t run_end = run_address + run_size - 1; + target_addr_t aligned_end = flash_write_align_end(c, run_end); + pad_bytes = aligned_end - run_end; + if (pad_bytes > 0) { + LOG_INFO("Padding image section %d at " TARGET_ADDR_FMT + " with %d bytes (bank write end alignment)", + section_last, run_end + 1, pad_bytes); + + padding[section_last] += pad_bytes; + run_size += pad_bytes; + } + + } else if (unlock || erase) { + /* If we're applying any sector automagic, then pad this + * (maybe-combined) segment to the end of its last sector. + */ int sector; uint32_t offset_start = run_address - c->base; uint32_t offset_end = offset_start + run_size; @@ -753,13 +857,17 @@ int flash_write_unlock(struct target *target, struct image *image, retval = ERROR_FAIL; goto done; } - buffer_size = 0; + + if (padding_at_start) + memset(buffer, c->default_padded_value, padding_at_start); + + buffer_idx = padding_at_start; /* read sections to the buffer */ - while (buffer_size < run_size) { + while (buffer_idx < run_size) { size_t size_read; - size_read = run_size - buffer_size; + size_read = run_size - buffer_idx; if (size_read > sections[section]->size - section_offset) size_read = sections[section]->size - section_offset; @@ -772,23 +880,25 @@ int flash_write_unlock(struct target *target, struct image *image, int t_section_num = diff / sizeof(struct imagesection); LOG_DEBUG("image_read_section: section = %d, t_section_num = %d, " - "section_offset = %d, buffer_size = %d, size_read = %d", - (int)section, (int)t_section_num, (int)section_offset, - (int)buffer_size, (int)size_read); + "section_offset = %"PRIu32", buffer_idx = %"PRIu32", size_read = %zu", + section, t_section_num, section_offset, + buffer_idx, size_read); retval = image_read_section(image, t_section_num, section_offset, - size_read, buffer + buffer_size, &size_read); + size_read, buffer + buffer_idx, &size_read); if (retval != ERROR_OK || size_read == 0) { free(buffer); goto done; } - /* see if we need to pad the section */ - while (padding[section]--) - (buffer + buffer_size)[size_read++] = c->default_padded_value; - - buffer_size += size_read; + buffer_idx += size_read; section_offset += size_read; + /* see if we need to pad the section */ + if (padding[section]) { + memset(buffer + buffer_idx, c->default_padded_value, padding[section]); + buffer_idx += padding[section]; + } + if (section_offset >= sections[section]->size) { section++; section_offset = 0; diff --git a/src/flash/nor/core.h b/src/flash/nor/core.h index 1bfe1ab97..67de94e70 100644 --- a/src/flash/nor/core.h +++ b/src/flash/nor/core.h @@ -65,6 +65,13 @@ struct flash_sector { int is_protected; }; +/** Special value for write_start_alignment and write_end_alignment field */ +#define FLASH_WRITE_ALIGN_SECTOR UINT32_MAX + +/** Special values for minimal_write_gap field */ +#define FLASH_WRITE_CONTINUOUS 0 +#define FLASH_WRITE_GAP_SECTOR UINT32_MAX + /** * Provides details of a flash bank, available either on-chip or through * a major interface. @@ -97,6 +104,18 @@ struct flash_bank { * erased value. Defaults to 0xFF. */ uint8_t default_padded_value; + /** Required alignment of flash write start address. + * Default 0, no alignment. Can be any power of two or FLASH_WRITE_ALIGN_SECTOR */ + uint32_t write_start_alignment; + /** Required alignment of flash write end address. + * Default 0, no alignment. Can be any power of two or FLASH_WRITE_ALIGN_SECTOR */ + uint32_t write_end_alignment; + /** Minimal gap between sections to discontinue flash write + * Default FLASH_WRITE_GAP_SECTOR splits the write if one or more untouched + * sectors in between. + * Can be size in bytes or FLASH_WRITE_CONTINUOUS */ + uint32_t minimal_write_gap; + /** * The number of sectors on this chip. This value will * be set intially to 0, and the flash driver must set this to @@ -135,6 +154,22 @@ int flash_erase_address_range(struct target *target, int flash_unlock_address_range(struct target *target, uint32_t addr, uint32_t length); +/** + * Align start address of a flash write region according to bank requirements. + * @param bank Pointer to bank descriptor structure + * @param addr Address to align + * @returns Aligned address +*/ +target_addr_t flash_write_align_start(struct flash_bank *bank, target_addr_t addr); +/** + * Align end address of a flash write region according to bank requirements. + * Note: Use address of the last byte to write, not the next after the region. + * @param bank Pointer to bank descriptor structure + * @param addr Address to align (address of the last byte to write) + * @returns Aligned address (address of the last byte of padded region) +*/ +target_addr_t flash_write_align_end(struct flash_bank *bank, target_addr_t addr); + /** * Writes @a image into the @a target flash. The @a written parameter * will contain the diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index e5e280111..34681db14 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -3,6 +3,7 @@ * Copyright (C) 2007,2008 Øyvind Harboe * * Copyright (C) 2008 by Spencer Oliver * * Copyright (C) 2009 Zachary T Welch * + * Copyright (C) 2017-2018 Tomas Vanek * * * * 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 * @@ -460,42 +461,29 @@ COMMAND_HANDLER(handle_flash_write_image_command) COMMAND_HANDLER(handle_flash_fill_command) { - int err = ERROR_OK; - uint32_t address; + target_addr_t address; uint32_t pattern; uint32_t count; - uint32_t wrote = 0; - uint32_t cur_size = 0; - uint32_t chunk_count; struct target *target = get_current_target(CMD_CTX); unsigned i; uint32_t wordsize; - int retval = ERROR_OK; + int retval; - static size_t const chunksize = 1024; - uint8_t *chunk = NULL, *readback = NULL; - - if (CMD_ARGC != 3) { - retval = ERROR_COMMAND_SYNTAX_ERROR; - goto done; - } + if (CMD_ARGC != 3) + return ERROR_COMMAND_SYNTAX_ERROR; +#if BUILD_TARGET64 + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], address); +#else COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); +#endif COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], pattern); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], count); - chunk = malloc(chunksize); - if (chunk == NULL) - return ERROR_FAIL; - - readback = malloc(chunksize); - if (readback == NULL) { - free(chunk); - return ERROR_FAIL; - } - - if (count == 0) - goto done; + struct flash_bank *bank; + retval = get_flash_bank_by_addr(target, address, true, &bank); + if (retval != ERROR_OK) + return retval; switch (CMD_NAME[4]) { case 'w': @@ -508,73 +496,109 @@ COMMAND_HANDLER(handle_flash_fill_command) wordsize = 1; break; default: - retval = ERROR_COMMAND_SYNTAX_ERROR; - goto done; + return ERROR_COMMAND_SYNTAX_ERROR; } - chunk_count = MIN(count, (chunksize / wordsize)); + if (count == 0) + return ERROR_OK; + + if (address + count >= bank->base + bank->size) { + LOG_ERROR("Cannot cross flash bank borders"); + return ERROR_FAIL; + } + + uint32_t size_bytes = count * wordsize; + target_addr_t aligned_start = flash_write_align_start(bank, address); + target_addr_t end_addr = address + size_bytes - 1; + target_addr_t aligned_end = flash_write_align_end(bank, end_addr); + uint32_t aligned_size = aligned_end + 1 - aligned_start; + uint32_t padding_at_start = address - aligned_start; + uint32_t padding_at_end = aligned_end - end_addr; + + uint8_t *buffer = malloc(aligned_size); + if (buffer == NULL) + return ERROR_FAIL; + + if (padding_at_start) { + memset(buffer, bank->default_padded_value, padding_at_start); + LOG_WARNING("Start address " TARGET_ADDR_FMT + " breaks the required alignment of flash bank %s", + address, bank->name); + LOG_WARNING("Padding %" PRId32 " bytes from " TARGET_ADDR_FMT, + padding_at_start, aligned_start); + } + + uint8_t *ptr = buffer + padding_at_start; + switch (wordsize) { case 4: - for (i = 0; i < chunk_count; i++) - target_buffer_set_u32(target, chunk + i * wordsize, pattern); + for (i = 0; i < count; i++, ptr += wordsize) + target_buffer_set_u32(target, ptr, pattern); break; case 2: - for (i = 0; i < chunk_count; i++) - target_buffer_set_u16(target, chunk + i * wordsize, pattern); + for (i = 0; i < count; i++, ptr += wordsize) + target_buffer_set_u16(target, ptr, pattern); break; case 1: - memset(chunk, pattern, chunk_count); + memset(ptr, pattern, count); + ptr += count; break; default: LOG_ERROR("BUG: can't happen"); exit(-1); } + if (padding_at_end) { + memset(ptr, bank->default_padded_value, padding_at_end); + LOG_INFO("Padding at " TARGET_ADDR_FMT " with %" PRId32 + " bytes (bank write end alignment)", + end_addr + 1, padding_at_end); + } + struct duration bench; duration_start(&bench); - for (wrote = 0; wrote < (count*wordsize); wrote += cur_size) { - struct flash_bank *bank; + retval = flash_driver_write(bank, buffer, aligned_start - bank->base, aligned_size); + if (retval != ERROR_OK) + goto done; - retval = get_flash_bank_by_addr(target, address, true, &bank); - if (retval != ERROR_OK) - goto done; + retval = flash_driver_read(bank, buffer, address - bank->base, size_bytes); + if (retval != ERROR_OK) + goto done; - cur_size = MIN((count * wordsize - wrote), chunksize); - err = flash_driver_write(bank, chunk, address - bank->base + wrote, cur_size); - if (err != ERROR_OK) { - retval = err; + for (i = 0, ptr = buffer; i < count; i++) { + uint32_t readback = 0; + + switch (wordsize) { + case 4: + readback = target_buffer_get_u32(target, ptr); + break; + case 2: + readback = target_buffer_get_u16(target, ptr); + break; + case 1: + readback = *ptr; + break; + } + if (readback != pattern) { + LOG_ERROR( + "Verification error address " TARGET_ADDR_FMT + ", read back 0x%02" PRIx32 ", expected 0x%02" PRIx32, + address + i * wordsize, readback, pattern); + retval = ERROR_FAIL; goto done; } - - err = flash_driver_read(bank, readback, address - bank->base + wrote, cur_size); - if (err != ERROR_OK) { - retval = err; - goto done; - } - - for (i = 0; i < cur_size; i++) { - if (readback[i] != chunk[i]) { - LOG_ERROR( - "Verification error address 0x%08" PRIx32 ", read back 0x%02x, expected 0x%02x", - address + wrote + i, - readback[i], - chunk[i]); - retval = ERROR_FAIL; - goto done; - } - } + ptr += wordsize; } if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { - command_print(CMD_CTX, "wrote %" PRIu32 " bytes to 0x%8.8" PRIx32 - " in %fs (%0.3f KiB/s)", wrote, address, - duration_elapsed(&bench), duration_kbps(&bench, wrote)); + command_print(CMD_CTX, "wrote %" PRIu32 " bytes to " TARGET_ADDR_FMT + " in %fs (%0.3f KiB/s)", size_bytes, address, + duration_elapsed(&bench), duration_kbps(&bench, size_bytes)); } done: - free(readback); - free(chunk); + free(buffer); return retval; } @@ -592,8 +616,8 @@ COMMAND_HANDLER(handle_flash_write_bank_command) struct duration bench; duration_start(&bench); - struct flash_bank *p; - int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; @@ -602,7 +626,7 @@ COMMAND_HANDLER(handle_flash_write_bank_command) if (CMD_ARGC > 2) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset); - if (offset > p->size) { + if (offset > bank->size) { LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank", offset); return ERROR_COMMAND_ARGUMENT_INVALID; @@ -618,7 +642,7 @@ COMMAND_HANDLER(handle_flash_write_bank_command) return retval; } - length = MIN(filesize, p->size - offset); + length = MIN(filesize, bank->size - offset); if (!length) { LOG_INFO("Nothing to write to flash bank"); @@ -630,14 +654,33 @@ COMMAND_HANDLER(handle_flash_write_bank_command) LOG_INFO("File content exceeds flash bank size. Only writing the " "first %zu bytes of the file", length); - buffer = malloc(length); + target_addr_t start_addr = bank->base + offset; + target_addr_t aligned_start = flash_write_align_start(bank, start_addr); + target_addr_t end_addr = start_addr + length - 1; + target_addr_t aligned_end = flash_write_align_end(bank, end_addr); + uint32_t aligned_size = aligned_end + 1 - aligned_start; + uint32_t padding_at_start = start_addr - aligned_start; + uint32_t padding_at_end = aligned_end - end_addr; + + buffer = malloc(aligned_size); if (buffer == NULL) { fileio_close(fileio); LOG_ERROR("Out of memory"); return ERROR_FAIL; } + + if (padding_at_start) { + memset(buffer, bank->default_padded_value, padding_at_start); + LOG_WARNING("Start offset 0x%08" PRIx32 + " breaks the required alignment of flash bank %s", + offset, bank->name); + LOG_WARNING("Padding %" PRId32 " bytes from " TARGET_ADDR_FMT, + padding_at_start, aligned_start); + } + + uint8_t *ptr = buffer + padding_at_start; size_t buf_cnt; - if (fileio_read(fileio, length, buffer, &buf_cnt) != ERROR_OK) { + if (fileio_read(fileio, length, ptr, &buf_cnt) != ERROR_OK) { free(buffer); fileio_close(fileio); return ERROR_FAIL; @@ -649,15 +692,23 @@ COMMAND_HANDLER(handle_flash_write_bank_command) return ERROR_FAIL; } - retval = flash_driver_write(p, buffer, offset, length); + ptr += length; + + if (padding_at_end) { + memset(ptr, bank->default_padded_value, padding_at_end); + LOG_INFO("Padding at " TARGET_ADDR_FMT " with %" PRId32 + " bytes (bank write end alignment)", + end_addr + 1, padding_at_end); + } + + retval = flash_driver_write(bank, buffer, aligned_start - bank->base, aligned_size); free(buffer); - buffer = NULL; if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD_CTX, "wrote %zu bytes from file %s to flash bank %u" " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)", - length, CMD_ARGV[1], p->bank_number, offset, + length, CMD_ARGV[1], bank->bank_number, offset, duration_elapsed(&bench), duration_kbps(&bench, length)); } @@ -1071,21 +1122,16 @@ COMMAND_HANDLER(handle_flash_bank_command) } } - struct flash_bank *c = malloc(sizeof(*c)); + struct flash_bank *c = calloc(1, sizeof(*c)); c->name = strdup(bank_name); c->target = target; c->driver = driver; - c->driver_priv = NULL; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], c->base); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], c->size); COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], c->chip_width); COMMAND_PARSE_NUMBER(int, CMD_ARGV[4], c->bus_width); c->default_padded_value = c->erased_value = 0xff; - c->num_sectors = 0; - c->sectors = NULL; - c->num_prot_blocks = 0; - c->prot_blocks = NULL; - c->next = NULL; + c->minimal_write_gap = FLASH_WRITE_GAP_SECTOR; int retval; retval = CALL_COMMAND_HANDLER(driver->flash_bank_command, c); From 66d924f787eb60e4f7a7d24c066d96aa68c73a11 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 15 Feb 2018 02:33:07 +0100 Subject: [PATCH 13/30] flash/nor/kinetis: implement flash bank deallocation Change-Id: I8ef80eae646d3b3eb7f6dd42067f8516adc5abef Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4415 Tested-by: jenkins --- src/flash/nor/kinetis.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index 48a5de46a..4d665d339 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -915,6 +915,22 @@ FLASH_BANK_COMMAND_HANDLER(kinetis_flash_bank_command) } +static void kinetis_free_driver_priv(struct flash_bank *bank) +{ + struct kinetis_flash_bank *k_bank = bank->driver_priv; + if (k_bank == NULL) + return; + + struct kinetis_chip *k_chip = k_bank->k_chip; + if (k_chip == NULL) + return; + + k_chip->num_banks--; + if (k_chip->num_banks == 0) + free(k_chip); +} + + static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) { unsigned bank_idx; @@ -939,7 +955,7 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) if (k_chip->num_pflash_blocks > 1) { /* rename first bank if numbering is needed */ snprintf(name, sizeof(name), "%s.pflash0", base_name); - free((void *)bank->name); + free(bank->name); bank->name = strdup(name); } } @@ -3132,4 +3148,5 @@ struct flash_driver kinetis_flash = { .erase_check = kinetis_blank_check, .protect_check = kinetis_protect_check, .info = kinetis_info, + .free_driver_priv = kinetis_free_driver_priv, }; From a9fb0d07f07f141f9a1c08c21341b3188b21fbe2 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 15 Feb 2018 10:18:37 +0100 Subject: [PATCH 14/30] flash/nor/at91sam: implement flash bank deallocation for SAM series Microchip (former Atmel) SAM drivers allocate a struct per chip. at91sam3, at91sam34: Deallocate all chip structs from the list at once, on the first bank deallocation. at91samd and at91sam4l drivers do not handle more than one bank. Convert them to simple driver_priv allocation and use default_flash_free_driver_priv(). Change-Id: I49d7200f38a4568c7e12f306c27d1b1b72646736 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4416 Tested-by: jenkins --- src/flash/nor/at91sam3.c | 17 ++++++++++++++++ src/flash/nor/at91sam4.c | 17 ++++++++++++++++ src/flash/nor/at91sam4l.c | 41 +++++++++++++-------------------------- src/flash/nor/at91samd.c | 39 +++++++++++++------------------------ 4 files changed, 61 insertions(+), 53 deletions(-) diff --git a/src/flash/nor/at91sam3.c b/src/flash/nor/at91sam3.c index 1536378df..d80b6fe6e 100644 --- a/src/flash/nor/at91sam3.c +++ b/src/flash/nor/at91sam3.c @@ -3117,6 +3117,22 @@ FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command) return ERROR_OK; } +/** + * Remove all chips from the internal list without distingushing which one + * is owned by this bank. This simplification works only for one shot + * deallocation like current flash_free_all_banks() + */ +void sam3_free_driver_priv(struct flash_bank *bank) +{ + struct sam3_chip *chip = all_sam3_chips; + while (chip) { + struct sam3_chip *next = chip->next; + free(chip); + chip = next; + } + all_sam3_chips = NULL; +} + static int sam3_GetDetails(struct sam3_bank_private *pPrivate) { const struct sam3_chip_details *pDetails; @@ -3771,4 +3787,5 @@ struct flash_driver at91sam3_flash = { .auto_probe = sam3_auto_probe, .erase_check = sam3_erase_check, .protect_check = sam3_protect_check, + .free_driver_priv = sam3_free_driver_priv, }; diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c index d101c9b4c..04752169f 100644 --- a/src/flash/nor/at91sam4.c +++ b/src/flash/nor/at91sam4.c @@ -2514,6 +2514,22 @@ FLASH_BANK_COMMAND_HANDLER(sam4_flash_bank_command) return ERROR_OK; } +/** + * Remove all chips from the internal list without distingushing which one + * is owned by this bank. This simplification works only for one shot + * deallocation like current flash_free_all_banks() + */ +static void sam4_free_driver_priv(struct flash_bank *bank) +{ + struct sam4_chip *chip = all_sam4_chips; + while (chip) { + struct sam4_chip *next = chip->next; + free(chip); + chip = next; + } + all_sam4_chips = NULL; +} + static int sam4_GetDetails(struct sam4_bank_private *pPrivate) { const struct sam4_chip_details *pDetails; @@ -3194,4 +3210,5 @@ struct flash_driver at91sam4_flash = { .auto_probe = sam4_auto_probe, .erase_check = default_flash_blank_check, .protect_check = sam4_protect_check, + .free_driver_priv = sam4_free_driver_priv, }; diff --git a/src/flash/nor/at91sam4l.c b/src/flash/nor/at91sam4l.c index 0a605d5d7..794ccbb01 100644 --- a/src/flash/nor/at91sam4l.c +++ b/src/flash/nor/at91sam4l.c @@ -129,10 +129,8 @@ struct sam4l_info { bool probed; struct target *target; - struct sam4l_info *next; }; -static struct sam4l_info *sam4l_chips; static int sam4l_flash_wait_until_ready(struct target *target) { @@ -204,30 +202,6 @@ static int sam4l_flash_command(struct target *target, uint8_t cmd, int page) FLASH_BANK_COMMAND_HANDLER(sam4l_flash_bank_command) { - struct sam4l_info *chip = sam4l_chips; - - while (chip) { - if (chip->target == bank->target) - break; - chip = chip->next; - } - - if (!chip) { - /* Create a new chip */ - chip = calloc(1, sizeof(*chip)); - if (!chip) - return ERROR_FAIL; - - chip->target = bank->target; - chip->probed = false; - - bank->driver_priv = chip; - - /* Insert it into the chips list (at head) */ - chip->next = sam4l_chips; - sam4l_chips = chip; - } - if (bank->base != SAM4L_FLASH) { LOG_ERROR("Address 0x%08" PRIx32 " invalid bank address (try 0x%08" PRIx32 "[at91sam4l series] )", @@ -235,6 +209,18 @@ FLASH_BANK_COMMAND_HANDLER(sam4l_flash_bank_command) return ERROR_FAIL; } + struct sam4l_info *chip; + chip = calloc(1, sizeof(*chip)); + if (!chip) { + LOG_ERROR("No memory for flash bank chip info"); + return ERROR_FAIL; + } + + chip->target = bank->target; + chip->probed = false; + + bank->driver_priv = chip; + return ERROR_OK; } @@ -396,7 +382,7 @@ static int sam4l_protect_check(struct flash_bank *bank) static int sam4l_protect(struct flash_bank *bank, int set, int first, int last) { - struct sam4l_info *chip = sam4l_chips; + struct sam4l_info *chip = (struct sam4l_info *)bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -709,4 +695,5 @@ struct flash_driver at91sam4l_flash = { .auto_probe = sam4l_probe, .erase_check = default_flash_blank_check, .protect_check = sam4l_protect_check, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index 64716d96f..8553ee8f9 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -304,10 +304,8 @@ struct samd_info { bool probed; struct target *target; - struct samd_info *next; }; -static struct samd_info *samd_chips; /** * Gives the family structure to specific device id. @@ -876,30 +874,6 @@ free_pb: FLASH_BANK_COMMAND_HANDLER(samd_flash_bank_command) { - struct samd_info *chip = samd_chips; - - while (chip) { - if (chip->target == bank->target) - break; - chip = chip->next; - } - - if (!chip) { - /* Create a new chip */ - chip = calloc(1, sizeof(*chip)); - if (!chip) - return ERROR_FAIL; - - chip->target = bank->target; - chip->probed = false; - - bank->driver_priv = chip; - - /* Insert it into the chips list (at head) */ - chip->next = samd_chips; - samd_chips = chip; - } - if (bank->base != SAMD_FLASH) { LOG_ERROR("Address 0x%08" PRIx32 " invalid bank address (try 0x%08" PRIx32 "[at91samd series] )", @@ -907,6 +881,18 @@ FLASH_BANK_COMMAND_HANDLER(samd_flash_bank_command) return ERROR_FAIL; } + struct samd_info *chip; + chip = calloc(1, sizeof(*chip)); + if (!chip) { + LOG_ERROR("No memory for flash bank chip info"); + return ERROR_FAIL; + } + + chip->target = bank->target; + chip->probed = false; + + bank->driver_priv = chip; + return ERROR_OK; } @@ -1281,4 +1267,5 @@ struct flash_driver at91samd_flash = { .auto_probe = samd_probe, .erase_check = default_flash_blank_check, .protect_check = samd_protect_check, + .free_driver_priv = default_flash_free_driver_priv, }; From 5c035e322f20a99679f626bb4b99c047b46d722f Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Wed, 20 Sep 2017 14:09:28 +0200 Subject: [PATCH 15/30] tcl/board: add board configuration for NXP IMX7SABRE configuration also contains a reset-init procedure that disables the watchdog and initilizes the boards DDR memory so that you can upload baremetal (e.g. boot loader) code into DDR and start it from there. Change-Id: I4d2311b3708a5fcb5174a3447f34ae3904de7243 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4227 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/board/nxp_imx7sabre.cfg | 114 ++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 tcl/board/nxp_imx7sabre.cfg diff --git a/tcl/board/nxp_imx7sabre.cfg b/tcl/board/nxp_imx7sabre.cfg new file mode 100644 index 000000000..25b7b8781 --- /dev/null +++ b/tcl/board/nxp_imx7sabre.cfg @@ -0,0 +1,114 @@ +# NXP IMX7SABRE board +# use on-board JTAG header +transport select jtag + +# set a safe speed, can be overridden +adapter_khz 1000 + +# reset configuration has TRST and SRST support +reset_config trst_and_srst srst_push_pull +# need at least 100ms delay after SRST release for JTAG +adapter_nsrst_delay 100 + +# source the target file +source [find target/imx7.cfg] +# import mrw proc +source [find mem_helper.tcl] + +# function to disable the on-chip watchdog +proc imx7_disable_wdog { } { + # echo "disable watchdog power-down counter" + mwh phys 0x30280008 0x00 +} + +proc imx7_uart_dbgconf { } { + # disable response to debug_req signal for uart1 + mww phys 0x308600b4 0x0a60 +} + +proc check_bits_set_32 { addr mask } { + while { [expr [mrw $addr] & $mask == 0] } { } +} + +proc apply_dcd { } { + # echo "apply dcd" + + mww phys 0x30340004 0x4F400005 + # Clear then set bit30 to ensure exit from DDR retention + mww phys 0x30360388 0x40000000 + mww phys 0x30360384 0x40000000 + + mww phys 0x30391000 0x00000002 + mww phys 0x307a0000 0x01040001 + mww phys 0x307a01a0 0x80400003 + mww phys 0x307a01a4 0x00100020 + mww phys 0x307a01a8 0x80100004 + mww phys 0x307a0064 0x00400046 + mww phys 0x307a0490 0x00000001 + mww phys 0x307a00d0 0x00020083 + mww phys 0x307a00d4 0x00690000 + mww phys 0x307a00dc 0x09300004 + mww phys 0x307a00e0 0x04080000 + mww phys 0x307a00e4 0x00100004 + mww phys 0x307a00f4 0x0000033f + mww phys 0x307a0100 0x09081109 + mww phys 0x307a0104 0x0007020d + mww phys 0x307a0108 0x03040407 + mww phys 0x307a010c 0x00002006 + mww phys 0x307a0110 0x04020205 + mww phys 0x307a0114 0x03030202 + mww phys 0x307a0120 0x00000803 + mww phys 0x307a0180 0x00800020 + mww phys 0x307a0184 0x02000100 + mww phys 0x307a0190 0x02098204 + mww phys 0x307a0194 0x00030303 + mww phys 0x307a0200 0x00000016 + mww phys 0x307a0204 0x00171717 + mww phys 0x307a0214 0x04040404 + mww phys 0x307a0218 0x0f040404 + mww phys 0x307a0240 0x06000604 + mww phys 0x307a0244 0x00000001 + mww phys 0x30391000 0x00000000 + mww phys 0x30790000 0x17420f40 + mww phys 0x30790004 0x10210100 + mww phys 0x30790010 0x00060807 + mww phys 0x307900b0 0x1010007e + mww phys 0x3079009c 0x00000d6e + mww phys 0x30790020 0x08080808 + mww phys 0x30790030 0x08080808 + mww phys 0x30790050 0x01000010 + mww phys 0x30790050 0x00000010 + + mww phys 0x307900c0 0x0e407304 + mww phys 0x307900c0 0x0e447304 + mww phys 0x307900c0 0x0e447306 + + check_bits_set_32 0x307900c4 0x1 + + mww phys 0x307900c0 0x0e447304 + mww phys 0x307900c0 0x0e407304 + + + mww phys 0x30384130 0x00000000 + mww phys 0x30340020 0x00000178 + mww phys 0x30384130 0x00000002 + mww phys 0x30790018 0x0000000f + + check_bits_set_32 0x307a0004 0x1 +} + +# disable internal reset-assert handling to +# allow reset-init to work +$_TARGETNAME.0 configure -event reset-assert "" +$_TARGETNAME.1 configure -event reset-assert "" +$_TARGETNAME_2 configure -event reset-assert "" + +$_TARGETNAME.0 configure -event reset-init { + global _CHIPNAME + imx7_disable_wdog + imx7_uart_dbgconf + apply_dcd + $_CHIPNAME.dap memaccess 0 +} + +target smp $_TARGETNAME.0 $_TARGETNAME.1 From c0f81fbee745e34d04d490df0b26d8e443d90c0e Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Thu, 14 Dec 2017 09:38:46 +0100 Subject: [PATCH 16/30] target: add configuration for NXP MC-IMX8M-EVK includes target configuration for i.MX8M SoC family, board file needs to set up CHIPNAME and CHIPCORES to match the actual hardware configuration Change-Id: Ieb6d89cab2477a58f85d0ef9cd242710950191c0 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4434 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/board/nxp_mcimx8m-evk.cfg | 22 ++++++++++++++ tcl/target/imx8m.cfg | 55 +++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 tcl/board/nxp_mcimx8m-evk.cfg create mode 100644 tcl/target/imx8m.cfg diff --git a/tcl/board/nxp_mcimx8m-evk.cfg b/tcl/board/nxp_mcimx8m-evk.cfg new file mode 100644 index 000000000..e2d63ce7c --- /dev/null +++ b/tcl/board/nxp_mcimx8m-evk.cfg @@ -0,0 +1,22 @@ +# +# configuration file for NXP MC-IMX8M-EVK +# + +# only JTAG supported +transport select jtag + +# set a safe JTAG clock speed, can be overridden +adapter_khz 1000 + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter_nsrst_delay 70 + +# board has an i.MX8MQ with 4 Cortex-A53 cores +set CHIPNAME imx8mq +set CHIPCORES 4 + +# source SoC configuration +source [find target/imx8m.cfg] diff --git a/tcl/target/imx8m.cfg b/tcl/target/imx8m.cfg new file mode 100644 index 000000000..33149540a --- /dev/null +++ b/tcl/target/imx8m.cfg @@ -0,0 +1,55 @@ +# +# configuration file for NXP i.MX8M family of SoCs +# +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME imx8m +} + +if { [info exists CHIPCORES] } { + set _cores $CHIPCORES +} else { + set _cores 1 +} + +# CoreSight Debug Access Port +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba00477 +} + +# the DAP tap +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ + -expected-id $_DAP_TAPID + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +set _TARGETNAME $_CHIPNAME.a53 +set _CTINAME $_CHIPNAME.cti + +set DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} +set CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} + +for { set _core 0 } { $_core < $_cores } { incr _core } { + + cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 \ + -ctibase [lindex $CTIBASE $_core] + + set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ + -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core" + + if { $_core != 0 } { + # non-boot core examination may fail + set _command "$_command -defer-examine" + set _smp_command "$_smp_command $_TARGETNAME.$_core" + } else { + set _smp_command "target smp $_TARGETNAME.$_core" + } + + eval $_command +} + +eval $_smp_command +targets $_TARGETNAME.0 From 09076d10dd553dc63f08e74aedb1b6aa030857f9 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Mon, 26 Mar 2018 09:45:46 +0200 Subject: [PATCH 17/30] armv8: valgrind memleak fixes Various fixes for memory leaks, adds a target cleanup for aarch64 and ARM CTI objects. Change-Id: I2267f0894df655fdf73d70c11ed03df0b8f8d07d Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4478 Tested-by: jenkins Reviewed-by: Matthias Welwarsky Reviewed-by: Tomas Vanek --- src/jtag/core.c | 2 -- src/openocd.c | 4 ++++ src/target/aarch64.c | 15 +++++++++++++++ src/target/arm_cti.c | 12 ++++++++++++ src/target/arm_cti.h | 2 +- src/target/armv8.c | 46 ++++++++++++++++++++++++++++++++++++++------ src/target/armv8.h | 2 ++ 7 files changed, 74 insertions(+), 9 deletions(-) diff --git a/src/jtag/core.c b/src/jtag/core.c index 4522321a7..5d9b8101e 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -1494,8 +1494,6 @@ int adapter_quit(void) t = n; } - dap_cleanup_all(); - return ERROR_OK; } diff --git a/src/openocd.c b/src/openocd.c index 902528d08..f084dd452 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -359,6 +359,10 @@ int openocd_main(int argc, char *argv[]) unregister_all_commands(cmd_ctx, NULL); + /* free all DAP and CTI objects */ + dap_cleanup_all(); + arm_cti_cleanup_all(); + adapter_quit(); /* Shutdown commandline interface */ diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 4641a3fd5..cd835027b 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -2386,6 +2386,20 @@ static int aarch64_target_create(struct target *target, Jim_Interp *interp) return aarch64_init_arch_info(target, aarch64, pc->adiv5_config.dap); } +static void aarch64_deinit_target(struct target *target) +{ + struct aarch64_common *aarch64 = target_to_aarch64(target); + struct armv8_common *armv8 = &aarch64->armv8_common; + struct arm_dpm *dpm = &armv8->dpm; + + armv8_free_reg_cache(target); + free(aarch64->brp_list); + free(dpm->dbp); + free(dpm->dwp); + free(target->private_config); + free(aarch64); +} + static int aarch64_mmu(struct target *target, int *enabled) { if (target->state != TARGET_HALTED) { @@ -2658,6 +2672,7 @@ struct target_type aarch64_target = { .target_create = aarch64_target_create, .target_jim_configure = aarch64_jim_configure, .init_target = aarch64_init_target, + .deinit_target = aarch64_deinit_target, .examine = aarch64_examine, .read_phys_memory = aarch64_read_phys_memory, diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c index 547b96158..0d117e76d 100644 --- a/src/target/arm_cti.c +++ b/src/target/arm_cti.c @@ -219,6 +219,18 @@ static int cti_find_reg_offset(const char *name) return -1; } +int arm_cti_cleanup_all(void) +{ + struct arm_cti_object *obj, *tmp; + + list_for_each_entry_safe(obj, tmp, &all_cti, lh) { + free(obj->name); + free(obj); + } + + return ERROR_OK; +} + COMMAND_HANDLER(handle_cti_dump) { struct arm_cti_object *obj = CMD_DATA; diff --git a/src/target/arm_cti.h b/src/target/arm_cti.h index 181f06447..7c4f7ebe3 100644 --- a/src/target/arm_cti.h +++ b/src/target/arm_cti.h @@ -73,7 +73,7 @@ extern int arm_cti_read_reg(struct arm_cti *self, unsigned int reg, uint32_t *va extern int arm_cti_pulse_channel(struct arm_cti *self, uint32_t channel); extern int arm_cti_set_channel(struct arm_cti *self, uint32_t channel); extern int arm_cti_clear_channel(struct arm_cti *self, uint32_t channel); - +extern int arm_cti_cleanup_all(void); extern int cti_register_commands(struct command_context *cmd_ctx); #endif /* OPENOCD_TARGET_ARM_CTI_H */ diff --git a/src/target/armv8.c b/src/target/armv8.c index 3321dd600..82b2b2495 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -1547,15 +1547,14 @@ struct reg_cache *armv8_build_reg_cache(struct target *target) } else LOG_ERROR("unable to allocate feature list"); - if (armv8_regs[i].data_type == NULL) { - reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); - if (reg_list[i].reg_data_type) + reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); + if (reg_list[i].reg_data_type) { + if (armv8_regs[i].data_type == NULL) reg_list[i].reg_data_type->type = armv8_regs[i].type; else - LOG_ERROR("unable to allocate reg type list"); + *reg_list[i].reg_data_type = *armv8_regs[i].data_type; } else - reg_list[i].reg_data_type = armv8_regs[i].data_type; - + LOG_ERROR("unable to allocate reg type list"); } arm->cpsr = reg_list + ARMV8_xPSR; @@ -1608,6 +1607,41 @@ struct reg *armv8_reg_current(struct arm *arm, unsigned regnum) return r; } +static void armv8_free_cache(struct reg_cache *cache, bool regs32) +{ + struct reg *reg; + unsigned int i; + + if (!cache) + return; + + for (i = 0; i < cache->num_regs; i++) { + reg = &cache->reg_list[i]; + + free(reg->feature); + free(reg->reg_data_type); + } + + if (!regs32) + free(cache->reg_list[0].arch_info); + free(cache->reg_list); + free(cache); +} + +void armv8_free_reg_cache(struct target *target) +{ + struct armv8_common *armv8 = target_to_armv8(target); + struct arm *arm = &armv8->arm; + struct reg_cache *cache = NULL, *cache32 = NULL; + + cache = arm->core_cache; + if (cache != NULL) + cache32 = cache->next; + armv8_free_cache(cache32, true); + armv8_free_cache(cache, false); + arm->core_cache = NULL; +} + const struct command_registration armv8_command_handlers[] = { COMMAND_REGISTRATION_DONE }; diff --git a/src/target/armv8.h b/src/target/armv8.h index 6525d2601..b34646224 100644 --- a/src/target/armv8.h +++ b/src/target/armv8.h @@ -318,6 +318,8 @@ static inline unsigned int armv8_curel_from_core_mode(enum arm_mode core_mode) void armv8_select_reg_access(struct armv8_common *armv8, bool is_aarch64); int armv8_set_dbgreg_bits(struct armv8_common *armv8, unsigned int reg, unsigned long mask, unsigned long value); +extern void armv8_free_reg_cache(struct target *target); + extern const struct command_registration armv8_command_handlers[]; #endif /* OPENOCD_TARGET_ARMV8_H */ From 81d0b769a65bf15dda2fd51cd4aee50bb0dc16fb Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Fri, 23 Feb 2018 00:12:50 +0100 Subject: [PATCH 18/30] target/cortex_m: allow setting the type of a breakpoint Cortex-M target used 'auto_bp_type' mode. The requested type of breakpoint was ignored and hard (FPB) breakpoints were set in 'code memory area' 0x00000000-0x1fffffff, soft breakpoints were set above 0x20000000. The code memory area of Cortex-M does not mean the memory is flash and vice versa. External flash (parallel or QSPI) is usually mapped above code memory area. Cortex-M7 ITCM RAM is mapped at 0. Kinetis has a RAM block under 0x20000000 boundary. Remove 'auto_bp_type' mode, set breakpoints to requested type. Change 'cortex_m maskisr auto' handling to use a hard temporary breakpoint everywhere: it can also workaround not working soft breakpoints on Cortex-M7 with ICache enabled. Change-Id: I7a9f9464c5e10bfd7f17cba1037ed07a064fa2e8 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4429 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- doc/openocd.texi | 7 ++++--- src/target/cortex_m.c | 29 +---------------------------- src/target/cortex_m.h | 1 - 3 files changed, 5 insertions(+), 32 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 1243438a4..a47244607 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8630,9 +8630,10 @@ the next instruction where the core was halted. After the step interrupts are enabled again. If the interrupt handlers don't complete within 500ms, the step command leaves with the core running. -Note that a free breakpoint is required for the @option{auto} option. If no -breakpoint is available at the time of the step, then the step is taken -with interrupts enabled, i.e. the same way the @option{off} option does. +Note that a free hardware (FPB) breakpoint is required for the @option{auto} +option. If no breakpoint is available at the time of the step, then the step +is taken with interrupts enabled, i.e. the same way the @option{off} option +does. Default is @option{auto}. @end deffn diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index a356350a2..30439f458 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -51,11 +51,6 @@ * any longer. */ -/** - * Returns the type of a break point required by address location - */ -#define BKPT_TYPE_BY_ADDR(addr) ((addr) < 0x20000000 ? BKPT_HARD : BKPT_SOFT) - /* forward declarations */ static int cortex_m_store_core_reg_u32(struct target *target, uint32_t num, uint32_t value); @@ -868,7 +863,7 @@ static int cortex_m_step(struct target *target, int current, if (breakpoint) retval = cortex_m_set_breakpoint(target, breakpoint); else - retval = breakpoint_add(target, pc_value, 2, BKPT_TYPE_BY_ADDR(pc_value)); + retval = breakpoint_add(target, pc_value, 2, BKPT_HARD); bool tmp_bp_set = (retval == ERROR_OK); /* No more breakpoints left, just do a step */ @@ -1131,9 +1126,6 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint return ERROR_OK; } - if (cortex_m->auto_bp_type) - breakpoint->type = BKPT_TYPE_BY_ADDR(breakpoint->address); - if (breakpoint->type == BKPT_HARD) { uint32_t fpcr_value; while (comparator_list[fp_num].used && (fp_num < cortex_m->fp_num_code)) @@ -1253,21 +1245,6 @@ int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint { struct cortex_m_common *cortex_m = target_to_cm(target); - if (cortex_m->auto_bp_type) - breakpoint->type = BKPT_TYPE_BY_ADDR(breakpoint->address); - - if (breakpoint->type != BKPT_TYPE_BY_ADDR(breakpoint->address)) { - if (breakpoint->type == BKPT_HARD) { - LOG_INFO("flash patch comparator requested outside code memory region"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - if (breakpoint->type == BKPT_SOFT) { - LOG_INFO("soft breakpoint requested in code (flash) memory region"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - } - if ((breakpoint->type == BKPT_HARD) && (cortex_m->fp_code_available < 1)) { LOG_INFO("no flash patch comparator unit available for hardware breakpoint"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; @@ -1299,9 +1276,6 @@ int cortex_m_remove_breakpoint(struct target *target, struct breakpoint *breakpo return ERROR_TARGET_NOT_HALTED; } - if (cortex_m->auto_bp_type) - breakpoint->type = BKPT_TYPE_BY_ADDR(breakpoint->address); - if (breakpoint->set) cortex_m_unset_breakpoint(target, breakpoint); @@ -2111,7 +2085,6 @@ int cortex_m_examine(struct target *target) /* Setup FPB */ target_read_u32(target, FP_CTRL, &fpcr); - cortex_m->auto_bp_type = 1; /* bits [14:12] and [7:4] */ cortex_m->fp_num_code = ((fpcr >> 8) & 0x70) | ((fpcr >> 4) & 0xF); cortex_m->fp_num_lit = (fpcr >> 8) & 0xF; diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index 9500acc1d..2daf4cb24 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -175,7 +175,6 @@ struct cortex_m_common { int fp_code_available; int fp_rev; int fpb_enabled; - int auto_bp_type; struct cortex_m_fp_comparator *fp_comparator_list; /* Data Watchpoint and Trace (DWT) */ From 2b47ded8dee5ba52d47ce7cbc8b643ae4a3663ae Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Mon, 9 Apr 2018 21:41:31 +0200 Subject: [PATCH 19/30] target: add Cortex-M4 target to VF6xx target The Vybrid VF6xx SoCs contain an additional Cortex-M4 core connected to AP number 3 of the main DAP. Change-Id: I59c020fdfc53e909b1f0dac1a8627a62cdaa74f2 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/3640 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/target/vybrid_vf6xx.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcl/target/vybrid_vf6xx.cfg b/tcl/target/vybrid_vf6xx.cfg index a1202efb7..7cb916d1f 100644 --- a/tcl/target/vybrid_vf6xx.cfg +++ b/tcl/target/vybrid_vf6xx.cfg @@ -33,5 +33,5 @@ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu target create ${_TARGETNAME}0 cortex_a -dap $_CHIPNAME.dap -dbgbase 0xc0088000 - +target create ${_TARGETNAME}1 cortex_m -dap $_CHIPNAME.dap -ap-num 3 -defer-examine adapter_khz 1000 From 3a28c8c4bab1e51b9ff2acd3ca590e61bbfb807c Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 15 Apr 2018 00:43:46 +0200 Subject: [PATCH 20/30] jtag: adapter: fix indentation in handle_interface_command Minor fix, no code change, just align it to the block it belongs to. Change-Id: I4c3b0d0bd00a55d5109d3723e5c4bfb2fc72e366 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4492 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/jtag/adapter.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c index 5953de7e5..2035788bf 100644 --- a/src/jtag/adapter.c +++ b/src/jtag/adapter.c @@ -149,14 +149,14 @@ COMMAND_HANDLER(handle_interface_command) jtag_interface = jtag_interfaces[i]; - /* LEGACY SUPPORT ... adapter drivers must declare what - * transports they allow. Until they all do so, assume - * the legacy drivers are JTAG-only - */ - if (!jtag_interface->transports) - LOG_WARNING("Adapter driver '%s' did not declare " - "which transports it allows; assuming " - "legacy JTAG-only", jtag_interface->name); + /* LEGACY SUPPORT ... adapter drivers must declare what + * transports they allow. Until they all do so, assume + * the legacy drivers are JTAG-only + */ + if (!jtag_interface->transports) + LOG_WARNING("Adapter driver '%s' did not declare " + "which transports it allows; assuming " + "legacy JTAG-only", jtag_interface->name); retval = allow_transports(CMD_CTX, jtag_interface->transports ? jtag_interface->transports : jtag_only); if (ERROR_OK != retval) From 3737dd69e73816d186ba418d7b833462a8041079 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 11 Apr 2018 17:15:01 +0200 Subject: [PATCH 21/30] tcl/target: Add Renesas R-Car R8A7790 H2 target Add configuration for the Renesas R-Car R8A7790 H2 target. This is an SoC with four Cortex A15 and four Cortex A7 ARMv7a cores, only the four A15 cores are supported. Change-Id: I6099b257cc0f04e6858ed5f5f8c8d8ad82ef7650 Signed-off-by: Marek Vasut Reviewed-on: http://openocd.zylin.com/4490 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/target/renesas_r8a7790.cfg | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tcl/target/renesas_r8a7790.cfg diff --git a/tcl/target/renesas_r8a7790.cfg b/tcl/target/renesas_r8a7790.cfg new file mode 100644 index 000000000..a662b6b37 --- /dev/null +++ b/tcl/target/renesas_r8a7790.cfg @@ -0,0 +1,36 @@ +# Renesas R-Car H2 +# https://www.renesas.com/en-us/solutions/automotive/products/rcar-h2.html + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x4ba00477 +} + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME r8a7790 +} + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $_DAP_TAPID + +# Configuring only one core using DAP. +# Base addresses of Cortex A15 cores: +# core 0 - 0x800B0000 +# core 1 - 0x800B2000 +# core 2 - 0x800B4000 +# core 3 - 0x800B6000 +# Base addresses of Cortex A7 cores (not supported yet): +# core 0 - 0x800F0000 +# core 1 - 0x800F2000 +# core 2 - 0x800F4000 +# core 3 - 0x800F6000 +set _TARGETNAME $_CHIPNAME.ca15. +dap create ${_CHIPNAME}.dap -chain-position $_CHIPNAME.cpu +target create ${_TARGETNAME}0 cortex_a -dap ${_CHIPNAME}.dap -coreid 0 -dbgbase 0x800B0000 +target create ${_TARGETNAME}1 cortex_a -dap ${_CHIPNAME}.dap -coreid 1 -dbgbase 0x800B2000 -defer-examine +target create ${_TARGETNAME}2 cortex_a -dap ${_CHIPNAME}.dap -coreid 2 -dbgbase 0x800B4000 -defer-examine +target create ${_TARGETNAME}3 cortex_a -dap ${_CHIPNAME}.dap -coreid 3 -dbgbase 0x800B6000 -defer-examine + +targets ${_TARGETNAME}0 From 2eadf1e847f4880c698cae8dca857714e464e471 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Thu, 19 Apr 2018 09:56:14 +0200 Subject: [PATCH 22/30] board: add configuration for stm32f103c8 "Blue Pill" The "Blue Pill" is a popular development board with an STM32F103C8 micro controller. According to sources, it has a 128kB Flash on board even though the option bytes only report 64kB. This patch therefore also modifies target/stm32f1x.cfg to take an optional FLASH_SIZE variable into account which the board file sets to 0x20000. Change-Id: I8a78ccd2b5faf637c539ee3cf8136789ee15c95d Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4495 Tested-by: jenkins Reviewed-by: Tomas Vanek --- tcl/board/stm32f103c8_blue_pill.cfg | 14 ++++++++++++++ tcl/target/stm32f1x.cfg | 10 +++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tcl/board/stm32f103c8_blue_pill.cfg diff --git a/tcl/board/stm32f103c8_blue_pill.cfg b/tcl/board/stm32f103c8_blue_pill.cfg new file mode 100644 index 000000000..2487f3500 --- /dev/null +++ b/tcl/board/stm32f103c8_blue_pill.cfg @@ -0,0 +1,14 @@ +# STM32F103C8 "Blue Pill" + +# NOTE: +# There is a fair bit of confusion about whether the "Blue Pill" has 128kB or 64kB flash size. +# The most likely cause is that there exist a -C8 and a -CB variant of the STM32F103, where +# the C8 has 64kB, the CB has 128kB as per specification. "Blue Pill" boards are manufactured +# by a lot of different vendors, some may actually use the CB variant but from a cursory look +# it very hard to tell them apart ("C8" and "CB" look very similar). Nevertheless, people have +# tried using the full 128kB of flash on the C8 and found it to be working. Hence this board file +# overrides the internal size detection. Be aware though that you may be using you particular +# board outside of its specification. If in doubt, comment the following line. +set FLASH_SIZE 0x20000 + +source [find target/stm32f1x.cfg] diff --git a/tcl/target/stm32f1x.cfg b/tcl/target/stm32f1x.cfg index e0f6ede95..471878d7f 100644 --- a/tcl/target/stm32f1x.cfg +++ b/tcl/target/stm32f1x.cfg @@ -22,6 +22,14 @@ if { [info exists WORKAREASIZE] } { set _WORKAREASIZE 0x1000 } +# Allow overriding the Flash bank size +if { [info exists FLASH_SIZE] } { + set _FLASH_SIZE $FLASH_SIZE +} else { + # autodetect size + set _FLASH_SIZE 0 +} + #jtag scan chain if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID @@ -49,7 +57,7 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE # flash size will be probed set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME stm32f1x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_FLASHNAME stm32f1x 0x08000000 $_FLASH_SIZE 0 0 $_TARGETNAME # JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz adapter_khz 1000 From b941e2e727387c6c8880990b829a48b289dfc90b Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 1 Mar 2018 22:57:08 +0100 Subject: [PATCH 23/30] flash/nor, contrib/loaders: add stm32 loaders Makefile and generated .inc Flash loaders refactored to the new style - use generated .inc instead of hexadecimal machine code in the flash driver source. Change-Id: If65a2099589e210f9450819b467d67819fd841fc Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4439 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- contrib/loaders/flash/stm32/Makefile | 28 ++++++++++++ contrib/loaders/flash/{ => stm32}/stm32f1x.S | 5 ++- contrib/loaders/flash/stm32/stm32f1x.inc | 5 +++ contrib/loaders/flash/{ => stm32}/stm32f2x.S | 10 +++-- contrib/loaders/flash/stm32/stm32f2x.inc | 6 +++ contrib/loaders/flash/{ => stm32}/stm32h7x.S | 25 +++-------- contrib/loaders/flash/stm32/stm32h7x.inc | 7 +++ contrib/loaders/flash/{ => stm32}/stm32l4x.S | 24 ++++------- contrib/loaders/flash/stm32/stm32l4x.inc | 7 +++ contrib/loaders/flash/{ => stm32}/stm32lx.S | 6 +-- contrib/loaders/flash/stm32/stm32lx.inc | 2 + src/flash/nor/stm32f1x.c | 39 +---------------- src/flash/nor/stm32f2x.c | 39 +---------------- src/flash/nor/stm32h7x.c | 45 +------------------- src/flash/nor/stm32l4x.c | 13 +----- src/flash/nor/stm32lx.c | 4 +- 16 files changed, 87 insertions(+), 178 deletions(-) create mode 100644 contrib/loaders/flash/stm32/Makefile rename contrib/loaders/flash/{ => stm32}/stm32f1x.S (99%) create mode 100644 contrib/loaders/flash/stm32/stm32f1x.inc rename contrib/loaders/flash/{ => stm32}/stm32f2x.S (96%) create mode 100644 contrib/loaders/flash/stm32/stm32f2x.inc rename contrib/loaders/flash/{ => stm32}/stm32h7x.S (90%) create mode 100644 contrib/loaders/flash/stm32/stm32h7x.inc rename contrib/loaders/flash/{ => stm32}/stm32l4x.S (90%) create mode 100644 contrib/loaders/flash/stm32/stm32l4x.inc rename contrib/loaders/flash/{ => stm32}/stm32lx.S (98%) create mode 100644 contrib/loaders/flash/stm32/stm32lx.inc diff --git a/contrib/loaders/flash/stm32/Makefile b/contrib/loaders/flash/stm32/Makefile new file mode 100644 index 000000000..b58b41284 --- /dev/null +++ b/contrib/loaders/flash/stm32/Makefile @@ -0,0 +1,28 @@ +BIN2C = ../../../../src/helper/bin2char.sh + +CROSS_COMPILE ?= arm-none-eabi- + +CC=$(CROSS_COMPILE)gcc +OBJCOPY=$(CROSS_COMPILE)objcopy +OBJDUMP=$(CROSS_COMPILE)objdump + +CFLAGS = -static -nostartfiles -mlittle-endian -Wa,-EL + +all: stm32f1x.inc stm32f2x.inc stm32h7x.inc stm32l4x.inc stm32lx.inc + +.PHONY: clean + +%.elf: %.S + $(CC) $(CFLAGS) $< -o $@ + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +%.bin: %.elf + $(OBJCOPY) -Obinary $< $@ + +%.inc: %.bin + $(BIN2C) < $< > $@ + +clean: + -rm -f *.elf *.lst *.bin *.inc diff --git a/contrib/loaders/flash/stm32f1x.S b/contrib/loaders/flash/stm32/stm32f1x.S similarity index 99% rename from contrib/loaders/flash/stm32f1x.S rename to contrib/loaders/flash/stm32/stm32f1x.S index 5ce463d1b..7b64c67aa 100644 --- a/contrib/loaders/flash/stm32f1x.S +++ b/contrib/loaders/flash/stm32/stm32f1x.S @@ -22,8 +22,6 @@ .syntax unified .cpu cortex-m0 .thumb - .thumb_func - .global write /* Params: * r0 - flash base (in), status (out) @@ -39,6 +37,9 @@ #define STM32_FLASH_SR_OFFSET 0x0c /* offset of SR register from flash reg base */ + .thumb_func + .global _start +_start: wait_fifo: ldr r6, [r2, #0] /* read wp */ cmp r6, #0 /* abort if wp == 0 */ diff --git a/contrib/loaders/flash/stm32/stm32f1x.inc b/contrib/loaders/flash/stm32/stm32f1x.inc new file mode 100644 index 000000000..7f9454b96 --- /dev/null +++ b/contrib/loaders/flash/stm32/stm32f1x.inc @@ -0,0 +1,5 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x16,0x68,0x00,0x2e,0x18,0xd0,0x55,0x68,0xb5,0x42,0xf9,0xd0,0x2e,0x88,0x26,0x80, +0x02,0x35,0x02,0x34,0xc6,0x68,0x01,0x27,0x3e,0x42,0xfb,0xd1,0x14,0x27,0x3e,0x42, +0x08,0xd1,0x9d,0x42,0x01,0xd3,0x15,0x46,0x08,0x35,0x55,0x60,0x01,0x39,0x00,0x29, +0x02,0xd0,0xe5,0xe7,0x00,0x20,0x50,0x60,0x30,0x46,0x00,0xbe, diff --git a/contrib/loaders/flash/stm32f2x.S b/contrib/loaders/flash/stm32/stm32f2x.S similarity index 96% rename from contrib/loaders/flash/stm32f2x.S rename to contrib/loaders/flash/stm32/stm32f2x.S index 0dd122319..f6f5b30a4 100644 --- a/contrib/loaders/flash/stm32f2x.S +++ b/contrib/loaders/flash/stm32/stm32f2x.S @@ -25,7 +25,6 @@ .syntax unified .cpu cortex-m3 .thumb - .thumb_func /* * Params : @@ -44,6 +43,11 @@ #define STM32_FLASH_CR_OFFSET 0x10 /* offset of CR register in FLASH struct */ #define STM32_FLASH_SR_OFFSET 0x0c /* offset of SR register in FLASH struct */ +#define STM32_PROG16 0x101 /* PG | PSIZE_16*/ + + .thumb_func + .global _start +_start: wait_fifo: ldr r8, [r0, #0] /* read wp */ cmp r8, #0 /* abort if wp == 0 */ @@ -52,7 +56,7 @@ wait_fifo: cmp r7, r8 /* wait until rp != wp */ beq wait_fifo - ldr r6, STM32_PROG16 + ldr r6, =STM32_PROG16 str r6, [r4, #STM32_FLASH_CR_OFFSET] ldrh r6, [r7], #0x02 /* read one half-word from src, increment ptr */ strh r6, [r2], #0x02 /* write one half-word from src, increment ptr */ @@ -78,4 +82,4 @@ exit: mov r0, r6 /* return status in r0 */ bkpt #0x00 -STM32_PROG16: .word 0x101 /* PG | PSIZE_16*/ + .pool diff --git a/contrib/loaders/flash/stm32/stm32f2x.inc b/contrib/loaders/flash/stm32/stm32f2x.inc new file mode 100644 index 000000000..3da2940eb --- /dev/null +++ b/contrib/loaders/flash/stm32/stm32f2x.inc @@ -0,0 +1,6 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0xd0,0xf8,0x00,0x80,0xb8,0xf1,0x00,0x0f,0x1b,0xd0,0x47,0x68,0x47,0x45,0xf7,0xd0, +0x0d,0x4e,0x26,0x61,0x37,0xf8,0x02,0x6b,0x22,0xf8,0x02,0x6b,0xbf,0xf3,0x4f,0x8f, +0xe6,0x68,0x16,0xf4,0x80,0x3f,0xfb,0xd1,0x16,0xf0,0xf0,0x0f,0x07,0xd1,0x8f,0x42, +0x28,0xbf,0x00,0xf1,0x08,0x07,0x47,0x60,0x01,0x3b,0x13,0xb1,0xe0,0xe7,0x00,0x21, +0x41,0x60,0x30,0x46,0x00,0xbe,0x00,0x00,0x01,0x01,0x00,0x00, diff --git a/contrib/loaders/flash/stm32h7x.S b/contrib/loaders/flash/stm32/stm32h7x.S similarity index 90% rename from contrib/loaders/flash/stm32h7x.S rename to contrib/loaders/flash/stm32/stm32h7x.S index 0f5ea996f..f910bfbb1 100644 --- a/contrib/loaders/flash/stm32h7x.S +++ b/contrib/loaders/flash/stm32/stm32h7x.S @@ -20,21 +20,6 @@ .syntax unified .cpu cortex-m7 .thumb - .thumb_func - -/* - * To assemble: - * arm-none-eabi-gcc -c stm32h7x.S - * - * To disassemble: - * arm-none-eabi-objdump -d stm32h7x.o - * - * To generate binary file: - * arm-none-eabi-objcopy -O binary stm32h7x.o stm32h7_flash_write_code.bin - * - * To generate include file: - * xxd -i stm32h7_flash_write_code.bin - */ /* * Code limitations: @@ -67,7 +52,9 @@ #define STM32_SR_ERROR_MASK 0x03ee0000 /* DBECCERR | SNECCERR | RDSERR | RDPERR | OPERR | INCERR | STRBERR | PGSERR | WRPERR */ -code: + .thumb_func + .global _start +_start: ldr r5, [r0, #4] /* read rp */ wait_fifo: @@ -100,7 +87,7 @@ busy: tst r6, #STM32_SR_BUSY_MASK bne busy /* operation in progress, wait ... */ - ldr r7, stm32_sr_error_mask + ldr r7, =STM32_SR_ERROR_MASK tst r6, r7 bne error /* fail... */ @@ -117,5 +104,5 @@ exit: mov r0, r6 /* return status in r0 */ bkpt #0x00 -stm32_sr_error_mask: - .word STM32_SR_ERROR_MASK + .pool + diff --git a/contrib/loaders/flash/stm32/stm32h7x.inc b/contrib/loaders/flash/stm32/stm32h7x.inc new file mode 100644 index 000000000..174354c76 --- /dev/null +++ b/contrib/loaders/flash/stm32/stm32h7x.inc @@ -0,0 +1,7 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x45,0x68,0x06,0x68,0x26,0xb3,0x76,0x1b,0x42,0xbf,0x76,0x18,0x36,0x1a,0x08,0x3e, +0x20,0x2e,0xf6,0xd3,0x4f,0xf0,0x32,0x06,0xe6,0x60,0x4f,0xf0,0x08,0x07,0x55,0xf8, +0x04,0x6b,0x42,0xf8,0x04,0x6b,0xbf,0xf3,0x4f,0x8f,0x8d,0x42,0x28,0xbf,0x00,0xf1, +0x08,0x05,0x01,0x3f,0xf3,0xd1,0x26,0x69,0x16,0xf0,0x01,0x0f,0xfb,0xd1,0x05,0x4f, +0x3e,0x42,0x03,0xd1,0x45,0x60,0x01,0x3b,0xdb,0xd1,0x01,0xe0,0x00,0x27,0x47,0x60, +0x30,0x46,0x00,0xbe,0x00,0x00,0xee,0x03, diff --git a/contrib/loaders/flash/stm32l4x.S b/contrib/loaders/flash/stm32/stm32l4x.S similarity index 90% rename from contrib/loaders/flash/stm32l4x.S rename to contrib/loaders/flash/stm32/stm32l4x.S index 799dec527..9c49016df 100644 --- a/contrib/loaders/flash/stm32l4x.S +++ b/contrib/loaders/flash/stm32/stm32l4x.S @@ -27,20 +27,6 @@ .syntax unified .cpu cortex-m4 .thumb - .thumb_func - -/* To assemble: - * arm-none-eabi-gcc -c stm32l4x.S - * - * To disassemble: - * arm-none-eabi-objdump -o stm32l4x.o - * - * To generate binary file: - * arm-none-eabi-objcopy -O binary stm32l4x.o stm32l4_flash_write_code.bin - * - * To generate include file: - * xxd -i stm32l4_flash_write_code.bin - */ /* * Params : @@ -59,6 +45,11 @@ #define STM32_FLASH_CR_OFFSET 0x14 /* offset of CR register in FLASH struct */ #define STM32_FLASH_SR_OFFSET 0x10 /* offset of SR register in FLASH struct */ +#define STM32_PROG 0x1 /* PG */ + + .thumb_func + .global _start +_start: wait_fifo: ldr r8, [r0, #0] /* read wp */ cmp r8, #0 /* abort if wp == 0 */ @@ -71,7 +62,7 @@ wait_fifo: cmp r6, #8 /* wait until 8 bytes are available */ bcc wait_fifo - ldr r6, STM32_PROG + ldr r6, =STM32_PROG str r6, [r4, #STM32_FLASH_CR_OFFSET] ldrd r6, [r5], #0x08 /* read one word from src, increment ptr */ strd r6, [r2], #0x08 /* write one word to dst, increment ptr */ @@ -97,4 +88,5 @@ exit: mov r0, r6 /* return status in r0 */ bkpt #0x00 -STM32_PROG: .word 0x1 /* PG */ + .pool + diff --git a/contrib/loaders/flash/stm32/stm32l4x.inc b/contrib/loaders/flash/stm32/stm32l4x.inc new file mode 100644 index 000000000..4065d14ef --- /dev/null +++ b/contrib/loaders/flash/stm32/stm32l4x.inc @@ -0,0 +1,7 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0xd0,0xf8,0x00,0x80,0xb8,0xf1,0x00,0x0f,0x20,0xd0,0x45,0x68,0xb8,0xeb,0x05,0x06, +0x44,0xbf,0x76,0x18,0x36,0x1a,0x08,0x2e,0xf2,0xd3,0x0d,0x4e,0x66,0x61,0xf5,0xe8, +0x02,0x67,0xe2,0xe8,0x02,0x67,0xbf,0xf3,0x4f,0x8f,0x26,0x69,0x16,0xf4,0x80,0x3f, +0xfb,0xd1,0x16,0xf0,0xfa,0x0f,0x07,0xd1,0x8d,0x42,0x28,0xbf,0x00,0xf1,0x08,0x05, +0x45,0x60,0x01,0x3b,0x13,0xb1,0xdb,0xe7,0x00,0x21,0x41,0x60,0x30,0x46,0x00,0xbe, +0x01,0x00,0x00,0x00, diff --git a/contrib/loaders/flash/stm32lx.S b/contrib/loaders/flash/stm32/stm32lx.S similarity index 98% rename from contrib/loaders/flash/stm32lx.S rename to contrib/loaders/flash/stm32/stm32lx.S index 8f9fd0b2b..bcae7a46c 100644 --- a/contrib/loaders/flash/stm32lx.S +++ b/contrib/loaders/flash/stm32/stm32lx.S @@ -28,13 +28,10 @@ ***************************************************************************/ -// Build : arm-eabi-gcc -c stm32lx.S .text .syntax unified .cpu cortex-m0 .thumb - .thumb_func - .global write /* r0 - destination address @@ -42,6 +39,9 @@ r2 - count */ + .thumb_func + .global _start +_start: // r2 = source + count * 4 lsls r2, r2, #2 adds r2, r1, r2 diff --git a/contrib/loaders/flash/stm32/stm32lx.inc b/contrib/loaders/flash/stm32/stm32lx.inc new file mode 100644 index 000000000..eaaf1848a --- /dev/null +++ b/contrib/loaders/flash/stm32/stm32lx.inc @@ -0,0 +1,2 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x92,0x00,0x8a,0x18,0x01,0xe0,0x08,0xc9,0x08,0xc0,0x91,0x42,0xfb,0xd1,0x00,0xbe, diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 64c91680c..015988a5d 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -572,45 +572,8 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; - /* see contrib/loaders/flash/stm32f1x.S for src */ - static const uint8_t stm32x_flash_write_code[] = { - /* #define STM32_FLASH_SR_OFFSET 0x0C */ - /* wait_fifo: */ - 0x16, 0x68, /* ldr r6, [r2, #0] */ - 0x00, 0x2e, /* cmp r6, #0 */ - 0x18, 0xd0, /* beq exit */ - 0x55, 0x68, /* ldr r5, [r2, #4] */ - 0xb5, 0x42, /* cmp r5, r6 */ - 0xf9, 0xd0, /* beq wait_fifo */ - 0x2e, 0x88, /* ldrh r6, [r5, #0] */ - 0x26, 0x80, /* strh r6, [r4, #0] */ - 0x02, 0x35, /* adds r5, #2 */ - 0x02, 0x34, /* adds r4, #2 */ - /* busy: */ - 0xc6, 0x68, /* ldr r6, [r0, #STM32_FLASH_SR_OFFSET] */ - 0x01, 0x27, /* movs r7, #1 */ - 0x3e, 0x42, /* tst r6, r7 */ - 0xfb, 0xd1, /* bne busy */ - 0x14, 0x27, /* movs r7, #0x14 */ - 0x3e, 0x42, /* tst r6, r7 */ - 0x08, 0xd1, /* bne error */ - 0x9d, 0x42, /* cmp r5, r3 */ - 0x01, 0xd3, /* bcc no_wrap */ - 0x15, 0x46, /* mov r5, r2 */ - 0x08, 0x35, /* adds r5, #8 */ - /* no_wrap: */ - 0x55, 0x60, /* str r5, [r2, #4] */ - 0x01, 0x39, /* subs r1, r1, #1 */ - 0x00, 0x29, /* cmp r1, #0 */ - 0x02, 0xd0, /* beq exit */ - 0xe5, 0xe7, /* b wait_fifo */ - /* error: */ - 0x00, 0x20, /* movs r0, #0 */ - 0x50, 0x60, /* str r0, [r2, #4] */ - /* exit: */ - 0x30, 0x46, /* mov r0, r6 */ - 0x00, 0xbe, /* bkpt #0 */ +#include "../../../contrib/loaders/flash/stm32/stm32f1x.inc" }; /* flash write code */ diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 8bca62ea2..8013e5869 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -584,45 +584,8 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; - /* see contrib/loaders/flash/stm32f2x.S for src */ - static const uint8_t stm32x_flash_write_code[] = { - /* wait_fifo: */ - 0xD0, 0xF8, 0x00, 0x80, /* ldr r8, [r0, #0] */ - 0xB8, 0xF1, 0x00, 0x0F, /* cmp r8, #0 */ - 0x1A, 0xD0, /* beq exit */ - 0x47, 0x68, /* ldr r7, [r0, #4] */ - 0x47, 0x45, /* cmp r7, r8 */ - 0xF7, 0xD0, /* beq wait_fifo */ - - 0xDF, 0xF8, 0x34, 0x60, /* ldr r6, STM32_PROG16 */ - 0x26, 0x61, /* str r6, [r4, #STM32_FLASH_CR_OFFSET] */ - 0x37, 0xF8, 0x02, 0x6B, /* ldrh r6, [r7], #0x02 */ - 0x22, 0xF8, 0x02, 0x6B, /* strh r6, [r2], #0x02 */ - 0xBF, 0xF3, 0x4F, 0x8F, /* dsb sy */ - /* busy: */ - 0xE6, 0x68, /* ldr r6, [r4, #STM32_FLASH_SR_OFFSET] */ - 0x16, 0xF4, 0x80, 0x3F, /* tst r6, #0x10000 */ - 0xFB, 0xD1, /* bne busy */ - 0x16, 0xF0, 0xF0, 0x0F, /* tst r6, #0xf0 */ - 0x07, 0xD1, /* bne error */ - - 0x8F, 0x42, /* cmp r7, r1 */ - 0x28, 0xBF, /* it cs */ - 0x00, 0xF1, 0x08, 0x07, /* addcs r7, r0, #8 */ - 0x47, 0x60, /* str r7, [r0, #4] */ - 0x01, 0x3B, /* subs r3, r3, #1 */ - 0x13, 0xB1, /* cbz r3, exit */ - 0xDF, 0xE7, /* b wait_fifo */ - /* error: */ - 0x00, 0x21, /* movs r1, #0 */ - 0x41, 0x60, /* str r1, [r0, #4] */ - /* exit: */ - 0x30, 0x46, /* mov r0, r6 */ - 0x00, 0xBE, /* bkpt #0x00 */ - - /* : */ - 0x01, 0x01, 0x00, 0x00, /* .word 0x00000101 */ +#include "../../../contrib/loaders/flash/stm32/stm32f2x.inc" }; if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index a15cd2531..009eb9b86 100644 --- a/src/flash/nor/stm32h7x.c +++ b/src/flash/nor/stm32h7x.c @@ -568,51 +568,8 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; int retval = ERROR_OK; - /* see contrib/loaders/flash/smt32h7x.S for src */ static const uint8_t stm32x_flash_write_code[] = { - /* : */ - 0x45, 0x68, /* ldr r5, [r0, #4] */ - /* : */ - 0x06, 0x68, /* ldr r6, [r0, #0] */ - 0x26, 0xb3, /* cbz r6, */ - 0x76, 0x1b, /* subs r6, r6, r5 */ - 0x42, 0xbf, /* ittt mi */ - 0x76, 0x18, /* addmi r6, r6, r1 */ - 0x36, 0x1a, /* submi r6, r6, r0 */ - 0x08, 0x3e, /* submi r6, #8 */ - 0x20, 0x2e, /* cmp r6, #32 */ - 0xf6, 0xd3, /* bcc.n */ - 0x4f, 0xf0, 0x32, 0x06, /* mov.w r6, #STM32_PROG */ - 0xe6, 0x60, /* str r6, [r4, #STM32_FLASH_CR_OFFSET] */ - 0x4f, 0xf0, 0x08, 0x07, /* mov.w r7, #8 */ - /* : */ - 0x55, 0xf8, 0x04, 0x6b, /* ldr.w r6, [r5], #4 */ - 0x42, 0xf8, 0x04, 0x6b, /* str.w r6, [r2], #4 */ - 0xbf, 0xf3, 0x4f, 0x8f, /* dsb sy */ - 0x8d, 0x42, /* cmp r5, r1 */ - 0x28, 0xbf, /* it cs */ - 0x00, 0xf1, 0x08, 0x05, /* addcs.w r5, r0, #8 */ - 0x01, 0x3f, /* subs r7, #1 */ - 0xf3, 0xd1, /* bne.n */ - /* : */ - 0x26, 0x69, /* ldr r6, [r4, #STM32_FLASH_SR_OFFSET] */ - 0x16, 0xf0, 0x01, 0x0f, /* tst.w r6, #STM32_SR_BUSY_MASK */ - 0xfb, 0xd1, /* bne.n */ - 0x05, 0x4f, /* ldr r7, [pc, #20] ; () */ - 0x3e, 0x42, /* tst r6, r7 */ - 0x03, 0xd1, /* bne.n */ - 0x45, 0x60, /* str r5, [r0, #4] */ - 0x01, 0x3b, /* subs r3, #1 */ - 0xdb, 0xd1, /* bne.n */ - 0x01, 0xe0, /* b.n */ - /* : */ - 0x00, 0x27, /* movs r7, #0 */ - 0x47, 0x60, /* str r7, [r0, #4] */ - /* : */ - 0x30, 0x46, /* mov r0, r6 */ - 0x00, 0xbe, /* bkpt 0x0000 */ - /* : */ - 0x00, 0x00, 0xee, 0x03 /* .word 0x03ee0000 ; (STM32_SR_ERROR_MASK) */ +#include "../../../contrib/loaders/flash/stm32/stm32h7x.inc" }; if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index e2710bd81..e47313c19 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -461,19 +461,8 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; - /* See contrib/loaders/flash/stm32l4x.S for source and - * hints how to generate the data! - */ - static const uint8_t stm32l4_flash_write_code[] = { - 0xd0, 0xf8, 0x00, 0x80, 0xb8, 0xf1, 0x00, 0x0f, 0x21, 0xd0, 0x45, 0x68, - 0xb8, 0xeb, 0x05, 0x06, 0x44, 0xbf, 0x76, 0x18, 0x36, 0x1a, 0x08, 0x2e, - 0xf2, 0xd3, 0xdf, 0xf8, 0x36, 0x60, 0x66, 0x61, 0xf5, 0xe8, 0x02, 0x67, - 0xe2, 0xe8, 0x02, 0x67, 0xbf, 0xf3, 0x4f, 0x8f, 0x26, 0x69, 0x16, 0xf4, - 0x80, 0x3f, 0xfb, 0xd1, 0x16, 0xf0, 0xfa, 0x0f, 0x07, 0xd1, 0x8d, 0x42, - 0x28, 0xbf, 0x00, 0xf1, 0x08, 0x05, 0x45, 0x60, 0x01, 0x3b, 0x13, 0xb1, - 0xda, 0xe7, 0x00, 0x21, 0x41, 0x60, 0x30, 0x46, 0x00, 0xbe, 0x01, 0x00, - 0x00, 0x00 +#include "../../../contrib/loaders/flash/stm32/stm32l4x.inc" }; if (target_alloc_working_area(target, sizeof(stm32l4_flash_write_code), diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index f4dd686aa..c68d7c243 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -448,10 +448,8 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff int retval = ERROR_OK; - /* see contib/loaders/flash/stm32lx.S for src */ - static const uint8_t stm32lx_flash_write_code[] = { - 0x92, 0x00, 0x8A, 0x18, 0x01, 0xE0, 0x08, 0xC9, 0x08, 0xC0, 0x91, 0x42, 0xFB, 0xD1, 0x00, 0xBE +#include "../../../contrib/loaders/flash/stm32/stm32lx.inc" }; /* Make sure we're performing a half-page aligned write. */ From 4440bf1fcddce3501781496e2d6a9d0f12cba08d Mon Sep 17 00:00:00 2001 From: Bohdan Tymkiv Date: Wed, 21 Mar 2018 16:13:28 +0200 Subject: [PATCH 24/30] psoc6: Run flash algorithm asynchronously to improve performance Existing psoc6 driver starts flash algorithm for each Flash row. This is suboptimal from performance point of view, starting/stopping flash algorithm for each row adds significant overhead. This change starts flash algorithm and leaves it running asynchronously while driver performs flash operations. Performance gain is 170...250% depending on probe: flash write_image img_256k.bin | w/o this change | with this change | ----------------------------------|-----------------|------------------| KitProg2/CMSIS-DAP, SWD @ 1 MHz | 4 KiB/s | 10 KiB/s | J-Link Ultra, SWD @ 1 MHz | 17 KiB/s | 31 KiB/s | J-Link Ultra, SWD @ 4 MHz | 33 KiB/s | 57 KiB/s | Change-Id: I5bd582584b35af67600c4d197829eb7aeeec7e3f Signed-off-by: Bohdan Tymkiv Reviewed-on: http://openocd.zylin.com/4472 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/flash/nor/psoc6.c | 363 +++++++++++++++++++++++++----------------- tcl/target/psoc6.cfg | 17 +- 2 files changed, 237 insertions(+), 143 deletions(-) diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c index e5c419764..9352ad41b 100644 --- a/src/flash/nor/psoc6.c +++ b/src/flash/nor/psoc6.c @@ -1,6 +1,6 @@ /*************************************************************************** * * - * Copyright (C) 2017 by Bohdan Tymkiv * + * Copyright (C) 2018 by Bohdan Tymkiv * * bohdan.tymkiv@cypress.com bohdan200@gmail.com * * * * This program is free software; you can redistribute it and/or modify * @@ -101,7 +101,7 @@ struct row_region { size_t size; }; -static struct row_region safe_sflash_regions[] = { +static const struct row_region safe_sflash_regions[] = { {0x16000800, 0x800}, /* SFLASH: User Data */ {0x16001A00, 0x200}, /* SFLASH: NAR */ {0x16005A00, 0xC00}, /* SFLASH: Public Key */ @@ -111,8 +111,12 @@ static struct row_region safe_sflash_regions[] = { #define SFLASH_NUM_REGIONS (sizeof(safe_sflash_regions) / sizeof(safe_sflash_regions[0])) static struct working_area *g_stack_area; -/************************************************************************************************** - * Initializes timeout_s structure with given timeout in milliseconds +static struct armv7m_algorithm g_armv7m_info; + +/** *********************************************************************************************** + * @brief Initializes `struct timeout` structure with given timeout value + * @param to pointer to `struct timeout` structure + * @param timeout_ms timeout, in milliseconds *************************************************************************************************/ static void timeout_init(struct timeout *to, long timeout_ms) { @@ -120,17 +124,23 @@ static void timeout_init(struct timeout *to, long timeout_ms) to->timeout_ms = timeout_ms; } -/************************************************************************************************** - * Returns true if given timeout_s object has expired +/** *********************************************************************************************** + * @brief Returns true if given `struct timeout` structure has expired + * @param to pointer to `struct timeout` structure + * @return true if timeout expired *************************************************************************************************/ static bool timeout_expired(struct timeout *to) { return (timeval_ms() - to->start_time) > to->timeout_ms; } -/************************************************************************************************** - * Prepares PSoC6 for running pseudo flash algorithm. This function allocates Working Area for - * the algorithm and for CPU Stack. +/** *********************************************************************************************** + * @brief Starts pseudo flash algorithm and leaves it running. Function allocates working area for + * algorithm code and CPU stack, adjusts stack pointer, uploads and starts the algorithm. + * Algorithm (a basic infinite loop) runs asynchronously while driver performs Flash operations. + * + * @param target target for the algorithm + * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int sromalgo_prepare(struct target *target) { @@ -141,21 +151,42 @@ static int sromalgo_prepare(struct target *target) if (hr != ERROR_OK) return hr; + /* Restore THUMB bit in xPSR register */ + const struct armv7m_common *cm = target_to_armv7m(target); + hr = cm->store_core_reg_u32(target, ARMV7M_xPSR, 0x01000000); + if (hr != ERROR_OK) + return hr; + /* Allocate Working Area for Stack and Flash algorithm */ hr = target_alloc_working_area(target, RAM_STACK_WA_SIZE, &g_stack_area); if (hr != ERROR_OK) return hr; - /* Restore THUMB bit in xPSR register */ - const struct armv7m_common *cm = target_to_armv7m(target); - hr = cm->store_core_reg_u32(target, ARMV7M_xPSR, 0x01000000); + g_armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + g_armv7m_info.core_mode = ARM_MODE_THREAD; + + struct reg_param reg_params; + init_reg_param(®_params, "sp", 32, PARAM_OUT); + buf_set_u32(reg_params.value, 0, 32, g_stack_area->address + g_stack_area->size); + + /* Write basic infinite loop algorithm to target RAM */ + hr = target_write_u32(target, g_stack_area->address, 0xFEE7FEE7); if (hr != ERROR_OK) - goto exit_free_wa; + goto destroy_rp_free_wa; - return ERROR_OK; + hr = target_start_algorithm(target, 0, NULL, 1, ®_params, g_stack_area->address, + 0, &g_armv7m_info); + if (hr != ERROR_OK) + goto destroy_rp_free_wa; + + destroy_reg_param(®_params); + + return hr; + +destroy_rp_free_wa: + /* Something went wrong, do some cleanup */ + destroy_reg_param(®_params); -exit_free_wa: - /* Something went wrong, free allocated area */ if (g_stack_area) { target_free_working_area(target, g_stack_area); g_stack_area = NULL; @@ -164,65 +195,48 @@ exit_free_wa: return hr; } -/************************************************************************************************** - * Releases working area +/** *********************************************************************************************** + * @brief Stops running flash algorithm and releases associated resources. + * This function is also used for cleanup in case of errors so g_stack_area may be NULL. + * These cases have to be handled gracefully. + * + * @param target current target *************************************************************************************************/ -static int sromalgo_release(struct target *target) +static void sromalgo_release(struct target *target) { int hr = ERROR_OK; - /* Free Stack/Flash algorithm working area */ if (g_stack_area) { - hr = target_free_working_area(target, g_stack_area); + /* Stop flash algorithm if it is running */ + if (target->running_alg) { + hr = target_halt(target); + if (hr != ERROR_OK) + goto exit_free_wa; + + hr = target_wait_algorithm(target, 0, NULL, 0, NULL, 0, + IPC_TIMEOUT_MS, &g_armv7m_info); + if (hr != ERROR_OK) + goto exit_free_wa; + } + +exit_free_wa: + /* Free Stack/Flash algorithm working area */ + target_free_working_area(target, g_stack_area); g_stack_area = NULL; } - - return hr; } -/************************************************************************************************** - * Runs pseudo flash algorithm. Algorithm itself consist of couple of NOPs followed by BKPT - * instruction. The trick here is that NMI has already been posted to CM0 via IPC structure - * prior to calling this function. CM0 will immediately jump to NMI handler and execute - * SROM API code. - * This approach is borrowed from PSoC4 Flash Driver. - *************************************************************************************************/ -static int sromalgo_run(struct target *target) -{ - int hr; - - struct armv7m_algorithm armv7m_info; - armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; - armv7m_info.core_mode = ARM_MODE_THREAD; - - struct reg_param reg_params; - init_reg_param(®_params, "sp", 32, PARAM_OUT); - buf_set_u32(reg_params.value, 0, 32, g_stack_area->address + g_stack_area->size); - - /* mov r8, r8; mov r8, r8 */ - hr = target_write_u32(target, g_stack_area->address + 0, 0x46C046C0); - if (hr != ERROR_OK) - return hr; - - /* mov r8, r8; bkpt #0 */ - hr = target_write_u32(target, g_stack_area->address + 4, 0xBE0046C0); - if (hr != ERROR_OK) - return hr; - - hr = target_run_algorithm(target, 0, NULL, 1, ®_params, g_stack_area->address, - 0, SROMAPI_CALL_TIMEOUT_MS, &armv7m_info); - - destroy_reg_param(®_params); - - return hr; -} - -/************************************************************************************************** - * Waits for expected IPC lock status. - * PSoC6 uses IPC structures for inter-core communication. Same IPCs are used to invoke SROM API. - * IPC structure must be locked prior to invoking any SROM API. This ensures nothing else in the - * system will use same IPC thus corrupting our data. Locking is performed by ipc_acquire(), this - * function ensures that IPC is actually in expected state +/** *********************************************************************************************** + * @brief Waits for expected IPC lock status. PSoC6 uses IPC structures for inter-core + * communication. Same IPCs are used to invoke SROM API. IPC structure must be locked prior to + * invoking any SROM API. This ensures nothing else in the system will use same IPC thus corrupting + * our data. Locking is performed by ipc_acquire(), this function ensures that IPC is actually + * in expected state + * + * @param target current target + * @param ipc_id IPC index to poll. IPC #2 is dedicated for DAP access + * @param lock_expected expected lock status + * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int ipc_poll_lock_stat(struct target *target, uint32_t ipc_id, bool lock_expected) { @@ -258,11 +272,15 @@ static int ipc_poll_lock_stat(struct target *target, uint32_t ipc_id, bool lock_ return ERROR_TARGET_TIMEOUT; } -/************************************************************************************************** - * Acquires IPC structure - * PSoC6 uses IPC structures for inter-core communication. Same IPCs are used to invoke SROM API. - * IPC structure must be locked prior to invoking any SROM API. This ensures nothing else in the - * system will use same IPC thus corrupting our data. This function locks the IPC. +/** *********************************************************************************************** + * @brief Acquires IPC structure. PSoC6 uses IPC structures for inter-core communication. + * Same IPCs are used to invoke SROM API. IPC structure must be locked prior to invoking any SROM API. + * This ensures nothing else in the system will use same IPC thus corrupting our data. + * This function locks the IPC. + * + * @param target current target + * @param ipc_id ipc_id IPC index to acquire. IPC #2 is dedicated for DAP access + * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int ipc_acquire(struct target *target, char ipc_id) { @@ -303,8 +321,14 @@ static int ipc_acquire(struct target *target, char ipc_id) return hr; } -/************************************************************************************************** - * Invokes SROM API functions which are responsible for Flash operations +/** *********************************************************************************************** + * @brief Invokes SROM API functions which are responsible for Flash operations + * + * @param target current target + * @param req_and_params requect id of the function to invoke + * @param working_area address of memory buffer in target's memory space for SROM API parameters + * @param data_out pointer to variable which will be populated with execution status + * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int call_sromapi(struct target *target, uint32_t req_and_params, @@ -336,10 +360,6 @@ static int call_sromapi(struct target *target, if (hr != ERROR_OK) return hr; - hr = sromalgo_run(target); - if (hr != ERROR_OK) - return hr; - /* Poll lock status */ hr = ipc_poll_lock_stat(target, IPC_ID, false); if (hr != ERROR_OK) @@ -365,8 +385,12 @@ static int call_sromapi(struct target *target, return ERROR_OK; } -/************************************************************************************************** - * Retrieves SiliconID and Protection status of the target device +/** *********************************************************************************************** + * @brief Retrieves SiliconID and Protection status of the target device + * @param target current target + * @param si_id pointer to variable, will be populated with SiliconID + * @param protection pointer to variable, will be populated with protection status + * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int get_silicon_id(struct target *target, uint32_t *si_id, uint8_t *protection) { @@ -375,17 +399,17 @@ static int get_silicon_id(struct target *target, uint32_t *si_id, uint8_t *prote hr = sromalgo_prepare(target); if (hr != ERROR_OK) - return hr; + goto exit; /* Read FamilyID and Revision */ hr = call_sromapi(target, SROMAPI_SIID_REQ_FAMILY_REVISION, 0, &family_rev); if (hr != ERROR_OK) - return hr; + goto exit; /* Read SiliconID and Protection */ hr = call_sromapi(target, SROMAPI_SIID_REQ_SIID_PROTECTION, 0, &siid_prot); if (hr != ERROR_OK) - return hr; + goto exit; *si_id = (siid_prot & 0x0000FFFF) << 16; *si_id |= (family_rev & 0x00FF0000) >> 8; @@ -393,12 +417,15 @@ static int get_silicon_id(struct target *target, uint32_t *si_id, uint8_t *prote *protection = (siid_prot & 0x000F0000) >> 0x10; - hr = sromalgo_release(target); - return hr; +exit: + sromalgo_release(target); + return ERROR_OK; } -/************************************************************************************************** - * Translates Protection status to openocd-friendly boolean value +/** *********************************************************************************************** + * @brief Translates Protection status to openocd-friendly boolean value + * @param bank current flash bank + * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_protect_check(struct flash_bank *bank) { @@ -429,8 +456,9 @@ static int psoc6_protect_check(struct flash_bank *bank) return ERROR_OK; } -/************************************************************************************************** - * Life Cycle transition is not currently supported +/** *********************************************************************************************** + * @brief Dummy function, Life Cycle transition is not currently supported + * @return ERROR_OK always *************************************************************************************************/ static int psoc6_protect(struct flash_bank *bank, int set, int first, int last) { @@ -443,8 +471,10 @@ static int psoc6_protect(struct flash_bank *bank, int set, int first, int last) return ERROR_OK; } -/************************************************************************************************** - * Translates Protection status to string +/** *********************************************************************************************** + * @brief Translates Protection status to string + * @param protection protection value + * @return pointer to const string describintg protection status *************************************************************************************************/ static const char *protection_to_str(uint8_t protection) { @@ -468,8 +498,12 @@ static const char *protection_to_str(uint8_t protection) } } -/************************************************************************************************** - * Displays human-readable information about acquired device +/** *********************************************************************************************** + * @brief psoc6_get_info Displays human-readable information about acquired device + * @param bank current flash bank + * @param buf pointer to buffer for human-readable text + * @param buf_size size of the buffer + * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_get_info(struct flash_bank *bank, char *buf, int buf_size) { @@ -494,8 +528,10 @@ static int psoc6_get_info(struct flash_bank *bank, char *buf, int buf_size) return ERROR_OK; } -/************************************************************************************************** - * Returns true if flash bank name represents Supervisory Flash +/** *********************************************************************************************** + * @brief Checks if given flash bank belongs to Supervisory Flash + * @param bank current flash bank + * @return true if flash bank belongs to Supervisory Flash *************************************************************************************************/ static bool is_sflash_bank(struct flash_bank *bank) { @@ -507,27 +543,33 @@ static bool is_sflash_bank(struct flash_bank *bank) return false; } -/************************************************************************************************** - * Returns true if flash bank name represents Work Flash +/** *********************************************************************************************** + * @brief Checks if given flash bank belongs to Work Flash + * @param bank current flash bank + * @return true if flash bank belongs to Work Flash *************************************************************************************************/ static inline bool is_wflash_bank(struct flash_bank *bank) { return (bank->base == MEM_BASE_WFLASH); } -/************************************************************************************************** - * Returns true if flash bank name represents Main Flash +/** *********************************************************************************************** + * @brief Checks if given flash bank belongs to Main Flash + * @param bank current flash bank + * @return true if flash bank belongs to Main Flash *************************************************************************************************/ static inline bool is_mflash_bank(struct flash_bank *bank) { return (bank->base == MEM_BASE_MFLASH); } -/************************************************************************************************** - * Probes the device and populates related data structures with target flash geometry data. +/** *********************************************************************************************** + * @brief Probes the device and populates related data structures with target flash geometry data. * This is done in non-intrusive way, no SROM API calls are involved so GDB can safely attach to a - * running target. - * Function assumes that size of Work Flash is 32kB (true for all current part numbers) + * running target. Function assumes that size of Work Flash is 32kB (true for all current part numbers) + * + * @param bank current flash bank + * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_probe(struct flash_bank *bank) { @@ -595,8 +637,10 @@ static int psoc6_probe(struct flash_bank *bank) return hr; } -/************************************************************************************************** - * Probes target device only if it hasn't been probed yet +/** *********************************************************************************************** + * @brief Probes target device only if it hasn't been probed yet + * @param bank current flash bank + * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_auto_probe(struct flash_bank *bank) { @@ -611,8 +655,12 @@ static int psoc6_auto_probe(struct flash_bank *bank) return hr; } -/************************************************************************************************** - * Erases single sector (256k) on target device +/** *********************************************************************************************** + * @brief Erases single sector (256k) on target device + * @param bank current flash bank + * @param wa working area for SROM API parameters + * @param addr starting address of the sector + * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_erase_sector(struct flash_bank *bank, struct working_area *wa, uint32_t addr) { @@ -636,8 +684,12 @@ static int psoc6_erase_sector(struct flash_bank *bank, struct working_area *wa, return hr; } -/************************************************************************************************** - * Erases single row (512b) on target device +/** *********************************************************************************************** + * @brief Erases single row (512b) on target device + * @param bank current flash bank + * @param wa working area for SROM API parameters + * @param addr starting address of the flash row + * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_erase_row(struct flash_bank *bank, struct working_area *wa, uint32_t addr) { @@ -661,9 +713,14 @@ static int psoc6_erase_row(struct flash_bank *bank, struct working_area *wa, uin return hr; } -/************************************************************************************************** - * Performs Erase operation. - * Function will try to use biggest erase block possible to speedup the operation +/** *********************************************************************************************** + * @brief Performs Erase operation. Function will try to use biggest erase block possible to + * speedup the operation. + * + * @param bank current flash bank + * @param first first sector to erase + * @param last last sector to erase + * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_erase(struct flash_bank *bank, int first, int last) { @@ -681,7 +738,7 @@ static int psoc6_erase(struct flash_bank *bank, int first, int last) hr = sromalgo_prepare(target); if (hr != ERROR_OK) - return hr; + goto exit; hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa); if (hr != ERROR_OK) @@ -720,9 +777,13 @@ exit: return hr; } - -/************************************************************************************************** - * Programs single Flash Row +/** *********************************************************************************************** + * @brief Programs single Flash Row + * @param bank current flash bank + * @param addr address of the flash row + * @param buffer pointer to the buffer with data + * @param is_sflash true if current flash bank belongs to Supervisory Flash + * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_program_row(struct flash_bank *bank, uint32_t addr, @@ -773,9 +834,13 @@ exit: return hr; } - -/************************************************************************************************** - * Programs set of Rows +/** *********************************************************************************************** + * @brief Performs Program operation + * @param bank current flash bank + * @param buffer pointer to the buffer with data + * @param offset starting offset in falsh bank + * @param count number of bytes in buffer + * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ static int psoc6_program(struct flash_bank *bank, const uint8_t *buffer, @@ -787,11 +852,11 @@ static int psoc6_program(struct flash_bank *bank, const bool is_sflash = is_sflash_bank(bank); int hr; + uint8_t page_buf[psoc6_info->row_sz]; + hr = sromalgo_prepare(target); if (hr != ERROR_OK) - return hr; - - uint8_t page_buf[psoc6_info->row_sz]; + goto exit; while (count) { uint32_t row_offset = offset % psoc6_info->row_sz; @@ -804,7 +869,7 @@ static int psoc6_program(struct flash_bank *bank, hr = psoc6_program_row(bank, aligned_addr, page_buf, is_sflash); if (hr != ERROR_OK) { LOG_ERROR("Failed to program Flash at address 0x%08X", aligned_addr); - break; + goto exit; } buffer += row_bytes; @@ -812,13 +877,15 @@ static int psoc6_program(struct flash_bank *bank, count -= row_bytes; } - hr = sromalgo_release(target); +exit: + sromalgo_release(target); return hr; } -/************************************************************************************************** - * Performs Mass Erase of given flash bank - * Syntax: psoc6 mass_erase bank_id +/** *********************************************************************************************** + * @brief Performs Mass Erase operation + * @param bank flash bank index to erase + * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ COMMAND_HANDLER(psoc6_handle_mass_erase_command) { @@ -835,13 +902,16 @@ COMMAND_HANDLER(psoc6_handle_mass_erase_command) return hr; } -/************************************************************************************************** - * Simulates broken Vector Catch +/** *********************************************************************************************** + * @brief Simulates broken Vector Catch * Function will try to determine entry point of user application. If it succeeds it will set HW * breakpoint at that address, issue SW Reset and remove the breakpoint afterwards. * In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will * reset CM4 anyway, so using SYSRESETREQ is safe here. * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core. + * + * @param target current target + * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ int handle_reset_halt(struct target *target) { @@ -889,33 +959,42 @@ int handle_reset_halt(struct target *target) const struct armv7m_common *cm = target_to_armv7m(target); + /* PSoC6 reboots immediatelly after issuing SYSRESETREQ / VECTRESET + * this disables SWD/JTAG pins momentarily and may break communication + * Ignoring return value of mem_ap_write_atomic_u32 seems to be ok here */ if (is_cm0) { /* Reset the CM0 by asserting SYSRESETREQ. This will also reset CM4 */ LOG_INFO("psoc6.cm0: bkpt @0x%08X, issuing SYSRESETREQ", reset_addr); - hr = mem_ap_write_atomic_u32(cm->debug_ap, - NVIC_AIRCR, - AIRCR_VECTKEY | AIRCR_SYSRESETREQ); - - /* Wait for bootcode and initialize DAP */ - usleep(3000); - dap_dp_init(cm->debug_ap->dap); + mem_ap_write_atomic_u32(cm->debug_ap, NVIC_AIRCR, + AIRCR_VECTKEY | AIRCR_SYSRESETREQ); } else { LOG_INFO("psoc6.cm4: bkpt @0x%08X, issuing VECTRESET", reset_addr); - hr = mem_ap_write_atomic_u32(cm->debug_ap, - NVIC_AIRCR, - AIRCR_VECTKEY | AIRCR_VECTRESET); - if (hr != ERROR_OK) - return hr; + mem_ap_write_atomic_u32(cm->debug_ap, NVIC_AIRCR, + AIRCR_VECTKEY | AIRCR_VECTRESET); } + /* Wait 100ms for bootcode and reinitialize DAP */ + usleep(100000); + dap_dp_init(cm->debug_ap->dap); + target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS); /* Remove the break point */ breakpoint_remove(target, reset_addr); - return hr; + return ERROR_OK; } +/** *********************************************************************************************** + * @brief Simulates broken Vector Catch + * Function will try to determine entry point of user application. If it succeeds it will set HW + * breakpoint at that address, issue SW Reset and remove the breakpoint afterwards. + * In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will + * reset CM4 anyway, so using SYSRESETREQ is safe here. + * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core. + * + * @return ERROR_OK in case of success, ERROR_XXX code otherwise + *************************************************************************************************/ COMMAND_HANDLER(psoc6_handle_reset_halt) { if (CMD_ARGC) @@ -945,7 +1024,7 @@ static const struct command_registration psoc6_exec_command_handlers[] = { .name = "mass_erase", .handler = psoc6_handle_mass_erase_command, .mode = COMMAND_EXEC, - .usage = NULL, + .usage = "bank", .help = "Erases entire Main Flash", }, { diff --git a/tcl/target/psoc6.cfg b/tcl/target/psoc6.cfg index ad9aba569..fc0c71159 100644 --- a/tcl/target/psoc6.cfg +++ b/tcl/target/psoc6.cfg @@ -82,19 +82,30 @@ proc psoc6_deassert_post { target } { $target arp_examine global RESET_MODE + global TARGET + if { $RESET_MODE ne "run" } { $target arp_poll $target arp_poll set st [$target curstate] + if { $st eq "reset" } { # we assume running state follows # if reset accidentally halts, waiting is useless catch { $target arp_waitstate running 100 } set st [$target curstate] } + if { $st eq "running" } { echo "$target: Ran after reset and before halt..." - $target arp_halt + if { $target eq "${TARGET}.cm0" } { + # Try to cleanly reset whole system + # and halt the CM0 at entry point + psoc6 reset_halt + $target arp_waitstate halted 100 + } else { + $target arp_halt + } } } } @@ -133,3 +144,7 @@ if { $_ENABLE_CM0 } { # Use CM0+ by default on dual-core devices targets ${TARGET}.cm0 } + +if {[using_jtag]} { + swj_newdap $_CHIPNAME bs -irlen 18 -expected-id 0x2e200069 +} From 087a162e3c64f1bd67543d0c8c902bd70044b1af Mon Sep 17 00:00:00 2001 From: Faisal Shah Date: Mon, 9 Apr 2018 22:46:45 -0500 Subject: [PATCH 25/30] ChibiOS thread states: Update thread state to label mapping Fixed style issue. Removed #define with list of strings, and just put the strings in the array initialization directly. Removed empty space at the start of line. Change-Id: I76580be203d7d69b8c5b5440f820156543e0d5cc Signed-off-by: Faisal Shah Reviewed-on: http://openocd.zylin.com/4488 Tested-by: jenkins Reviewed-by: Freddie Chopin Reviewed-by: Tomas Vanek --- src/rtos/ChibiOS.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/rtos/ChibiOS.c b/src/rtos/ChibiOS.c index a46f7a492..312fc4d99 100644 --- a/src/rtos/ChibiOS.c +++ b/src/rtos/ChibiOS.c @@ -69,10 +69,9 @@ struct ChibiOS_chdebug { /** * @brief ChibiOS thread states. */ -static const char * const ChibiOS_thread_states[] = { - "READY", "CURRENT", "SUSPENDED", "WTSEM", "WTMTX", "WTCOND", "SLEEPING", - "WTEXIT", "WTOREVT", "WTANDEVT", "SNDMSGQ", "SNDMSG", "WTMSG", "WTQUEUE", - "FINAL" +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 *)) From aba11ae6e2b63129512473906816d2051becf285 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 10 Feb 2018 15:08:26 +0100 Subject: [PATCH 26/30] doc: fix several typos in openocd.texi Mostly trivial fixes spotted by spell checker One fix s/are/is/ No changes in the content of the document Change-Id: Ic2d8696860c540e901e8c5190f8f1e7dce80545f Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4402 Tested-by: jenkins Reviewed-by: Tomas Vanek --- doc/openocd.texi | 150 +++++++++++++++++++++++------------------------ 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index a47244607..3944572d2 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -578,7 +578,7 @@ produced, PDF schematics are easily found and it is easy to make. @url{http://www.latticesemi.com/lit/docs/@/devtools/dlcable.pdf} @item @b{flashlink} -@* From ST Microsystems; +@* From STMicroelectronics; @* Link: @url{http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATA_BRIEF/DM00039500.pdf} @end itemize @@ -1036,7 +1036,7 @@ that the @code{reset-init} event handler does. Likewise, the @command{arm9 vector_catch} command (or @cindex vector_catch its siblings @command{xscale vector_catch} -and @command{cortex_m vector_catch}) can be a timesaver +and @command{cortex_m vector_catch}) can be a time-saver during some debug sessions, but don't make everyone use that either. Keep those kinds of debugging aids in your user config file, along with messaging and tracing setup. @@ -1127,7 +1127,7 @@ handling issues like: @itemize @bullet @item @b{Watchdog Timers}... -Watchog timers are typically used to automatically reset systems if +Watchdog timers are typically used to automatically reset systems if some application task doesn't periodically reset the timer. (The assumption is that the system has locked up if the task can't run.) When a JTAG debugger halts the system, that task won't be able to run @@ -1464,7 +1464,7 @@ While the default is normally provided by the chip manufacturer, board files may need to distinguish between instances of a chip. @item @code{ENDIAN} ... By default @option{little} - although chips may hard-wire @option{big}. -Chips that can't change endianness don't need to use this variable. +Chips that can't change endianess don't need to use this variable. @item @code{CPUTAPID} ... When OpenOCD examines the JTAG chain, it can be told verify the chips against the JTAG IDCODE register. @@ -1875,9 +1875,9 @@ Target config files can either be ``linear'' (script executed line-by-line when configuration stage, @xref{configurationstage,,Configuration Stage},) or they can contain a special procedure called @code{init_targets}, which will be executed when entering run stage (after parsing all config files or after @code{init} command, @xref{enteringtherunstage,,Entering the Run Stage}.) -Such procedure can be overriden by ``next level'' script (which sources the original). -This concept faciliates code reuse when basic target config files provide generic configuration -procedures and @code{init_targets} procedure, which can then be sourced and enchanced or changed in +Such procedure can be overridden by ``next level'' script (which sources the original). +This concept facilitates code reuse when basic target config files provide generic configuration +procedures and @code{init_targets} procedure, which can then be sourced and enhanced or changed in a ``more specific'' target config file. This is not possible with ``linear'' config scripts, because sourcing them executes every initialization commands they provide. @@ -2053,7 +2053,7 @@ Once OpenOCD has entered the run stage, a number of commands become available. A number of these relate to the debug targets you may have declared. For example, the @command{mww} command will not be available until -a target has been successfuly instantiated. +a target has been successfully instantiated. If you want to use those commands, you may need to force entry to the run stage. @@ -2213,7 +2213,7 @@ The default behaviour is @option{enable}. @end deffn @deffn {Command} gdb_save_tdesc -Saves the target descripton file to the local file system. +Saves the target description file to the local file system. The file name is @i{target_name}.xml. @end deffn @@ -2424,7 +2424,7 @@ Engine) mode built into many FTDI chips, such as the FT2232, FT4232 and FT232H. The driver is using libusb-1.0 in asynchronous mode to talk to the FTDI device, bypassing intermediate libraries like libftdi or D2XX. -Support for new FTDI based adapters can be added competely through +Support for new FTDI based adapters can be added completely through configuration files, without the need to patch and rebuild OpenOCD. The driver uses a signal abstraction to enable Tcl configuration files to @@ -2552,7 +2552,7 @@ Get the value of a previously defined signal. Configure TCK edge at which the adapter samples the value of the TDO signal Due to signal propagation delays, sampling TDO on rising TCK can become quite -peculiar at high JTAG clock speeds. However, FTDI chips offer a possiblity to sample +peculiar at high JTAG clock speeds. However, FTDI chips offer a possibility to sample TDO on falling edge of TCK. With some board/adapter configurations, this may increase stability at higher JTAG clocks. @itemize @minus @@ -2702,7 +2702,7 @@ SEGGER J-Link family of USB adapters. It currently supports JTAG and SWD transports. @quotation Compatibility Note -SEGGER released many firmware versions for the many harware versions they +SEGGER released many firmware versions for the many hardware versions they produced. OpenOCD was extensively tested and intended to run on all of them, but some combinations were reported as incompatible. As a general recommendation, it is advisable to use the latest firmware version @@ -2970,10 +2970,10 @@ This is a driver that supports multiple High Level Adapters. This type of adapter does not expose some of the lower level api's that OpenOCD would normally use to access the target. -Currently supported adapters include the ST STLINK and TI ICDI. -STLINK firmware version >= V2.J21.S4 recommended due to issues with earlier +Currently supported adapters include the ST ST-LINK and TI ICDI. +ST-LINK firmware version >= V2.J21.S4 recommended due to issues with earlier versions of firmware where serial number is reset after first use. Suggest -using ST firmware update utility to upgrade STLINK firmware even if current +using ST firmware update utility to upgrade ST-LINK firmware even if current version reported is V2.J21.S4. @deffn {Config Command} {hla_device_desc} description @@ -3131,7 +3131,7 @@ Parameters are currently the same as "jtag newtap" but this is expected to change. @end deffn @deffn Command {swd wcr trn prescale} -Updates TRN (turnaraound delay) and prescaling.fields of the +Updates TRN (turnaround delay) and prescaling.fields of the Wire Control Register (WCR). No parameters: displays current settings. @end deffn @@ -3433,7 +3433,7 @@ haven't seen hardware with such a bug, and can be worked around). @item The @var{gates} tokens control flags that describe some cases where -JTAG may be unvailable during reset. +JTAG may be unavailable during reset. @option{srst_gates_jtag} (default) indicates that asserting SRST gates the JTAG clock. This means that no communication can happen on JTAG @@ -3472,7 +3472,7 @@ Possible @var{srst_type} driver modes for the system reset signal (SRST) are the default @option{srst_open_drain}, and @option{srst_push_pull}. Most boards connect this signal to a pullup, and allow the signal to be pulled low by various events including system -powerup and pressing a reset button. +power-up and pressing a reset button. @end itemize @end deffn @@ -3641,7 +3641,7 @@ That declaration order must match the order in the JTAG scan chain, both inside a single chip and between them. @xref{faqtaporder,,FAQ TAP Order}. -For example, the ST Microsystems STR912 chip has +For example, the STMicroelectronics STR912 chip has three separate TAPs@footnote{See the ST document titled: @emph{STR91xFAxxx, Section 3.15 Jtag Interface, Page: 28/102, Figure 3: JTAG chaining inside the STR91xFA}. @@ -4278,7 +4278,7 @@ To avoid being confused by the variety of ARM based cores, remember this key point: @emph{ARM is a technology licencing company}. (See: @url{http://www.arm.com}.) The CPU name used by OpenOCD will reflect the CPU design that was -licenced, not a vendor brand which incorporates that design. +licensed, not a vendor brand which incorporates that design. Name prefixes like arm7, arm9, arm11, and cortex reflect design generations; while names like ARMv4, ARMv5, ARMv6, ARMv7 and ARMv8 @@ -4327,7 +4327,7 @@ On more complex chips, the work area can become inaccessible when application code (such as an operating system) enables or disables the MMU. -For example, the particular MMU context used to acess the virtual +For example, the particular MMU context used to access the virtual address will probably matter ... and that context might not have easy access to other addresses needed. At this writing, OpenOCD doesn't have much MMU intelligence. @@ -4744,7 +4744,7 @@ bank'', and the GDB flash features be enabled. @xref{gdbconfiguration,,GDB Configuration}. @end enumerate -Many CPUs have the ablity to ``boot'' from the first flash bank. +Many CPUs have the ability to ``boot'' from the first flash bank. This means that misprogramming that bank can ``brick'' a system, so that it can't boot. JTAG tools, like OpenOCD, are often then used to ``de-brick'' the @@ -4821,7 +4821,7 @@ but most don't bother. @anchor{flashprogrammingcommands} One feature distinguishing NOR flash from NAND or serial flash technologies -is that for read access, it acts exactly like any other addressible memory. +is that for read access, it acts exactly like any other addressable memory. This means you can use normal memory read commands like @command{mdw} or @command{dump_image} with it, with no special @command{flash} subcommands. @xref{memoryaccess,,Memory access}, and @ref{imageaccess,,Image access}. @@ -4838,7 +4838,7 @@ chips consume target address space. They implicitly refer to the current JTAG target, and map from an address in that target's address space back to a flash bank. @comment In May 2009, those mappings may fail if any bank associated -@comment with that target doesn't succesfuly autoprobe ... bug worth fixing? +@comment with that target doesn't successfully autoprobe ... bug worth fixing? A few commands use abstract addressing based on bank and sector numbers, and don't depend on searching the current target and its address space. Avoid confusing the two command models. @@ -4984,7 +4984,7 @@ See @command{flash info} for a list of protection blocks. @deffn Command {flash padded_value} num value Sets the default value used for padding any image sections, This should normally match the flash bank erased value. If not specified by this -comamnd or the flash driver then it defaults to 0xff. +command or the flash driver then it defaults to 0xff. @end deffn @anchor{program} @@ -5011,8 +5011,8 @@ The @var{virtual} driver defines one mandatory parameters, @end itemize So in the following example addresses 0xbfc00000 and 0x9fc00000 refer to -the flash bank defined at address 0x1fc00000. Any cmds executed on -the virtual banks are actually performed on the physical banks. +the flash bank defined at address 0x1fc00000. Any command executed on +the virtual banks is actually performed on the physical banks. @example flash bank $_FLASHNAME pic32mx 0x1fc00000 0 0 0 $_TARGETNAME flash bank vbank0 virtual 0xbfc00000 0 0 0 \ @@ -5047,7 +5047,7 @@ like AM29LV010 and similar types. @item @var{x16_as_x8} ... when a 16-bit flash is hooked up to an 8-bit bus. @item @var{bus_swap} ... when data bytes in a 16-bit flash needs to be swapped. @item @var{data_swap} ... when data bytes in a 16-bit flash needs to be -swapped when writing data values (ie. not CFI commands). +swapped when writing data values (i.e. not CFI commands). @end itemize To configure two adjacent banks of 16 MBytes each, both sixteen bits (two bytes) @@ -5184,7 +5184,7 @@ flash bank $_FLASHNAME lpcspifi 0x14000000 0 0 0 $_TARGETNAME @cindex STMicroelectronics Serial Memory Interface @cindex SMI @cindex stmsmi -Some devices form STMicroelectronics (e.g. STR75x MCU family, +Some devices from STMicroelectronics (e.g. STR75x MCU family, SPEAr MPU family) include a proprietary ``Serial Memory Interface'' (SMI) controller able to drive external SPI flash devices. @@ -5284,7 +5284,7 @@ with the target using SWD. The @var{ambiqmicro} driver reads the Chip Information Register detect the device class of the MCU. -The Flash and Sram sizes directly follow device class, and are used +The Flash and SRAM sizes directly follow device class, and are used to set up the flash banks. If this fails, the driver will use default values set to the minimum sizes of an Apollo chip. @@ -5315,8 +5315,8 @@ Erase device pages. @end deffn @deffn Command {ambiqmicro program_otp} Program OTP is a one time operation to create write protected flash. -The user writes sectors to sram starting at 0x10000010. -Program OTP will write these sectors from sram to flash, and write protect +The user writes sectors to SRAM starting at 0x10000010. +Program OTP will write these sectors from SRAM to flash, and write protect the flash. @end deffn @end deffn @@ -5326,7 +5326,7 @@ the flash. @cindex at91samd All members of the ATSAMD, ATSAMR, ATSAML and ATSAMC microcontroller families from Atmel include internal flash and use ARM's Cortex-M0+ core. -This driver uses the same cmd names/syntax as @xref{at91sam3}. +This driver uses the same command names/syntax as @xref{at91sam3}. @deffn Command {at91samd chip-erase} Issues a complete Flash erase via the Device Service Unit (DSU). This can be @@ -5351,7 +5351,7 @@ Shows or sets the EEPROM emulation size configuration, stored in the User Row of the Flash. When setting, the EEPROM size must be specified in bytes and it must be one of the permitted sizes according to the datasheet. Settings are written immediately but only take effect on MCU reset. EEPROM emulation -requires additional firmware support and the minumum EEPROM size may not be +requires additional firmware support and the minimum EEPROM size may not be the same as the minimum that the hardware supports. Set the EEPROM size to 0 in order to disable this feature. @@ -5411,7 +5411,7 @@ currently (6/22/09) recognizes the AT91SAM3U[1/2/4][C/E] chips. Note that the driver was orginaly developed and tested using the AT91SAM3U4E, using a SAM3U-EK eval board. Support for other chips in the family was cribbed from the data sheet. @emph{Note to future -readers/updaters: Please remove this worrysome comment after other +readers/updaters: Please remove this worrisome comment after other chips are confirmed.} The AT91SAM3U4[E/C] (256K) chips have two flash banks; most other chips @@ -5471,14 +5471,14 @@ This command shows/sets the slow clock frequency used in the @cindex at91sam4 All members of the AT91SAM4 microcontroller family from Atmel include internal flash and use ARM's Cortex-M4 core. -This driver uses the same cmd names/syntax as @xref{at91sam3}. +This driver uses the same command names/syntax as @xref{at91sam3}. @end deffn @deffn {Flash Driver} at91sam4l @cindex at91sam4l All members of the AT91SAM4L microcontroller family from Atmel include internal flash and use ARM's Cortex-M4 core. -This driver uses the same cmd names/syntax as @xref{at91sam3}. +This driver uses the same command names/syntax as @xref{at91sam3}. The AT91SAM4L driver adds some additional commands: @deffn Command {at91sam4l smap_reset_deassert} @@ -5492,7 +5492,7 @@ Command is used internally in event event reset-deassert-post. @cindex atsamv All members of the ATSAMV, ATSAMS, and ATSAME families from Atmel include internal flash and use ARM's Cortex-M7 core. -This driver uses the same cmd names/syntax as @xref{at91sam3}. +This driver uses the same command names/syntax as @xref{at91sam3}. @end deffn @deffn {Flash Driver} at91sam7 @@ -5877,7 +5877,7 @@ lpc2900 read_custom 0 /path_to/customer_info.bin The index sector of the flash is a @emph{write-only} sector. It cannot be erased! In order to guard against unintentional write access, all following -commands need to be preceeded by a successful call to the @code{password} +commands need to be preceded by a successful call to the @code{password} command: @deffn Command {lpc2900 password} bank password @@ -5979,7 +5979,7 @@ Full erase, single and block writes are supported for both main and info regions There is additional not memory mapped flash called "Userflash", which also have division into regions: main and info. Purpose of userflash - to store system and user settings. -Driver has special commands to perform operations with this memmory. +Driver has special commands to perform operations with this memory. @example flash bank $_FLASHNAME niietcm4 0 0 0 0 $_TARGETNAME @@ -6183,7 +6183,7 @@ All members of the SiM3 microcontroller family from Silicon Laboratories include internal flash and use ARM Cortex-M3 cores. It supports both JTAG and SWD interface. The @var{sim3x} driver tries to probe the device to auto detect the MCU. -If this failes, it will use the @var{size} parameter as the size of flash bank. +If this fails, it will use the @var{size} parameter as the size of flash bank. @example flash bank $_FLASHNAME sim3x 0 $_CPUROMSIZE 0 0 $_TARGETNAME @@ -6505,7 +6505,7 @@ Standard driver @option{str9x} programmed via the str9 core. Normally used for flash programming as it is faster than the @option{str9xpec} driver. @item Direct programming @option{str9xpec} using the flash controller. This is an -ISC compilant (IEEE 1532) tap connected in series with the str9 core. The str9 +ISC compliant (IEEE 1532) tap connected in series with the str9 core. The str9 core does not need to be running to program using this flash driver. Typical use for this driver is locking/unlocking the target and programming the option bytes. @end enumerate @@ -6658,7 +6658,7 @@ geared for newer MLC chips may correct 4 or more errors for every 512 bytes of data. You will need to make sure that any data you write using -OpenOCD includes the apppropriate kind of ECC. For example, +OpenOCD includes the appropriate kind of ECC. For example, that may mean passing the @code{oob_softecc} flag when writing NAND data, or ensuring that the correct hardware ECC mode is used. @@ -6831,7 +6831,7 @@ if @command{nand raw_access} was used to disable hardware ECC. @itemize @bullet @item no oob_* parameter @*File has only page data, which is written. -If raw acccess is in use, the OOB area will not be written. +If raw access is in use, the OOB area will not be written. Otherwise, if the underlying NAND controller driver has a @code{write_page} routine, that routine may write the OOB with hardware-computed ECC data. @@ -6884,7 +6884,7 @@ can be compared against the contents produced from @command{nand dump}. @b{NOTE:} This will not work when the underlying NAND controller driver's @code{write_page} routine must update the OOB with a -hardward-computed ECC before the data is written. This limitation may +hardware-computed ECC before the data is written. This limitation may be removed in a future release. @end deffn @@ -7008,7 +7008,7 @@ in the MLC controller mode, but won't change SLC behavior. @deffn {NAND Driver} mx3 This driver handles the NAND controller in i.MX31. The mxc driver -should work for this chip aswell. +should work for this chip as well. @end deffn @deffn {NAND Driver} mxc @@ -7022,7 +7022,7 @@ main area and spare area (@option{biswap}), defaults to off. nand device mx35.nand mxc imx35.cpu mx35 hwecc biswap @end example @deffn Command {mxc biswap} bank_num [enable|disable] -Turns on/off bad block information swaping from main area, +Turns on/off bad block information swapping from main area, without parameter query status. @end deffn @end deffn @@ -7117,13 +7117,13 @@ Write the binary file @var{filename} to mflash bank @var{num}, starting at @chapter Flash Programming OpenOCD implements numerous ways to program the target flash, whether internal or external. -Programming can be acheived by either using GDB @ref{programmingusinggdb,,Programming using GDB}, -or using the cmds given in @ref{flashprogrammingcommands,,Flash Programming Commands}. +Programming can be achieved by either using GDB @ref{programmingusinggdb,,Programming using GDB}, +or using the commands given in @ref{flashprogrammingcommands,,Flash Programming Commands}. -@*To simplify using the flash cmds directly a jimtcl script is available that handles the programming and verify stage. +@*To simplify using the flash commands directly a jimtcl script is available that handles the programming and verify stage. OpenOCD will program/verify/reset the target and optionally shutdown. -The script is executed as follows and by default the following actions will be peformed. +The script is executed as follows and by default the following actions will be performed. @enumerate @item 'init' is executed. @item 'reset init' is called to reset and halt the target, any 'reset init' scripts are executed. @@ -7216,7 +7216,7 @@ Intent: @itemize @bullet @item @b{Source Of Commands} @* OpenOCD commands can occur in a configuration script (discussed -elsewhere) or typed manually by a human or supplied programatically, +elsewhere) or typed manually by a human or supplied programmatically, or via one of several TCP/IP Ports. @item @b{From the human} @@ -7384,7 +7384,7 @@ Also, it can't work until an interrupt is issued. A more complete workaround is to not use that operation while you work with a JTAG debugger. -Tasking environments generaly have idle loops where the body is the +Tasking environments generally have idle loops where the body is the @emph{wait for interrupt} operation. (On older cores, it is a coprocessor action; newer cores have a @option{wfi} instruction.) @@ -7552,7 +7552,7 @@ binary file named @var{filename}. @deffn Command {fast_load} Loads an image stored in memory by @command{fast_load_image} to the -current target. Must be preceeded by fast_load_image. +current target. Must be preceded by fast_load_image. @end deffn @deffn Command {fast_load_image} filename address [@option{bin}|@option{ihex}|@option{elf}|@option{s19}] @@ -7570,7 +7570,7 @@ separately. Load image from file @var{filename} to target memory offset by @var{address} from its load address. The file format may optionally be specified (@option{bin}, @option{ihex}, @option{elf}, or @option{s19}). -In addition the following arguments may be specifed: +In addition the following arguments may be specified: @var{min_addr} - ignore data below @var{min_addr} (this is w.r.t. to the target's load address + @var{address}) @var{max_length} - maximum number of bytes to load. @example @@ -7741,7 +7741,7 @@ Declares the ETM associated with @var{target}, and associates it with a given trace port @var{driver}. @xref{traceportdrivers,,Trace Port Drivers}. Several of the parameters must reflect the trace port capabilities, -which are a function of silicon capabilties (exposed later +which are a function of silicon capabilities (exposed later using @command{etm info}) and of what hardware is connected to that port (such as an external pod, or ETB). The @var{width} must be either 4, 8, or 16, @@ -8063,7 +8063,7 @@ Supervisor Call vector by OpenOCD. @deffn Command {arm semihosting_cmdline} [@option{enable}|@option{disable}] @cindex ARM semihosting -Set the command line to be passed to the debuggee. +Set the command line to be passed to the debugger. @example arm semihosting_cmdline argv0 argv1 argv2 ... @@ -8274,7 +8274,7 @@ mini-IC is marked valid, which makes the CPU fetch all exception handlers from the mini-IC, ignoring the code in RAM. To address this situation, OpenOCD provides the @code{xscale -vector_table} command, which allows the user to explicity write +vector_table} command, which allows the user to explicitly write individual entries to either the high or low vector table stored in the mini-IC. @@ -8675,7 +8675,7 @@ otherwise fallback to @option{vectreset}. @end itemize Using @option{vectreset} is a safe option for all current Cortex-M cores. This however has the disadvantage of only resetting the core, all peripherals -are uneffected. A solution would be to use a @code{reset-init} event handler to manually reset +are unaffected. A solution would be to use a @code{reset-init} event handler to manually reset the peripherals. @xref{targetevents,,Target Events}. @end deffn @@ -9125,7 +9125,7 @@ Command options: @item @option{-tap @var{tapname}} ignore IR and DR headers and footers specified by the SVF file with HIR, TIR, HDR and TDR commands; instead, calculate them automatically according to the current JTAG -chain configuration, targetting @var{tapname}; +chain configuration, targeting @var{tapname}; @item @option{[-]quiet} do not log every command before execution; @item @option{[-]nil} ``dry run'', i.e., do not perform any operations on the real interface; @@ -9690,18 +9690,18 @@ holds one of the following values: @itemize @bullet @item @b{cygwin} Running under Cygwin -@item @b{darwin} Darwin (Mac-OS) is the underlying operating sytem. +@item @b{darwin} Darwin (Mac-OS) is the underlying operating system. @item @b{freebsd} Running under FreeBSD @item @b{openbsd} Running under OpenBSD @item @b{netbsd} Running under NetBSD -@item @b{linux} Linux is the underlying operating sytem +@item @b{linux} Linux is the underlying operating system @item @b{mingw32} Running under MingW32 @item @b{winxx} Built using Microsoft Visual Studio @item @b{ecos} Running under eCos @item @b{other} Unknown, none of the above. @end itemize -Note: 'winxx' was choosen because today (March-2009) no distinction is made between Win32 and Win64. +Note: 'winxx' was chosen because today (March-2009) no distinction is made between Win32 and Win64. @quotation Note We should add support for a variable like Tcl variable @@ -9782,7 +9782,7 @@ See an example application here: @cindex adaptive clocking @* -In digital circuit design it is often refered to as ``clock +In digital circuit design it is often referred to as ``clock synchronisation'' the JTAG interface uses one clock (TCK or TCLK) operating at some speed, your CPU target is operating at another. The two clocks are not synchronised, they are ``asynchronous'' @@ -9910,7 +9910,7 @@ Make sure you have Cygwin installed, or at least a version of OpenOCD that claims to come with all the necessary DLLs. When using Cygwin, try launching OpenOCD from the Cygwin shell. -@item @b{Breakpoint Issue} I'm trying to set a breakpoint using GDB (or a frontend like Insight or +@item @b{Breakpoint Issue} I'm trying to set a breakpoint using GDB (or a front-end like Insight or Eclipse), but OpenOCD complains that "Info: arm7_9_common.c:213 arm7_9_add_breakpoint(): sw breakpoint requested, but software breakpoints not enabled". @@ -9950,7 +9950,7 @@ stackframes have been processed. By pushing zeros on the stack, GDB gracefully stops. @b{Debugging Interrupt Service Routines} - In your ISR before you call -your C code, do the same - artifically push some zeros onto the stack, +your C code, do the same - artificially push some zeros onto the stack, remember to pop them off when the ISR is done. @b{Also note:} If you have a multi-threaded operating system, they @@ -10026,8 +10026,8 @@ particular order? Yes; whenever you have more than one, you must declare them in the same order used by the hardware. -Many newer devices have multiple JTAG TAPs. For example: ST -Microsystems STM32 chips have two TAPs, a ``boundary scan TAP'' and +Many newer devices have multiple JTAG TAPs. For example: +STMicroelectronics STM32 chips have two TAPs, a ``boundary scan TAP'' and ``Cortex-M3'' TAP. Example: The STM32 reference manual, Document ID: RM0008, Section 26.5, Figure 259, page 651/681, the ``TDI'' pin is connected to the boundary scan TAP, which then connects to the @@ -10110,7 +10110,7 @@ those commands is the word ``for'', another command is ``if''. @section Per Rule #1 - All Results are strings Every Tcl command results in a string. The word ``result'' is used -deliberatly. No result is just an empty string. Remember: @i{Rule #1 - +deliberately. No result is just an empty string. Remember: @i{Rule #1 - Everything is a string} @section Tcl Quoting Operators @@ -10127,7 +10127,7 @@ three primary quoting constructs, the [square-brackets] the By now you should know $VARIABLES always start with a $DOLLAR sign. BTW: To set a variable, you actually use the command ``set'', as -in ``set VARNAME VALUE'' much like the ancient BASIC langauge ``let x +in ``set VARNAME VALUE'' much like the ancient BASIC language ``let x = 1'' statement, but without the equal sign. @itemize @bullet @@ -10173,7 +10173,7 @@ the normal way. As a script is parsed, each (multi) line in the script file is tokenised and according to the quoting rules. After tokenisation, that -line is immedatly executed. +line is immediately executed. Multi line statements end with one or more ``still-open'' @{curly-braces@} which - eventually - closes a few lines later. @@ -10244,7 +10244,7 @@ MyCommand( Jim_Interp *interp, @end example Real Tcl is nearly identical. Although the newer versions have -introduced a byte-code parser and intepreter, but at the core, it +introduced a byte-code parser and interpreter, but at the core, it still operates in the same basic way. @subsection FOR command implementation @@ -10257,7 +10257,7 @@ In Tcl there are two underlying C helper functions. Remember Rule #1 - You are a string. The @b{first} helper parses and executes commands found in an ascii -string. Commands can be seperated by semicolons, or newlines. While +string. Commands can be separated by semicolons, or newlines. While parsing, variables are expanded via the quoting rules. The @b{second} helper evaluates an ascii string as a numerical @@ -10352,7 +10352,7 @@ it reads a file and executes as a script. @} $_TARGETNAME configure -event FOO someproc #2 Good - no variables - $_TARGETNAME confgure -event foo "this ; that;" + $_TARGETNAME configure -event foo "this ; that;" #3 Good Curly Braces $_TARGETNAME configure -event FOO @{ puts "Time: [date]" @@ -10371,7 +10371,7 @@ command. @*There are 4 examples: @enumerate @item The TCLBODY is a simple string that happens to be a proc name -@item The TCLBODY is several simple commands seperated by semicolons +@item The TCLBODY is several simple commands separated by semicolons @item The TCLBODY is a multi-line @{curly-brace@} quoted string @item The TCLBODY is a string with variables that get expanded. @end enumerate From 7b94ae9e520877e7f2341b48b3bd0c0d1ca8a14b Mon Sep 17 00:00:00 2001 From: Philipp Tomsich Date: Fri, 27 Apr 2018 19:59:56 +0200 Subject: [PATCH 27/30] arm_dpm: flush both scratch registers (R0 and R1) Neither the initial loop to clear dirty registers (which visits all registers starting at R2 and counting upwards) nor the final explicit flushes ensure a write-back in arm_dpm_write_dirty_registers. This change makes sure that both our scratch registers (i.e. R0 and R1) are written back to the target. Change-Id: If65be4f371cd40af9a0cfa97f3730b070b92e981 Signed-off-by: Philipp Tomsich Reviewed-on: http://openocd.zylin.com/4506 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/arm_dpm.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index 65790995a..f9b30c187 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -587,11 +587,13 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) goto done; arm->pc->dirty = false; - /* flush R0 -- it's *very* dirty by now */ - retval = dpm_write_reg(dpm, &cache->reg_list[0], 0); - if (retval != ERROR_OK) - goto done; - cache->reg_list[0].dirty = false; + /* flush R0 and R1 (our scratch registers) */ + for (unsigned i = 0; i < 2; i++) { + retval = dpm_write_reg(dpm, &cache->reg_list[i], i); + if (retval != ERROR_OK) + goto done; + cache->reg_list[i].dirty = false; + } /* (void) */ dpm->finish(dpm); done: From f0767a316a11c03924322b96b8d3feae1fe99a34 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 10 Feb 2018 23:56:30 +0100 Subject: [PATCH 28/30] doc: fix several typos within manual documents Mostly trivial fixes spotted by spell checker Change-Id: I3af693faf5506c866e2abe253a0e37aea3c4d284 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4510 Tested-by: jenkins Reviewed-by: Christopher Head Reviewed-by: Matthias Welwarsky --- doc/manual/jtag/drivers/remote_bitbang.txt | 4 +- doc/manual/primer/autotools.txt | 2 +- doc/manual/primer/commands.txt | 2 +- doc/manual/primer/docs.txt | 2 +- doc/manual/primer/tcl.txt | 26 +++++------ doc/manual/release.txt | 8 ++-- doc/manual/scripting.txt | 2 +- doc/manual/server.txt | 36 ++++++++-------- doc/manual/style.txt | 8 ++-- doc/manual/target/mips.txt | 50 +++++++++++----------- doc/manual/target/notarm.txt | 2 +- 11 files changed, 71 insertions(+), 71 deletions(-) diff --git a/doc/manual/jtag/drivers/remote_bitbang.txt b/doc/manual/jtag/drivers/remote_bitbang.txt index 5a800479d..f394d736a 100644 --- a/doc/manual/jtag/drivers/remote_bitbang.txt +++ b/doc/manual/jtag/drivers/remote_bitbang.txt @@ -28,7 +28,7 @@ An additional function, quit, is added to the remote_bitbang interface to indicate there will be no more requests and the connection with the remote driver should be closed. -These five functions are encoded in ascii by assigning a single character to +These five functions are encoded in ASCII by assigning a single character to each possible request. The assignments are: B - Blink on @@ -48,6 +48,6 @@ each possible request. The assignments are: t - Reset 1 0 u - Reset 1 1 -The read response is encoded in ascii as either digit 0 or 1. +The read response is encoded in ASCII as either digit 0 or 1. */ diff --git a/doc/manual/primer/autotools.txt b/doc/manual/primer/autotools.txt index 9d9aada10..3471eacd7 100644 --- a/doc/manual/primer/autotools.txt +++ b/doc/manual/primer/autotools.txt @@ -123,7 +123,7 @@ implement new checks. The make distcheck command produces an archive of the project deliverables (using make dist) and verifies its -integrity for distribution by attemptng to use the package in the same +integrity for distribution by attempting to use the package in the same manner as a user. These checks includes the following steps: diff --git a/doc/manual/primer/commands.txt b/doc/manual/primer/commands.txt index 5f89d5062..a626f56b5 100644 --- a/doc/manual/primer/commands.txt +++ b/doc/manual/primer/commands.txt @@ -30,7 +30,7 @@ called (with the appropriate parameters), the @c CALL_COMMAND_HANDLER macro to pass any e as parameters to the following helper function: The subsequent blocks of code are a normal C function that can do -anything, so only complex commands deserve should use comamnd helper +anything, so only complex commands deserve should use command helper functions. In this respect, this example uses one to demonstrate how -- not when -- they should be used. diff --git a/doc/manual/primer/docs.txt b/doc/manual/primer/docs.txt index 504da7907..b1c053137 100644 --- a/doc/manual/primer/docs.txt +++ b/doc/manual/primer/docs.txt @@ -19,7 +19,7 @@ OpenOCD presently produces several kinds of documentation: - See @subpage primerlatex and @ref stylelatex. - The Manual: - Focuses on developing the OpenOCD software. - - Details the architecutre, driver interfaces, and processes. + - Details the architecture, driver interfaces, and processes. - Provides "full" coverage of C source code (work-in-progress). - Written using Doxygen C language conventions (i.e. in comments). - Created with 'make doxygen'. diff --git a/doc/manual/primer/tcl.txt b/doc/manual/primer/tcl.txt index 9be4a05e0..868a75ba0 100644 --- a/doc/manual/primer/tcl.txt +++ b/doc/manual/primer/tcl.txt @@ -125,7 +125,7 @@ There is some tricky things going on. =============== First, there is a "for" loop - at level 0 -{level 0 means: out side of a proc/function} +{level 0 means: outside of a procedure/function} This means it is evaluated when the file is parsed. @@ -151,9 +151,9 @@ The FOR command: 5) Goto Step 2. As show, each of these items are in {curly-braces}. This means they -are passed as they are - KEY-POINT: un evaluated to the FOR +are passed as they are - KEY-POINT: unevaluated to the FOR command. Think of it like escaping the backticks in Bash so that the -"under-lying" command can evaluate the contents. In this case, the FOR +"underlying" command can evaluate the contents. In this case, the FOR COMMAND. == END: SIDEBAR: About The FOR command == @@ -167,9 +167,9 @@ Format is like "sprintf". Because of the [brackets], it becomes what you think. But here's how: First - the line is parsed - for {braces}. In this case, there are -none. The, the parser looks for [brackets] and finds them. The, +none. Then, the parser looks for [brackets] and finds them. The parser then evaluates the contents of the [brackets], and replaces -them. It is alot this bash statement. +them. It is similar to this bash statement. EXPORT vn=`date` @@ -179,7 +179,7 @@ LINE 2 & 3 In line 1, we dynamically created a variable name. Here, we are assigning it a value. Lastly Line 3 we force the variable to be -global, not "local" the the "for command body" +global, not "local" within the "for command body" =============== The PROCS @@ -194,7 +194,7 @@ The (1) NAME of the function, a (2) LIST of parameters, and a (3) BODY Again, this is at "level 0" so it is a global function. (Yes, TCL supports local functions, you put them inside of a function} -You'll see in some cases, I nest [brackets] alot and in others I'm +You'll see in some cases, I nest [brackets] a lot and in others I'm lazy or wanted it to be more clear... it is a matter of choice. =============== @@ -224,7 +224,7 @@ All memory regions must have 2 things: RWX - the access ability. WIDTH - the accessible width. - ie: Some regions of memory are not 'word' + i.e.: Some regions of memory are not 'word' accessible. The function "address_info" - given an address should @@ -287,7 +287,7 @@ Notice this IF COMMAND - (not statement) is like this: error [format string...] } -The "IF" command expects either 2 params, or 4 params. +The "IF" command expects either 2 or 4 parameters. === Sidebar: About "commands" === @@ -317,7 +317,7 @@ You give CATCH 1 or 2 parameters. The 2nd (optional) is where to put the error message. CATCH returns 0 on success, 1 for failure. - The "![catch command]" is self explaintory. + The "![catch command]" is self explanatory. The 3rd parameter to IF must be exactly "else" or "elseif" [I lied @@ -341,7 +341,7 @@ exists. {the function: "proc_exists" does this} And - if it does - I call the function. -In "C" it is alot like using: 'sprintf()' to construct a function name +In "C" it is a lot like using: 'sprintf()' to construct a function name string, then using "dlopen()" and "dlsym()" to look it up - and get a function pointer - and calling the function pointer. @@ -380,7 +380,7 @@ Some assumptions: The "CHIP" file has defined some variables in a proper form. -ie: AT91C_BASE_US0 - for usart0, +i.e.: AT91C_BASE_US0 - for usart0, AT91C_BASE_US1 - for usart1 ... And so on ... @@ -394,7 +394,7 @@ looks like this: In this case, I'm trying to figure out what USARTs exist. Step 1 - is to determine if the NAME has been defined. -ie: Does AT91C_BASE_USx - where X is some number exist? +i.e.: Does AT91C_BASE_USx - where X is some number exist? The "info exists VARNAME" tells you if the variable exists. Then - inside the IF statement... There is another loop. This loop is the diff --git a/doc/manual/release.txt b/doc/manual/release.txt index 83f668f52..44de4464f 100644 --- a/doc/manual/release.txt +++ b/doc/manual/release.txt @@ -36,7 +36,7 @@ several important advantages compared to using the source repository were produced as part of creating the archive. -# Because they have been formally released by the project, users don't need to try a random work-in-process revision. Releasing - involves spending some time specifically on quality improvments, + involves spending some time specifically on quality improvements, including bugfixing source code and documentation. -# They provide developers with the flexibility needed to address larger issues, which sometimes involves temporary breakage. @@ -149,7 +149,7 @@ specific git revisions: 0.3.0-rc1-dev-00015-gf37c9b8-dirty -indicates a development tree based on git revison f37c9b8 +indicates a development tree based on git revision f37c9b8 (a truncated version of a SHA1 hash) with some non-git patches applied (the dirty tag). This information can be useful when tracking down bugs. @@ -385,7 +385,7 @@ git tag -m "The openocd-${PACKAGE_VERSION} release." "${PACKAGE_TAG}" - Last updates for the release, including the release tag (you will need to "git push --tags"). - Updates opening the merge window - - At this point, it's OK for commiters to start pushing changes + - At this point, it's OK for committers to start pushing changes which have been held off until the next release. (Any bugfixes to this release will be against a bug-fix release branch starting from the commit you tagged as this release, not mainline.) @@ -423,7 +423,7 @@ tools/release.sh --type=micro branch Both of these variations make automatic commits and tags in your repository, so you should be sure to run it on a cloned copy before -proceding with a live release. +proceeding with a live release. @subsection releasescriptopts Release Script Options diff --git a/doc/manual/scripting.txt b/doc/manual/scripting.txt index 783541caf..f8764e2d7 100644 --- a/doc/manual/scripting.txt +++ b/doc/manual/scripting.txt @@ -43,7 +43,7 @@ Default implementation of procedures in tcl/procedures.tcl. functions constitute the tcl api. flash_banks is such a low level tcl proc. "flash banks" is an example of a command that has human readable output. The human - readable output is expected to change inbetween versions + readable output is expected to change in between versions of OpenOCD. The output from flash_banks may not be in the preferred form for the client. The client then has two choices a) parse the output from flash_banks diff --git a/doc/manual/server.txt b/doc/manual/server.txt index 3c2fbd0e3..50fcac75e 100644 --- a/doc/manual/server.txt +++ b/doc/manual/server.txt @@ -29,7 +29,7 @@ write new code and creates a support nightmare. In many ways, people had talked about the need for some type of high-level interface to OpenOCD, because they only had two choices: - the ability to script: via an external program the actions of OpenOCD. -- the ablity to write a complex internal commands: native 'commands' +- the ability to write a complex internal commands: native 'commands' inside of OpenOCD was complicated. Fundamentally, the basic problem with both of those would be solved @@ -68,7 +68,7 @@ interfaces well with TCL. From there, the developers wanted to create an external front-end that would be @a very usable and that that @a any language could utilize, -allowing simple front-ends to be (a) cross-platform (b) languag +allowing simple front-ends to be (a) cross-platform (b) language agnostic, and (c) easy to develop and use. Simple ASCII protocols are easy. For example, HTTP, FTP (control), and @@ -76,7 +76,7 @@ SMTP are all text-based. All of these examples are widely and well-known, and they do not require high-speed or high-volume. They also support a high degree of interoperability with multiple systems. They are not human-centric protocols; more correctly, they are rigid, -terse, simple ASCII protocols that are emensely parsable by a script. +terse, simple ASCII protocols that are easily parsable by a script. Thus, the TCL server -- a 'machine' type socket interface -- was added with the hope was it would output simple "name-value" pair type @@ -95,25 +95,25 @@ and do things with it! A lot has been said about various "widigit-foo-gui-library is so wonderful". Please refer back to the domino and spider web problem of dependencies. Sure, you may well know the WhatEver-GUI library, but -most others will not (including the next contributer to OpenOCD). +most others will not (including the next contributor to OpenOCD). How do we solve that problem? For example, Cygwin can be painful, Cygwin GUI packages want X11 to be present, crossing the barrier between MinGW and Cygwin is painful, let alone getting the GUI front end to work on MacOS, and -Linux, yuck yuck yuck. Painful. very very painful. +Linux, yuck yuck yuck. Painful, very very painful. What works easier and is less work is what is already present in every platform? The answer: A web browser. In other words, OpenOCD could serve out embedded web pages via "localhost" to your browser. Long before OpenOCD had a TCL command line, Zylin AS built their ZY1000 -devince with a built-in HTTP server. Later, they were willing to both +device with a built-in HTTP server. Later, they were willing to both contribute and integrate most of that work into the main tree. @subsection serverdocsother Other Options Considered -What if a web browser is not acceptable ie: You want to write your own +What if a web browser is not acceptable i.e.: You want to write your own front gadget in Eclipse, or KDevelop, or PerlTK, Ruby, or what ever the latest and greatest Script De Jour is. @@ -134,7 +134,7 @@ taking over OpenOCD. His concern is and was: how do you debug something written in 2 different languages? A "SWIG" front-end is unlikely to help that situation. -@subsection serverdoccombined Combined: Socket & WebServer Benifits +@subsection serverdoccombined Combined: Socket & WebServer Benefits Seriously think about this question: What script language (or compiled language) today cannot talk directly to a socket? Every thing in the @@ -146,23 +146,23 @@ and serve it out via the embedded web server, could it - or something like it talk to the built in TCL server? Yes, absolutely! We are on to something here. -@subsection serverdocplatforms Platform Permuntations +@subsection serverdocplatforms Platform Permutations Look at some permutations where OpenOCD can run; these "just work" if the Socket Approach is used. -- Linux/Cygwin/MinGw/MacOSx/FreeBSD development Host Locally +- Linux/Cygwin/MinGW/MacOSX/FreeBSD development Host Locally - OpenOCD with some dongle on that host -- Linux/Cygwin/MingW/MacOS/FreeBSD development host -- DONGLE: tcpip based ARM-Linux perhaps at91rm9200 or ep93xx.c, running openocd. +- Linux/Cygwin/MinGW/MacOS/FreeBSD development host +- DONGLE: TCP/IP based ARM-Linux perhaps at91rm9200 or ep93xx.c, running openocd. -- Windows cygwin/X desktop environment. +- Windows Cygwin/X desktop environment. - Linux development host (via remote X11) -- Dongle: "eb93xx.c" based linux board +- Dongle: "eb93xx.c" based Linux board @subsection serverdocfuture Development Scale Out @@ -214,8 +214,8 @@ love or attention. Perhaps it will after you read and understand this. One reason might be, this adds one more host side requirement to make use of the feature. In other words, one could write a Python/TK front-end, but it is only useable if you have Python/TK installed. -Maybe this can be done via Ecllipse, but not all developers use Ecplise. -Many devlopers use Emacs (possibly with GUD mode) or vim and will not +Maybe this can be done via Eclipse, but not all developers use Eclipse. +Many developers use Emacs (possibly with GUD mode) or vim and will not accept such an interface. The next developer reading this might be using Insight (GDB-TK) - and somebody else - DDD.. @@ -260,7 +260,7 @@ OS) is another example. One could create a simple: Click here to display memory or maybe click here to display the UART REGISTER BLOCK; click again and see -each register explained in exquisit detail. +each register explained in exquisite detail. For an STM32, one could create a simple HTML page, with simple substitution text that the simple web server use to substitute the @@ -269,7 +269,7 @@ memory. We end up with an HTML page that could list the contents of every peripheral register on the target platform. That also is transportable, regardless of the OpenOCD host -platform: Linux/X86, Linux/ARM, FreeBSD, Cygwin, MingW, or MacOSX. +platform: Linux/X86, Linux/ARM, FreeBSD, Cygwin, MinGW, or MacOSX. You could even port OpenOCD to an Android system and use it as a bit-banging JTAG Adapter serving web pages. diff --git a/doc/manual/style.txt b/doc/manual/style.txt index 0bfae35f7..e654be9c3 100644 --- a/doc/manual/style.txt +++ b/doc/manual/style.txt @@ -112,7 +112,7 @@ pthreads require modest and predictable stack usage. @section stylefunc Functions -- static inline functions should be prefered over macros: +- static inline functions should be preferred over macros: @code /** do NOT define macro-like functions like this... */ #define CUBE(x) ((x) * (x) * (x)) @@ -201,7 +201,7 @@ The following guidelines apply to all Doxygen comment blocks: -# @c struct_name::member_name should be used to reference structure fields in the documentation (e.g. @c flash_driver::name). -# URLS get converted to markup automatically, without any extra effort. - -# new pages can be linked into the heirarchy by using the @c \@subpage + -# new pages can be linked into the hierarchy by using the @c \@subpage command somewhere the page(s) under which they should be linked: -# use @c \@ref in other contexts to create links to pages and sections. -# Use good Doxygen mark-up: @@ -233,7 +233,7 @@ documentation as part of standalone text files: - Doxygen creates such pages for files automatically, but no content will appear on them for those that only contain manual pages. - The \@file block should provide useful meta-documentation to assist - techincal writers; typically, a list of the pages that it contains. + technical writers; typically, a list of the pages that it contains. - For example, the @ref styleguide exists in @c doc/manual/style.txt, which contains a reference back to itself. -# The \@file and \@page commands should begin on the same line as @@ -261,7 +261,7 @@ The User's Guide is there to provide two basic kinds of information. It is a guide for how and why to use each feature or mechanism of OpenOCD. It is also the reference manual for all commands and options involved in using them, including interface, flash, target, and other drivers. -At this time, it is the only user-targetted documentation; everything +At this time, it is the only documentation for end users; everything else is addressing OpenOCD developers. There are two key audiences for the User's Guide, both developer based. diff --git a/doc/manual/target/mips.txt b/doc/manual/target/mips.txt index 32c40b986..5121d1276 100644 --- a/doc/manual/target/mips.txt +++ b/doc/manual/target/mips.txt @@ -46,14 +46,14 @@ This value is defined only when a processor access is pending. Processor will do the action for us : it can for example read internal state (register values), and send us back the information via EJTAG memory (dmseg), or it can take some data from dmseg and write it into the registers or RAM. -Every time when it sees address (i.e. when this address is the part of the opcode it is executing, wether it is instruction or data fetch) -that falls into dmseg, processor stalls. That acutally meand that CPU stops it's pipeline and it is waitning for dongle to take some action. +Every time when it sees address (i.e. when this address is the part of the opcode it is executing, whether it is instruction or data fetch) +that falls into dmseg, processor stalls. That actually means that CPU stops it's pipeline and it is waiting for dongle to take some action. CPU is now either waiting for dongle to take some data from dmseg (if we requested for CPU do give us internal state, for example), or it will wait for some data from dongle (if it needs following instruction because it did previous, or if the operand address of the currently executed opcode falls somewhere (anywhere) in dmseg (0xff..ff20000 - 0xff..ff2fffff)). -Bit PNnW describes character of CPU access to EJTAG memory (the memry where dongle puts/takes data) - CPU can either READ for it (PNnW == 0) or +Bit PNnW describes character of CPU access to EJTAG memory (the memory where dongle puts/takes data) - CPU can either READ for it (PNnW == 0) or WRITE to it (PNnW == 1). By reading PNnW bit OpenOCD will know if it has to send (PNnW == 0) or to take (PNnW == 1) data (from dmseg, via dongle). @@ -79,7 +79,7 @@ OpenOCD can figure out which action has to be taken by reading PrAcc bit. Once action from dongle has been done, i.e. after the data is taken/put, OpenOCD can signal to CPU to proceed with executing the instruction. This can be the next instruction (if previous was finished before pending), or the same instruction - if for example CPU was waiting on dongle -to give it an operand, because it saw in the instruction opcode that operand address is somewhere in dmseg. That prowoked the CPU to stall (it tried operand fetch to dmseg and stopped), +to give it an operand, because it saw in the instruction opcode that operand address is somewhere in dmseg. That provoked the CPU to stall (it tried operand fetch to dmseg and stopped), and PNnW bit is 0 (CPU does read from dmseg), and PrAcc is 1 (CPU is pending on dmseg access). @subsection spracc SPrAcc @@ -155,16 +155,16 @@ static const uint32_t code[] = { We have to pass this code to CPU via dongle via dmseg. -After debug exception CPU will find itself stalling at the begining of the dmseg. It waits for the first instruction from dongle. +After debug exception CPU will find itself stalling at the beginning of the dmseg. It waits for the first instruction from dongle. This is MIPS32_MTC0(15,31,0), so CPU saves C0 and continues to addr 0xFF20 0001, which falls also to dmseg, so it stalls. Dongle proceeds giving to CPU one by one instruction in this manner. However, things are not so simple. If you take a look at the program, you will see that some instructions take operands. If it has to take -operand from the address in dmseg, CPU will stall witing for the dongle to do the action of passing the operand and signal this by putting PrAcc to 0. -If this operand is somewhere in RAM, CPU will not stall (it stalls only on dmseg), but it will just take it and proceed to nex instruction. But since PC for next instruction +operand from the address in dmseg, CPU will stall waiting for the dongle to do the action of passing the operand and signal this by putting PrAcc to 0. +If this operand is somewhere in RAM, CPU will not stall (it stalls only on dmseg), but it will just take it and proceed to next instruction. But since PC for next instruction points to dmseg, it will stall, so that dongle can pass next instruction. -Some instuctions are jumps (if these are jumps in dmseg addr, CPU will jump and then stall. If this is jump to some address in RAM, CPU will jump and just proceed - +Some instructions are jumps (if these are jumps in dmseg addr, CPU will jump and then stall. If this is jump to some address in RAM, CPU will jump and just proceed - will not stall on addresses in RAM). To have information about CPU is currently (does it stalls wanting on operand or it jumped somewhere waiting for next instruction), @@ -213,10 +213,10 @@ else @endcode i.e. if CPU is stalling on addresses in dmseg that are reserved for input parameters, we can conclude that it actually tried to take (read) -parametar from there, and saw that address of param falls in dmseg, so it stopped. Obviously, now dongle have to give to it operand. +parameter from there, and saw that address of parameter falls in dmseg, so it stopped. Obviously, now dongle have to give to it operand. Similarly, mips32_pracc_exec_write() describes CPU writes into EJTAG memory (dmseg). -Obvioulsy, code is RO, and CPU can change only parameters : +Obviously, code is RO, and CPU can change only parameters : @code mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA); @@ -331,10 +331,10 @@ uint32_t handler_code[] = { }; @endcode -In the begining and the end of the handler we have fuction prologue (save the regs that will be clobbered) and epilogue (restore regs), +In the beginning and the end of the handler we have function prologue (save the regs that will be clobbered) and epilogue (restore regs), and in the very end, after all the xfer have been done, we do jump to the MIPS32_PRACC_TEXT address, i.e. Debug Exception Vector location. We will use this fact (that we came back to MIPS32_PRACC_TEXT) to verify later if all the handler is executed (because when in RAM, -processor do not stall - it executes all instructions untill one of them do not demand access to dmseg (if one of it's opernads is there)). +processor do not stall - it executes all instructions until one of them do not demand access to dmseg (if one of it's operands is there)). This handler is put into the RAM and executed from there, and not instruction by instruction, like in previous simple write (mips_m4k_write_memory()) and read (mips_m4k_read_memory()) functions. @@ -347,12 +347,12 @@ MIPS32_LW(9,0,8) /* start addr in t1 */ and there it will stall - because it will see that one of the operands have to be fetched from dmseg (EJTAG memory, in this case FASTDATA memory segment). -This handler is loaded in the RAM, ath the reserved location "work_area". This work_area is configured in OpenOCD configuration script and should be selected +This handler is loaded in the RAM, at the reserved location "work_area". This work_area is configured in OpenOCD configuration script and should be selected in that way that it is not clobbered (overwritten) by data we want to write-in using FASTDATA. What is executed instruction by instruction which is passed by dongle (via EJATG memory) is small jump code, which jumps at the handler in RAM. CPU stalls on dmseg when receiving these jmp_code instructions, but once it jumps in RAM, CPU do not stall anymore and executes bunch of handler instructions. -Untill it comes to the first instruction which has an operand in FASTDATA area. There it stalls and waits on action from probe. +Until it comes to the first instruction which has an operand in FASTDATA area. There it stalls and waits on action from probe. It happens actually when CPU comes to this loop : @code @@ -393,15 +393,15 @@ for (i = 0; i < count; i++) } @endcode -Each time when OpenOCD fills data to CPU (via dongle, via dmseg), CPU takes it and proceeds in executing the endler. However, since handler is in a assembly loop, +Each time when OpenOCD fills data to CPU (via dongle, via dmseg), CPU takes it and proceeds in executing the handler. However, since handler is in a assembly loop, CPU comes to next instruction which also fetches data from FASTDATA area. So it stalls. Then OpenOCD fills the data again, from it's (OpenOCD's) loop. And this game continues untill all the data has been filled. -After the last data has beend given to CPU it sees that it reached the end address, so it proceeds with next instruction. However, rhis instruction do not point into dmseg, so +After the last data has been given to CPU it sees that it reached the end address, so it proceeds with next instruction. However, this instruction do not point into dmseg, so CPU executes bunch of handler instructions (all prologue) and in the end jumps to MIPS32_PRACC_TEXT address. -On it's side, OpenOCD checks in CPU has jumped back to MIPS32_PRACC_TEXT, which is the confirmation that it correclty executed all the rest of the handler in RAM, -and that is not stuck somewhere in the RAM, or stalling on some acces in dmseg - that would be an error : +On it's side, OpenOCD checks in CPU has jumped back to MIPS32_PRACC_TEXT, which is the confirmation that it correctly executed all the rest of the handler in RAM, +and that is not stuck somewhere in the RAM, or stalling on some access in dmseg - that would be an error : @code address = 0; @@ -462,7 +462,7 @@ Download flow (probe -> target block transfer) : Note: A failure may have a recoverable (and even expected) cause like slow target execution of the load loop. Other failures may be due to unexpected more troublesome causes like an exception while in debug mode or a target hang on a bad target memory access. -Shifted out SPrAcc bit inform us that there was CPU access pendingand that it can be complete. +Shifted out SPrAcc bit inform us that there was CPU access pending and that it can be complete. Basically, we should do following procedure : @@ -497,7 +497,7 @@ by checking SPrAcc that we shifted out. If some FASTDATA write fails, OpenOCD will continue with it's loop (on the host side), but CPU will rest pending (on the target side) waiting for correct FASTDATA write. -Since OpenOCD goes ahead, it will eventually finish it's loop, and proceede to check if CPU took all the data. But since CPU did not took all the data, +Since OpenOCD goes ahead, it will eventually finish it's loop, and proceed to check if CPU took all the data. But since CPU did not took all the data, it is still turns in handler's loop in RAM, stalling on Fastdata area so this check : @code @@ -513,24 +513,24 @@ if (address != MIPS32_PRACC_TEXT) fails, and that gives us enough information of the failure. -In this case, we can lower the JTAG frquency and try again, bacuse most probable reason of this failure is that we tried FASTDATA upload before CPU arrived to rise PrAcc (i.e. before it was pending on access). +In this case, we can lower the JTAG frequency and try again, because most probable reason of this failure is that we tried FASTDATA upload before CPU arrived to rise PrAcc (i.e. before it was pending on access). However, the reasons for failure might be numerous : reset, exceptions which can occur in debug mode, bus hangs, etc. If lowering the JTAG freq does not work either, we can fall back to more robust solution with patch posted below. To summarize, FASTDATA communication goes as following : --# CPU jumps to Debug Exception Vector Location 0xFF200200 in dmseg and it stalls, pending and waiting for EJTAG to give it first debug instruction and signall it by putting PrAcc to "0" +-# CPU jumps to Debug Exception Vector Location 0xFF200200 in dmseg and it stalls, pending and waiting for EJTAG to give it first debug instruction and signal it by putting PrAcc to "0" -# When PrAcc goes to "0" CPU execute one opcode sent by EJTAG via DATA reg. Then it pends on next access, waiting for PrAcc to be put to "0" again -# Following this game, OpenOCD first loads handler code in RAM, and then sends the jmp_code - instruction by instruction via DATA reg, which redirects CPU to handler previously set up in RAM --# Once in RAM CPU does not pend on any instruction, but it executes all handler instructions untill first "fetch" to Fastdata area - then it stops and pends. +-# Once in RAM CPU does not pend on any instruction, but it executes all handler instructions until first "fetch" to Fastdata area - then it stops and pends. -# So - when it comes to any instruction (opcode) in this handler in RAM which reads (or writes) to Fastdata area (0xF..F20.0000 to 0xF..F20.000F), CPU stops (i.e. stalls access). I.e. it stops on this lw opcode and waits to FASTDATA TAP command from the probe. -# CPU continues only if OpenOCD shifted in SPrAcc "0" (and if the PrAcc was "1"). It shifts-out "1" to tell us that it was OK (processor was stalled, so it can complete the access), and that it continued execution of the handler in RAM. -# If PrAcc was not "1" CPU will not continue (go to next instruction), but will shift-out "0" and keep stalling on the same instruction of my handler in RAM. --# When Fastdata loop is finished, CPU executes all following hadler instructions in RAM (prologue). --# In the end of my handler in RAM, I jumps back to begining of Debug Exception Vector Location 0xFF200200 in dmseg. +-# When Fastdata loop is finished, CPU executes all following handler instructions in RAM (prologue). +-# In the end of my handler in RAM, I jumps back to beginning of Debug Exception Vector Location 0xFF200200 in dmseg. -# When it jumps back to 0xFF200200 in dmseg processor stops and pends, waiting for OpenOCD to send it instruction via DATA reg and signal it by putting PrAcc to "0". */ diff --git a/doc/manual/target/notarm.txt b/doc/manual/target/notarm.txt index 5d5be78c0..6de2c36b1 100644 --- a/doc/manual/target/notarm.txt +++ b/doc/manual/target/notarm.txt @@ -59,7 +59,7 @@ of the total OpenOCD system. @section targetnotarmppc PowerPC -there exists open source implementations of powerpc +there exists open source implementations of PowerPC target manipulation, but there hasn't been a lot of activity in the mailing list. From dae1ec1278fcac5369843b52db5eb12c2180d624 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Tue, 16 Jan 2018 09:24:27 +0100 Subject: [PATCH 29/30] configure.ac: Fix required libjaylink version Change-Id: I9ede86eeef8991db52ffa188ff293c14bd50a1f4 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4450 Tested-by: jenkins Reviewed-by: Paul Fertser --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 312fda8b2..11f80425d 100644 --- a/configure.ac +++ b/configure.ac @@ -659,7 +659,7 @@ PROCESS_ADAPTERS([USB0_ADAPTERS], ["x$use_libusb0" = "xyes"], [libusb-0.1]) PROCESS_ADAPTERS([HIDAPI_ADAPTERS], ["x$use_hidapi" = "xyes"], [hidapi]) PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libusb1" = "xyes"], [hidapi and libusb-1.x]) PROCESS_ADAPTERS([LIBFTDI_ADAPTERS], ["x$use_libftdi" = "xyes"], [libftdi]) -PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_internal_libjaylink" = "xyes" -o "x$use_libjaylink" = "xyes"], [libjaylink-0.1]) +PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_internal_libjaylink" = "xyes" -o "x$use_libjaylink" = "xyes"], [libjaylink-0.2]) AS_IF([test "x$build_openjtag" = "xyes"], [ AS_IF([test "x$use_libusb1" != "xyes" -a "x$use_libusb0" != "xyes"], [ From b50fa9a19d0b600d26b6cbca57cd94c7b89f941c Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Tue, 22 May 2018 12:04:31 +0300 Subject: [PATCH 30/30] Fix warnings exposed by GCC8 gcc (GCC) 8.1.0 generates new warnings and thus fails the build. The ARM disassembler warnings actually exposed a bug in SMALW, SMULW and SMUL instructions decoding. Reported by Eimers on IRC. Change-Id: I200c70f75a9e07a1f13a592addc1c5fb37714440 Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/4526 Tested-by: jenkins Reviewed-by: Jiri Kastner Reviewed-by: Antonio Borneo Reviewed-by: Matthias Welwarsky --- src/flash/nor/kinetis.c | 10 ++++++---- src/jtag/drivers/kitprog.c | 4 +--- src/target/arm_adi_v5.c | 2 ++ src/target/arm_disassembler.c | 6 +++--- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index 4d665d339..86fad7215 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -937,7 +937,7 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) unsigned num_blocks; struct kinetis_flash_bank *k_bank; struct flash_bank *bank; - char base_name[80], name[80], num[4]; + char base_name[69], name[80], num[4]; char *class, *p; num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks; @@ -948,7 +948,8 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) bank = k_chip->banks[0].bank; if (bank && bank->name) { - strncpy(base_name, bank->name, sizeof(base_name)); + strncpy(base_name, bank->name, sizeof(base_name) - 1); + base_name[sizeof(base_name) - 1] = '\0'; p = strstr(base_name, ".pflash"); if (p) { *p = '\0'; @@ -960,7 +961,8 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) } } } else { - strncpy(base_name, target_name(k_chip->target), sizeof(base_name)); + strncpy(base_name, target_name(k_chip->target), sizeof(base_name) - 1); + base_name[sizeof(base_name) - 1] = '\0'; p = strstr(base_name, ".cpu"); if (p) *p = '\0'; @@ -2012,7 +2014,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) unsigned cpu_mhz = 120; unsigned idx; bool use_nvm_marking = false; - char flash_marking[11], nvm_marking[2]; + char flash_marking[12], nvm_marking[2]; char name[40]; k_chip->probed = false; diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c index 522eb17bb..e3ad84d30 100644 --- a/src/jtag/drivers/kitprog.c +++ b/src/jtag/drivers/kitprog.c @@ -888,13 +888,11 @@ COMMAND_HANDLER(kitprog_handle_acquire_psoc_command) COMMAND_HANDLER(kitprog_handle_serial_command) { if (CMD_ARGC == 1) { - size_t len = strlen(CMD_ARGV[0]); - kitprog_serial = calloc(len + 1, sizeof(char)); + kitprog_serial = strdup(CMD_ARGV[0]); if (kitprog_serial == NULL) { LOG_ERROR("Failed to allocate memory for the serial number"); return ERROR_FAIL; } - strncpy(kitprog_serial, CMD_ARGV[0], len + 1); } else { LOG_ERROR("expected exactly one argument to kitprog_serial "); return ERROR_FAIL; diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index e2d9b5e66..d0a58bda0 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -152,6 +152,8 @@ static uint32_t mem_ap_get_tar_increment(struct adiv5_ap *ap) return 2; case CSW_32BIT: return 4; + default: + return 0; } case CSW_ADDRINC_PACKED: return 4; diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c index 8e783d342..17948d6da 100644 --- a/src/target/arm_disassembler.c +++ b/src/target/arm_disassembler.c @@ -1549,7 +1549,7 @@ static int evaluate_misc_instr(uint32_t opcode, } /* SMLAW < y> */ - if (((opcode & 0x00600000) == 0x00100000) && (x == 0)) { + if (((opcode & 0x00600000) == 0x00200000) && (x == 0)) { uint8_t Rd, Rm, Rs, Rn; instruction->type = ARM_SMLAWy; Rd = (opcode & 0xf0000) >> 16; @@ -1571,7 +1571,7 @@ static int evaluate_misc_instr(uint32_t opcode, } /* SMUL < x> */ - if ((opcode & 0x00600000) == 0x00300000) { + if ((opcode & 0x00600000) == 0x00600000) { uint8_t Rd, Rm, Rs; instruction->type = ARM_SMULxy; Rd = (opcode & 0xf0000) >> 16; @@ -1592,7 +1592,7 @@ static int evaluate_misc_instr(uint32_t opcode, } /* SMULW < y> */ - if (((opcode & 0x00600000) == 0x00100000) && (x == 1)) { + if (((opcode & 0x00600000) == 0x00200000) && (x == 1)) { uint8_t Rd, Rm, Rs; instruction->type = ARM_SMULWy; Rd = (opcode & 0xf0000) >> 16;