aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2018-08-20 14:55:30 -0700
committerGitHub <noreply@github.com>2018-08-20 14:55:30 -0700
commit2a69f1bd2f4f4c839f246ca81084ff8ab029739b (patch)
treea1ba4209ed4aab4885901b25e2c6da625adeb682 /src
parent684d7d67642ef2805e3c5c25e5183c055464213a (diff)
downloadriscv-openocd-2a69f1bd2f4f4c839f246ca81084ff8ab029739b.zip
riscv-openocd-2a69f1bd2f4f4c839f246ca81084ff8ab029739b.tar.gz
riscv-openocd-2a69f1bd2f4f4c839f246ca81084ff8ab029739b.tar.bz2
From upstream (#286)
* flash/nor: Add support for TI CC26xx/CC13xx flash Added cc26xx flash driver to support the TI CC26xx and CC13xx microcontrollers. Driver is capable of determining which MCU is connected and configures itself accordingly. Added config files for four specific variants: CC26x0, CC13x0, CC26x2, and CC13x2. Note that the flash loader code is based on the sources used to support flash in Code Composer Studio and Uniflash from TI. Removed cc26xx.cfg file made obsolete by this patch. Change-Id: Ie2b0f74f8af7517a9184704b839677d1c9787862 Signed-off-by: Edward Fewell <efewell@ti.com> Reviewed-on: http://openocd.zylin.com/4358 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-by: Fredrik Hederstierna <fredrik@hederstierna.com> * flash/nor/nrf5: remove is_erased setting and autoerase before write Cached flash erase state in sectors[].is_erased is not reliable as running target can change the flash. Autoerase was issued before flash write on condition is_erased != 1 Remove autoerase completely as it is a quite non-standard feature. Change-Id: I19bef459e6afdc4c5fcaa2ccd194cf05be8a42b6 Signed-off-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-on: http://openocd.zylin.com/4400 Tested-by: jenkins * src/flash/tms470: remove testing of sectors[].is_erased state The erase check routine checked sectors only if is_erased != 1 Check sector unconditionally. While on it fix clang static analyzer warnings. Change-Id: I9988615fd8530c55a9b0c54b1900f89b550345e9 Signed-off-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-on: http://openocd.zylin.com/4401 Tested-by: jenkins * tcl/target/stm32f7x: configure faster system clock in reset-init STM32F7xx devices need faster clock for flash programming over JTAG transport. Using reset default 16 MHz clock resulted in lot of DAP WAITs and substantial decrease of flashing performance. Adapted to the restructured dap support (see 2231da8ec4e7d7ae9b652f3dd1a7104f5a110f3f). Change-Id: Ida6915331dd924c9c0d08822fd94c04ad408cdc5 Signed-off-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-on: http://openocd.zylin.com/4464 Tested-by: jenkins Reviewed-by: Christopher Head <chead@zaber.com> * flash/nor/psoc5lp: fix compile issue on GCC 8.1.0 Issue already identified by Alex https://sourceforge.net/u/alexbour/ in ticket #191 https://sourceforge.net/p/openocd/tickets/191/ src/flash/nor/psoc5lp.c:237:2: error: ‘strncpy’ output truncated before terminating nul copying 2 bytes from a string of the same length [-Werror=stringop-truncation] Fix it by assigning the value to the array elements. Change-Id: I22468e5700efa64ea48ae8cdec930c48b4a7d8fb Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4563 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * target/arm: Add PLD command to ARM disassembler. Updates the ARM disassembler to handle PLD (PreLoad Data) commands. Previously handled by printing a TODO message. There are three forms of the command: literal, register, and immediate. Simply decode based off of the A1 encoding for the instructions in the ARM ARM. Also fixes mask to handle PLDW commands. Change-Id: I63bf97f16af254e838462c7cfac80f6c4681c556 Signed-off-by: James Marshall <jcmarsh@gwmail.gwu.edu> Reviewed-on: http://openocd.zylin.com/4348 Tested-by: jenkins Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com> * mips_m4k.c: Fix build with --disable-target64 Replace PRIx64 with TARGET_PRIxADDR to avoid build problems when --disable-target64 is used during configure. Change-Id: I054a27a491e86c42c9386a0488194320b808ba96 Signed-off-by: Liviu Ionescu <ilg@livius.net> Reviewed-on: http://openocd.zylin.com/4566 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-by: Tim Newsome <tim@sifive.com> * target/arm_adi_v5: sync CSW and TAR cache on apreg write When using apreg to change AP registers CSW or TAR we get internal cached value not valid anymore. Reuse the setup functions for CSW and TAR to write them. Invalidate the cached value before the call to force the write, thus keeping original apreg behaviour. Change-Id: Ib14fafd5e584345de94f2e983de55406c588ac1c Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4565 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * target/arm_adi_v5: keep CSW and TAR cache updated The call to dap_queue_ap_write() can fail and the value in CSW and TAR becomes unknown. Invalidate the OpenOCD cache if dap_queue_ap_write() fails. Change-Id: Id6ec370b4c5ad07e454464780c1a1c8ae34ac870 Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4564 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * tcl/target: Add Renesas R-Car R8A7794 E2 target Add configuration for the Renesas R-Car R8A7794 E2 target. This is an SoC with two Cortex A7 ARMv7a cores, both A7 cores are supported. Change-Id: Ic1c81840e3bfcef8ee1de5acedffae5c83612a5e Signed-off-by: Marek Vasut <marek.vasut@gmail.com> Reviewed-on: http://openocd.zylin.com/4531 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * tcl/board: Add Renesas R-Car R8A7790 H2 Stout board Add configuration for the Renesas R-Car R8A7790 H2 based Stout ADAS board. Change-Id: Ib880b5d2e1fab5c8c0bc0dbcedcdce8055463fe2 Signed-off-by: Marek Vasut <marek.vasut@gmail.com> Reviewed-on: http://openocd.zylin.com/4497 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * tcl/board: Add Renesas R-Car R8A7791 M2W Porter board Add configuration for the Renesas R-Car R8A7791 M2W based Porter evaluation board. Change-Id: Iaadb18f29748f890ebb68519ea9ddbd18e7649af Signed-off-by: Marek Vasut <marek.vasut@gmail.com> Reviewed-on: http://openocd.zylin.com/4498 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * tcl/board: Add Renesas R-Car R8A7794 E2 Silk board Add configuration for the Renesas R-Car R8A7794 E2 based Silk evaluation board. Change-Id: I504b5630b1a2791ed6967c6c2af8851ceef9723f Signed-off-by: Marek Vasut <marek.vasut@gmail.com> --- NOTE: This requires SW7[1] in position 1 (default is 0) Reviewed-on: http://openocd.zylin.com/4532 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * tcl/board: Factor out common R-Car Gen2 code Factor out the code shared by all R-Car Gen2 boards into a single file to get rid of the duplication. Change-Id: I70b302c2e71f4e6fdccb2817dd65a5493bb393d8 Signed-off-by: Marek Vasut <marek.vasut@gmail.com> Reviewed-on: http://openocd.zylin.com/4533 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * jtag/drivers/cmsis-dap: fix connect in cmsis_dap_swd_switch_seq() The proc cmsis_dap_swd_switch_seq() is part of the SWD API for this interface driver. It is valid only when the interface is used in SWD mode. In this proc there is the need to call, in sequence, first cmsis_dap_cmd_DAP_Disconnect() then cmsis_dap_cmd_DAP_Connect(). The latter call requires the connection mode as parameter, that inside cmsis_dap_swd_switch_seq() can only be CONNECT_SWD. The current implementation is not correct and in some cases can pass mode CONNECT_JTAG. Moreover, JTAG is optional in CMSIS-DAP and passing mode CONNECT_JTAG triggers an error with SWD-only interfaces. Use mode CONNECT_SWD in SWD specific cmsis_dap_swd_switch_seq(). Change-Id: Ib455bf5b69cb2a2d146a6c8875387b00c27a5690 Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4571 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * target/cortex_m: return error if breakpoint address is out of range If the "Flash Patch and Breakpoint" unit is rev.1 then it can only accept breakpoint addresses below 0x1FFFFFFF. Detailed info in "ARM v7-M Architecture Reference Manual", DDI0403E at chapter "C1.11 Flash Patch and Breakpoint unit". Print a message and return error if the address of hardware breakpoint cannot be handled by the breakpoint unit. Change-Id: I95c92b1f058f0dfc568bf03015f99e439b27c59b Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4535 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-by: Christopher Head <chead@zaber.com> * flash/nor/stm32: Report errors in wait_status_busy Flash operation errors that occur during algorithm programming are reported via the algorithm return value. However, Flash operation errors that occur during non-algorithm work (erasing, programming without a work area, programming the last non-multiple-of-32-bytes on an H7, etc.) generally end with a call to stm32x_wait_status_busy, which reads the status register and clears the error flags but fails to actually report that something went wrong should an error flag (other than WRPERR) be set. Return an error status from stm32x_wait_status_busy in those cases. Correct a log message accordingly. Change-Id: I09369ea5f924fe58833aec1f45e52320ab4aaf43 Signed-off-by: Christopher Head <chead@zaber.com> Reviewed-on: http://openocd.zylin.com/4519 Tested-by: jenkins Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk> Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * flash/nor/stm32: Eliminate working area leak On a specific early-return path, an allocated working area was not freed. Free it. Change-Id: I7c8fe51ff475f191624086996be1c77251780b77 Signed-off-by: Christopher Head <chead@zaber.com> Reviewed-on: http://openocd.zylin.com/4520 Tested-by: jenkins Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk> Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * flash/nor/stm32h7: Fix incorrect comment The name of the bit according to the reference manual is inconsistency error, not increment error. Change-Id: Ie3b73c0312db586e35519e03fd1a5cb225673d97 Signed-off-by: Christopher Head <chead@zaber.com> Reviewed-on: http://openocd.zylin.com/4521 Tested-by: jenkins Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk> * target: fix 'bp' command help message "asid" and "length" are separate arguments of the command. Put space between them. Change-Id: I36cfc1e3a01caafef4fc3b26972a0cc192b0b963 Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4511 Tested-by: jenkins Reviewed-by: Christopher Head <chead@zaber.com> Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * Add ARM v8 AArch64 semihosting support This patch implements semihosting support for AArch64. This picks code from previously submitted AArch64 semihosting support patch and rebases on top of reworked semihosting code. Tested in AArch64 mode on a Lemaker Hikey Board with NewLib and GDB. Change-Id: I228a38f1de24f79e49ba99d8514d822a28c2950b Signed-off-by: Omair Javaid <omair.javaid@linaro.org> Reviewed-on: http://openocd.zylin.com/4537 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * GDB fileIO stdout support This patch fixes gdb fileio support to allow gdb console to be used as stdout. Now we can do something like gdb <inferior file> (gdb) tar ext :3333 (gdb) load (gdb) monitor arm semihosting enable (gdb) monitor arm semihosting_fileio enable (gdb) continue Here: Output from inferior using puts, printf etc will be routed to gdb console. Change-Id: I9cb0dddda1de58038c84f5b035c38229828cd744 Signed-off-by: Omair Javaid <omair.javaid@linaro.org> Reviewed-on: http://openocd.zylin.com/4538 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * target: armv8: Avoid semihosting segfault on halt Avoid a NULL pointer dereference when halting an aarch64 core. Change-Id: I333d40475ab26e2f0dca5c27302a5fa4d817a12f Signed-off-by: Andreas Färber <afaerber@suse.de> Reviewed-on: http://openocd.zylin.com/4593 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * tcl: target: Add NXP LS1012A config As seen on the FRDM-LS1012A board. Change-Id: Ifc9074b3f7535167b9ded5f544501ec2879f5db7 Signed-off-by: Andreas Färber <afaerber@suse.de> Reviewed-on: http://openocd.zylin.com/4594 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * tcl: board: Add NXP Freedom FRDM-LS1012A config An update for the K20 CMSIS-DAP firmware can be found here: https://community.nxp.com/thread/387080?commentID=840141#comment-840141 Change-Id: I149d7f8610aa56daf1aeb95f14ee1bf88f7cb647 Signed-off-by: Andreas Färber <afaerber@suse.de> Reviewed-on: http://openocd.zylin.com/4595 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * gdb_server: only trigger once the event gdb-detach at gdb quit When GDB quits (e.g. with "quit" command) we first execute gdb_detach() to reply "OK" then, at GDB disconnect (either TCP or pipe connection type), we execute gdb_connection_closed(). In case GDB is killed or it crashes, OpenOCD only executes the latter when detects the disconnection. Both gdb_detach() and gdb_connection_closed() trigger the event TARGET_EVENT_GDB_DETACH thus getting it triggered twice on clean GDB quit. Do not trigger the event TARGET_EVENT_GDB_DETACH in gdb_detach() and let only gdb_connection_closed() to handle it. Change-Id: Iacf035c855b8b3e2239c1c0e259c279688b418ee Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4585 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * gdb_server: set current_target from connection's one In a multi-target environment we are supposed to have a single gdb server for each target (or for each group of targets within a SMP node). By default, the gdb attached to a server sends its command to the target (or to the SMP node targets) linked to that server. This is working fine for the normal gdb commands, but it is broken for the native OpenOCD commands executed through gdb "monitor" command. In the latter case, gdb "monitor" commands will be executed on the current target of OpenOCD configuration script (that is either the last target created or the target specified in a "targets" command). Fixed in gdb_new_connection() by replacing the current target in the connection's copy of command context. Change-Id: If7c8f2dce4a3138f0907d3000dd0b15e670cfa80 Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4586 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-by: Christopher Head <chead@zaber.com> * target/image: make i/j unsigned to avoid ubsan runtime error src/target/image.c:1055:15: runtime error: left shift of 128 by 24 places cannot be represented in type 'int' Change-Id: I322fd391cf3f242beffc8a274824763c8c5e69a4 Signed-off-by: Cody Schafer <openocd@codyps.com> Reviewed-on: http://openocd.zylin.com/4584 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-by: Christopher Head <chead@zaber.com> * target/stm32f7x: Clear stuck HSE clock with CSS Change-Id: Ica0025ea465910dd664ab546b66f4f25b271f1f5 Signed-off-by: Christopher Head <chead@zaber.com> Reviewed-on: http://openocd.zylin.com/4570 Tested-by: jenkins Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com> * psoc5lp: fix erase check, add free_driver_priv psoc5lp_erase_check() was not properly adapted to the new armv7m_blank_check_memory() in the hot fix 53376dbbede4f0bf42e724ff This change fixes handling of num_sectors in dependecy of ecc_enabled. Also add comments how ecc_enabled influences num_sectors. Add pointer to default_flash_free_driver_priv() to all psoc5lp flash drivers to keep valgrind happy. Change-Id: Ie1806538becd364fe0efb7a414f0fe6a84b2055b Signed-off-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-on: http://openocd.zylin.com/4569 Tested-by: jenkins * target: atmel samd10 xplained mini cortex m0+ on a tiny board, with an mEDBG (CMSIS-DAP) debug interface. Change-Id: Iaedfab578b4eb4aa2d923bd80f220f59b34e6ef9 Signed-off-by: Karl Palsson <karlp@tweak.net.au> Reviewed-on: http://openocd.zylin.com/3402 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * tcl/board: add SAMD11 Xplained Pro evaluation board Change-Id: Id996c4de6dc9f25f71424017bf07689fea7bd3af Signed-off-by: Peter Lawrence <majbthrd@gmail.com> Reviewed-on: http://openocd.zylin.com/4507 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * Adds SAMD11D14AU flash support. Corrects names of SAMD11D14AM and SAMD11D14ASS per datasheet. Change-Id: I8beb15d5376966a4f8d7de76bfb2cbda2db440dc Signed-off-by: Christopher Hoover <ch@murgatroid.com> Reviewed-on: http://openocd.zylin.com/4597 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * nds32: Avoid detected JTAG clock AICE2 doesn't support scan for the maximum clock frequency of JTAG chain. It will cause USB command timeout. Change-Id: I41d1e3be387b6ed5a4dd0be663385a5f053fbcf9 Signed-off-by: Hellosun Wu <wujiheng.tw@gmail.com> Reviewed-on: http://openocd.zylin.com/4292 Tested-by: jenkins Reviewed-by: Hsiangkai Wang <hsiangkai@gmail.com> Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * flash/nor/tcl: Distinguish between sectors and blocks in status messages Use the right word in flash protect command status messages based on whether the target bank defines num_prot_blocks. Minor message style tidy-up. Change-Id: I5f40fb5627422536ce737f242fbf80feafe7a1fc Signed-off-by: Dominik Peklo <dom.peklo@gmail.com> Reviewed-on: http://openocd.zylin.com/4573 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-by: Christopher Head <chead@zaber.com> * drivers: cmsis-dap: pull up common connect code Just a minor deduplication Change-Id: Idd256883e5f6d4bd4dcc18462dd5468991f507b3 Signed-off-by: Karl Palsson <karlp@tweak.net.au> Reviewed-on: http://openocd.zylin.com/3403 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * drivers: cmsis-dap: Print version info when available No need to wait until after connecting, might help diagnose part information by printing earlier. Change-Id: I51eb0d584be306baa811fbeb1ad6a604773e602c Signed-off-by: Karl Palsson <karlp@tweak.net.au> Reviewed-on: http://openocd.zylin.com/3404 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * flash/nor: add support for TI MSP432 devices Added msp432 flash driver to support the TI MSP432P4x and MSP432E4x microcontrollers. Implemented the flash algo helper as used in the TI debug and flash tools. This implemention supports the MSP432E4, Falcon, and Falcon 2M variants. The flash driver automatically detects the connected variant and configures itself appropriately. Added command to mass erase device for consistency with TI tools and added command to unlock the protected BSL region. Tested using MSP432E401Y, MSP432P401R, and MSP432P4111 LaunchPads. Tested with embedded XDS110 debug probe in CMSIS-DAP mode and with external SEGGER J-Link probe. Removed ti_msp432p4xx.cfg file made obsolete by this patch. Change-Id: I3b29d39ccc492524ef2c4a1733f7f9942c2684c0 Signed-off-by: Edward Fewell <efewell@ti.com> Reviewed-on: http://openocd.zylin.com/4153 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * flash/nor/at91sam4: fix sam4sa16c flash banks and its gpnvms count There was already a github fork that had this fixed, but as we try to use the latest, non-modified version of all software we use, I would like to have this fix in the next releases of OpenOCD so that if people uses $packagemanager, they will not have issues flashing the last part of the flash of sam4sa16c chips. Additionally, I've added some more logging related to the flash bank that was used, and the chip ID that was detected. Change-Id: I7ea5970105906e4560b727e46222ae9a91e41559 Signed-off-by: Erwin Oegema <blablaechthema@hotmail.com> Reviewed-on: http://openocd.zylin.com/4599 Reviewed-by: Tomas Vanek <vanekt@fbl.cz> Tested-by: jenkins * flash/nor/stm32lx: Add revision 'V' for STM32L1xx Cat.3 devices Change-Id: Ic92b0fb5b738af3bec79ae335876aa9e26f5f4cd Signed-off-by: Marc Schink <openocd-dev@marcschink.de> Reviewed-on: http://openocd.zylin.com/4600 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * Avoid null target->semihosting references. The new common semihosting code introduced a bug, in certain conditions target->semihosting was used without semihosting being initialised. The solution was to explicitly test for target->semihosting before dereferencing it. Change-Id: I4c83e596140c68fe4ab32e586e51f7e981a40798 Signed-off-by: Liviu Ionescu <ilg@livius.net> Reviewed-on: http://openocd.zylin.com/4603 Tested-by: jenkins Reviewed-by: Jonathan Larmour <jifl@eCosCentric.com> Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * nrf5: Add HWID 0x139 (52832 rev E0) Change-Id: I71b7471ccfcb8fcc6de30da57ce4165c7fb1f73f Signed-off-by: James Jacobsson <slowcoder@gmail.com> Reviewed-on: http://openocd.zylin.com/4604 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * target: Fix segfault for 'mem2array' Call 'mem2array' without arguments to reproduce the segmentation fault. Change-Id: I02bf46cc8bd317abbb721a8c75d7cbfac99eb34e Signed-off-by: Marc Schink <openocd-dev@marcschink.de> Reviewed-on: http://openocd.zylin.com/4534 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-by: Christopher Head <chead@zaber.com> * target/armv7m_trace: Fix typo in enum Change-Id: I6364ee5011ef2d55c59674e3b97504a285de0cb2 Signed-off-by: Marc Schink <openocd-dev@marcschink.de> Reviewed-on: http://openocd.zylin.com/3904 Tested-by: jenkins Reviewed-by: Paul Fertser <fercerpav@gmail.com> * target/armv7m_trace: Use prefix for enums Change-Id: I3f199e6053146a1094d96b98ea174b41bb021599 Signed-off-by: Marc Schink <openocd-dev@marcschink.de> Reviewed-on: http://openocd.zylin.com/3905 Tested-by: jenkins Reviewed-by: Paul Fertser <fercerpav@gmail.com> * target/aarch64: Call aarch64_init_debug_access() earlier in aarch64_deassert_reset() On Renesas R-Car, calling 'reset halt' and 'reset init' always made DAP inaccessible. Calling 'reset' and 'halt' seperatly worked fine. The only differences seems to be the point in time when aarch64_init_debug_access() is called. This patch aligns the behaviour. Change-Id: I2296c65e48414a7d9846f12a395e5eca315b49ca Signed-off-by: Dennis Ostermann <dennis.ostermann@renesas.com> Reviewed-on: http://openocd.zylin.com/4607 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * server: Improve signal handling under Linux Commit 5087a955 added custom signal handlers for the openocd server process. Before this commit, when openocd is run as a background process having the same controlling terminal as gdb, Control-C would be handled by gdb to stop target execution and return to the gdb prompt. However, after commit 5087a955, the SIGINT caused by pressing Control-C also terminates openocd, effectively crashing the debugging session. The only way to avoid this is run openocd in a different controling terminal or to detach openocd from its controlling terminal, thus losing all job control for the openocd process. This patch improves the server's handling of POSIX signals: 1) Keyboard generated signals (INT and QUIT) are ignored when server process has is no controlling terminal. 2) SIGHUP and SIGPIPE are handled to ensure that .quit functions for each interface are called if user's logs out of X session or there is a network failure. SIG_INT & SIG_QUIT still stop openocd when it is running in the foreground. Change-Id: I03ad645e62408fdaf4edc49a3550b89b287eda10 Signed-off-by: Brent Roman <genosensor@gmail.com> Signed-off-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-on: http://openocd.zylin.com/3963 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * armv7a: read ttbcr and ttb0/1 at every entry in debug state Commit bfc5c764df145f68835543119865eabe462e19c2 avoids reading ttbcr and ttb0/1 at every virt2phys translation by caching them, and it updates the cached values in armv7a_arch_state(). But the purpose of any (*arch_state)() method, thus including armv7a_arch_state(), is to only print out and inform the user about some architecture specific status. Moreover, to reduce the verbosity during a GDB session, the method (*arch_state)() is not executed anymore at debug state entry (check use of target->verbose_halt_msg in src/openocd.c), thus the state of translation table gets out-of-sync triggering Error: Address translation failure or even using a wrong address in the memory R/W operation. In addition, the commit above breaks the case of armv7r by calling armv7a_read_ttbcr() unconditionally. Fixed by moving in cortex_a_post_debug_entry() the call to armv7a_read_ttbcr() on armv7a case only. Remove the call to armv7a_read_ttbcr() in armv7a_identify_cache() since it is (conditionally) called only in the same procedure cortex_a_post_debug_entry(). Fixes: bfc5c764df14 ("armv7a: cache ttbcr and ttb0/1 on debug state entry") Change-Id: Ifc20eca190111832e339a01b7f85d28c1547c8ba Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4601 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * Avoid dereferencing NULL pointer. If a NULL pointer is passed, don't attempt to increment it. This avoids passing the now not-NULL pointer on and eventually segfaulting. Also remove some unnecessary temporary variables. Change-Id: I268e225121aa283d59179bfae407ebf6959d3a4e Signed-off-by: Darius Rad <darius@bluespec.com> Reviewed-on: http://openocd.zylin.com/4550 Tested-by: jenkins Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com> * Remove FSF mailing address. Checkpatch complains about this (FSF_MAILING_ADDRESS). Change-Id: Ib46a7704f9aed4ed16ce7733d43c58254a094149 Signed-off-by: Tim Newsome <tim@sifive.com> Reviewed-on: http://openocd.zylin.com/4559 Tested-by: jenkins Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk> * drivers: cmsis_dap_usb: implement cmd JTAG_TMS Simply add a wrapper around cmsis_dap_cmd_DAP_SWJ_Sequence() Change-Id: Icf86f84b24e9fec56e2f9e155396aac34b0e06d2 Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4517 Tested-by: jenkins Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk> * arm_adi_v5: put SWJ-DP back to JTAG mode at exit When SWD mode is used, current OpenOCD code left the SWJ-DP in SWD mode at exit. Also, current code is unable to switch back the SWJ-DP in JTAG at next run, thus a power cycle of both target and interface is required in order to run OpenOCD in JTAG mode again. Put the SWJ-DP back to JTAG mode before exit from OpenOCD. Use switch_seq(SWD_TO_JTAG) instead of dap_to_jtag(), because the latter is not implemented on some interfaces. This is aligned with the use of switch_seq(JTAG_TO_SWD) in swd_connect(). Change-Id: I55d3faebe60d6402037ec39dd9700dc5f17c53b0 Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4493 Tested-by: jenkins Reviewed-by: Bohdan Tymkiv <bhdt@cypress.com> Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * Add RISC-V support. This supports both 0.11 and 0.13 versions of the debug spec. Support for `-rtos riscv` will come in a separate commit since it was easy to separate out, and is likely to be more controversial. Flash support for the SiFive boards will also come in a later commit. Change-Id: I1d38fe669c2041b4e21a5c54a091594aac3e2190 Signed-off-by: Tim Newsome <tim@sifive.com> Reviewed-on: http://openocd.zylin.com/4578 Tested-by: jenkins Reviewed-by: Liviu Ionescu <ilg@livius.net> Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * usb_blaster: Don't unnecessarily go through DR-/IR-Pause There is no need to pass through DR-/IR-Pause after a scan if we want to go to DR-/IR-Update. We just have to skip the first step of the path to the end state because we already did that step when shifting the last bit. v2: - Fix comments as remarked in review of v1 Change-Id: I3c10f02794b2233f63d2150934e2768430873caa Signed-off-by: Daniel Glöckner <daniel-gl@gmx.net> Reviewed-on: http://openocd.zylin.com/4245 Tested-by: jenkins Reviewed-by: Christopher Head <chead@zaber.com> Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * cortex_a: fix virt2phys when mmu is disabled When the MMU is not enabled on debug state entry, virt2phys cannot perform a translation since it is unknown whether a valid MMU configuration existed before. In this case, return the virtual address as physical address. Change-Id: I6f85a7a5dbc200be1a4b5badf10a1a717f1c79c0 Signed-off-by: Matthias Welwarsky <matthias.welwarsky@sysgo.com> Reviewed-on: http://openocd.zylin.com/4480 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * drivers: cmsis-dap: print serial if available Helpful for sanity checking connections Change-Id: Ife0d8b4e12d4c03685aac8115c9739a4c1e994fe Signed-off-by: Karl Palsson <karlp@tweak.net.au> Reviewed-on: http://openocd.zylin.com/3405 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * target/cortex_m: make a variable local The vec_ids variable is not referenced anywhere other than the vector catch command handler. Make it local to that function. Change-Id: Ie5865e8f78698c19a09f0b9d58269ced1c9db440 Signed-off-by: Christopher Head <chead@zaber.com> Reviewed-on: http://openocd.zylin.com/4606 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * target/cortex_a: fix compile error for uninitialized variable Commit ad6c71e151590f9d07eb07eda978a8d2a845259c introduced the variable "mmu_enabled" whose pointer is passed to cortex_a_mmu() that initialises it. This initialization is not visible to the compiler that issue a compile error. The same situation is common across the same file and the usual workaround is to initialize it to zero; thus the same fix i applied here. Ticket: https://sourceforge.net/p/openocd/tickets/197/ Fixes: commit ad6c71e15159 ("cortex_a: fix virt2phys when mmu is disabled") Change-Id: I77dec41acdf4c715b45ae37b72e36719d96d9283 Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4619 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * mips_m4k: add optional reset handler In some cases by using SRST we can't halt CPU early enough. And option PrRst is not available too. In this case the only way is to set BOOT flag over EJTAG and reset CPU or SoC from CPU itself. For example by writing to some reset register. This patch is providing possibility to use user defined reset-assert handler which will be enabled only in case SRST is disabled. It is needed to be able switch between two different reset variants on run time. Change-Id: I6ef98f1871ea657115877190f7cc7a5e8f3233e4 Signed-off-by: Oleksij Rempel <linux@rempel-privat.de> Reviewed-on: http://openocd.zylin.com/4404 Tested-by: jenkins Reviewed-by: Paul Fertser <fercerpav@gmail.com> * tcl/target: add config for Qualcomm QCA4531 The QCA4531 is a two stream (2x2) 802.11b/g/n single-band programmable Wi-Fi System-on-Chip (SoC) for the Internet of Things (IoT). https://www.qualcomm.com/products/qca4531 Change-Id: I58398c00943b005cfaf0ac1eaad92d1fa4e2cba7 Signed-off-by: Oleksij Rempel <linux@rempel-privat.de> Reviewed-on: http://openocd.zylin.com/4405 Tested-by: jenkins Reviewed-by: Paul Fertser <fercerpav@gmail.com> * tcl/board: add config for 8devices LIMA board More information about this board can be found here: https://www.8devices.com/products/lima Change-Id: Id35a35d3e986630d58d37b47828870afd107cc6a Signed-off-by: Oleksij Rempel <linux@rempel-privat.de> Reviewed-on: http://openocd.zylin.com/4406 Tested-by: jenkins Reviewed-by: Paul Fertser <fercerpav@gmail.com> * tcl/target|board: move common AR9331 code to atheros_ar9331.cfg The ar9331_25mhz_pll_init and ar9331_ddr1_init routines can be used not only for TP-Link MR3020 board, so move them to the common atheros_ar9331.cfg file. Change-Id: I04090856b08151d6bb0f5ef9cc654efae1c81835 Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com> Reviewed-on: http://openocd.zylin.com/2999 Tested-by: jenkins Reviewed-by: Paul Fertser <fercerpav@gmail.com> * tcl/target/atheros_ar9331: add DDR2 helper this helper works on many different boards, so it is good to have it in target config Change-Id: I068deac36fdd73dbbcedffc87865cc5b9d992c1d Signed-off-by: Oleksij Rempel <linux@rempel-privat.de> Reviewed-on: http://openocd.zylin.com/4422 Tested-by: jenkins Reviewed-by: Paul Fertser <fercerpav@gmail.com> * tcl/target/atheros_ar9331: add documentation and extra helpers Sync it with experience gathered on Qualcomm QCA4531 SoC. This chips are in many ways similar. Change-Id: I06b9c85e5985a09a9be3cb6cc0ce3b37695d2e54 Signed-off-by: Oleksij Rempel <linux@rempel-privat.de> Reviewed-on: http://openocd.zylin.com/4423 Tested-by: jenkins Reviewed-by: Paul Fertser <fercerpav@gmail.com> * tcl/board: add DPTechnics DPT-Board-v1 it is Atheros AR9331 based IoT dev board. Change-Id: I6fc3cdea1bef49c53045018ff5acfec4d5610ba6 Signed-off-by: Oleksij Rempel <linux@rempel-privat.de> Reviewed-on: http://openocd.zylin.com/4424 Tested-by: jenkins Reviewed-by: Paul Fertser <fercerpav@gmail.com> * fpga/altera-10m50: add all device id add all currently know Intel (Alter) MAX 10 device ids Change-Id: I6a88fef222c8e206812499d41be863c3d89fa944 Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> Reviewed-on: http://openocd.zylin.com/4598 Tested-by: jenkins Reviewed-by: Paul Fertser <fercerpav@gmail.com> * target|board: Add Intel (Altera) Arria 10 target and related board Target information about this SoC can be found here: https://www.altera.com/products/fpga/arria-series/arria-10/overview.html Achilles Instant-Development Kit Arria 10 SoC SoM: https://www.reflexces.com/products-solutions/development-kits/arria-10/achilles-instant-development-kit-arria-10-soc-som Change-Id: Id78c741be6a8b7d3a70f37d41088e47ee61b437a Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> Reviewed-on: http://openocd.zylin.com/4583 Tested-by: jenkins Reviewed-by: Paul Fertser <fercerpav@gmail.com> * target/riscv: fix compile error with gcc 8.1.1 Fix compile error: src/target/riscv/riscv-011.c: In function ‘slot_offset’: src/target/riscv/riscv-011.c:238:4: error: this statement may fall through [-Werror=implicit-fallthrough=] switch (slot) { ^~~~~~ src/target/riscv/riscv-011.c:243:3: note: here case 64: ^~~~ Fixes: a51ab8ddf63a ("Add RISC-V support.") Change-Id: I7fa86b305bd90cc590fd4359c3698632d44712e5 Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4618 Tested-by: jenkins Reviewed-by: Jiri Kastner <cz172638@gmail.com> Reviewed-by: Oleksij Rempel <linux@rempel-privat.de> Reviewed-by: Tim Newsome <tim@sifive.com> Reviewed-by: Paul Fertser <fercerpav@gmail.com> * server: explicitly call "shutdown" when catch CTRL-C or a signal Every TCL command can be renamed (or deleted) and then replaced by a TCL proc that has the same name of the original TCL command. This can be used either to completely replace an existing command or to wrap the original command to extend its functionality. This applies also to the OpenOCD command "shutdown" and can be useful, for example, to set back some default value to the target before quitting OpenOCD. E.g. (TCL code): rename shutdown original_shutdown proc shutdown {} { puts "This is my implementation of shutdown" # my own stuff before exit OpenOCD original_shutdown } Unfortunately, sending a signal (or pressing CTRL-C) to terminate OpenOCD doesn't trigger calling the original "shutdown" command nor its (eventual) replacement. Detect if the main loop is terminated by an external signal and in such case execute explicitly the command "shutdown". Replace with enum the magic numbers assumed by "shutdown_openocd". Please notice that it's possible to write a custom "shutdown" TCL proc that does not call the original "shutdown" command. This is useful, for example, to prevent the user to quit OpenOCD by typing "shutdown" in the telnet session. Such case will not prevent OpenOCD to terminate when receiving a signal; OpenOCD will quit after executing the custom "shutdown" command. Change-Id: I86b8f9eab8dbd7a28dad58b8cafd97caa7a82f43 Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4551 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * zy1000: fix compile error with gcc 8.1.1 The fall-through comment is not taken in consideration by gcc 8.1.1 because it is inside the braces of a C-code block. Move the comment outside the C block. Change-Id: I22d87b2dee109fb8bcf2071ac55fdf7171ffcf4b Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4614 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * flash/nor/tcl.c: fix flash bank bounds check in 'flash fill' command handler Steps to reproduce ( STM32F103 'Blue Pill', 128KiB of flash ): > flash fillh 0x0801FFFE 00 1 wrote 2 bytes to 0x0801fffe in 0.019088s (0.102 KiB/s) > flash fillw 0x0801FFFE 00 1 Error: stm32f1x.cpu -- clearing lockup after double fault Error: error waiting for target flash write algorithm Error: error writing to flash at address 0x08000000 at offset 0x0001fffe Change-Id: I145092ec5e45bc586b3df48bf37c38c9226915c1 Signed-off-by: Bohdan Tymkiv <bhdt@cypress.com> Reviewed-on: http://openocd.zylin.com/4516 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * target/arm_adi_v5: add command "dpreg" For very low level debug or development around DAP, it is useful to have direct access to DP registers. Add command "dpreg" by mimic the syntax of the existing "apreg" command: $dap_name dpreg reg [value] Change-Id: Ic4ab451eb5e74453133adee61050b4c6f656ffa3 Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4612 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * nrf5: add free_driver_priv Change-Id: I429a9868deb0c4b51f47a4bbad844bdc348e8d21 Signed-off-by: Jim Paris <jim@jtan.com> Reviewed-on: http://openocd.zylin.com/4608 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * rtos: add support for NuttX This patch introduces RTOS support for NuttX. Currently, only ARM Cortex-M (both FPU and FPU-less) targets are supported. To use, add the following lines to ~/.gdbinit. define hookpost-file eval "monitor nuttx.pid_offset %d", &((struct tcb_s *)(0))->pid eval "monitor nuttx.xcpreg_offset %d", &((struct tcb_s *)(0))->xcp.regs eval "monitor nuttx.state_offset %d", &((struct tcb_s *)(0))->task_state eval "monitor nuttx.name_offset %d", &((struct tcb_s *)(0))->name eval "monitor nuttx.name_size %d", sizeof(((struct tcb_s *)(0))->name) end And please make sure the above values are the same as in src/rtos/nuttx_header.h Change-Id: I2aaf8644d24dfb84b500516a9685382d5d8fe48f Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com> Signed-off-by: Masatoshi Tateishi <Masatoshi.Tateishi@jp.sony.com> Signed-off-by: Nobuto Kobayashi <Nobuto.Kobayashi@sony.com> Reviewed-on: http://openocd.zylin.com/4103 Tested-by: jenkins Reviewed-by: Alan Carvalho de Assis <acassis@gmail.com> Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * server/server: Add ability to remove services Add the ability to remove services while OpenOCD is running. Change-Id: I4067916fda6d03485463fa40901b40484d94e24e Signed-off-by: Marc Schink <openocd-dev@marcschink.de> Reviewed-on: http://openocd.zylin.com/4054 Tested-by: jenkins Reviewed-by: Fredrik Hederstierna <fredrik@hederstierna.com> Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * target/cortex_m: fix incorrect comment The code sets C_MASKINTS if that bit is not already set (correctly). Fix the comment to agree. Change-Id: If4543e2660a9fa2cdabb2d2698427a6c8d9a274c Signed-off-by: Christopher Head <chead@zaber.com> Reviewed-on: http://openocd.zylin.com/4620 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * tcl/target/stm32f0x: Allow overriding the Flash bank size Copy & paste from another stm32 target. Change-Id: I0f6cbcec974ce70c23c1850526354106caee1172 Signed-off-by: Dominik Peklo <dom.peklo@gmail.com> Reviewed-on: http://openocd.zylin.com/4575 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * tcl/target: add Allwinner V3s SoC support Change-Id: I2459d2b137050985b7301047f9651951d72d9e9e Signed-off-by: Oleksij Rempel <linux@rempel-privat.de> Reviewed-on: http://openocd.zylin.com/4427 Tested-by: jenkins Reviewed-by: Paul Fertser <fercerpav@gmail.com> * target/arm_adi_v5: allow commands apsel and apcsw during init phase The current implementation of apsel cannot be executed during the initialization phase because it queries the DAP AP to retrieve and print the content of IDR register, and the query is only possible later on during the exec phase. But IDR information is already printed by the dedicated command apid, making redundant printing it by apsel too. Being unable to run apsel during initialization, makes also apcsw command (that depends on apsel) not usable in such phase. Modify the command apsel to only set the current AP, without making any transfer to the (possibly not initialized yet) DAP. When run without parameters, just print the current AP number. Change mode to COMMAND_ANY to apsel and to apcsw. Change-Id: Ibea6d531e435d1d49d782de1ed8ee6846e91bfdf Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4624 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * target/cortex_a: allow command dacrfixup during init phase There is no reason to restrict the command "cortex_a dacrfixup" to the EXEC phase only. Change the command mode to ANY so the command can be used in the initialization phase too. Change-Id: I498cc6b2dbdc48b3b2dd5f0445519a51857b295f Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4623 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * target/armv7a_cache: add gdb keep-alive and fix a missing dpm finish Depending on range size, the loop on cache operations can take quite some time, causing gdb to timeout. Add keep-alive to prevent gdb to timeout. Add also a missing dpm->finish() to balance dpm->prepare(). Change-Id: Ia87934b1ec19a0332bb50e3010b582381e5f3685 Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: http://openocd.zylin.com/4627 Tested-by: jenkins Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de> * Add detail to `wrong register size` error. Signed-off-by: Tim Newsome <tim@sifive.com> Change-Id: Id31499c94b539969970251145e42c89c943fd87c Reviewed-on: http://openocd.zylin.com/4577 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * doc: fix typo in cortex_m maskisr command Change-Id: I37795c320ff7cbf6f2c7434e03b26dbaf6fc6db4 Signed-off-by: Christopher Head <chead@zaber.com> Reviewed-on: http://openocd.zylin.com/4621 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * target/cortex_m: restore C_MASKINTS after reset The cortex_m maskisr user-facing setting is not changed across a target reset. However, the in-core C_MASKINTS bit was always cleared as part of reset processing, meaning that a cortex_m maskisr on setting would not be respected after a reset. Set C_MASKINTS based on the user-facing setting value rather than always clearing it after reset. Change-Id: I5aa5b9dfde04a0fb9c6816fa55b5ef1faf39f8de Signed-off-by: Christopher Head <chead@zaber.com> Reviewed-on: http://openocd.zylin.com/4605 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * tcl/board: update all uses of interface/stlink-v2-1 to interface/stlink Change-Id: I5e27e84d022f73101376e8b4a1bdc65f58fd348a Signed-off-by: Cody P Schafer <openocd@codyps.com> Reviewed-on: http://openocd.zylin.com/4456 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * target/riscv/riscv-011: fix compile warning about uninitialized variable In MSYS2 MinGW 64-bit git clone git://git.code.sf.net/p/openocd/code openocd $ gcc --version gcc.exe (Rev1, Built by MSYS2 project) 8.2.0 ./bootstrap ./configure --prefix= $ cat config.status | grep CFLAGS CFLAGS='-g -O2' make bindir = "bin-x64" depbase=`echo src/target/riscv/riscv-011.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\ /bin/sh ./libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -D__USE_MINGW_ANSI_STDIO -I./src -I./src -I./src/helper -DPKGDATADIR=\"/mingw64/share/openocd\" -DBINDIR=\"bin-x64\" -I./jimtcl -I./jimtcl -Wall -Wstrict-prototypes -Wformat-security -Wshadow -Wextra -Wno-unused-parameter -Wbad-function-cast -Wcast-align -Wredundant-decls -Werror -g -O2 -MT src/target/riscv/riscv-011.lo -MD -MP -MF $depbase.Tpo -c -o src/target/riscv/riscv-011.lo src/target/riscv/riscv-011.c &&\ mv -f $depbase.Tpo $depbase.Plo libtool: compile: gcc -DHAVE_CONFIG_H -I. -D__USE_MINGW_ANSI_STDIO -I./src -I./src -I./src/helper -DPKGDATADIR=\"/mingw64/share/openocd\" -DBINDIR=\"bin-x64\" -I./jimtcl -I./jimtcl -Wall -Wstrict-prototypes -Wformat-security -Wshadow -Wextra -Wno-unused-parameter -Wbad-function-cast -Wcast-align -Wredundant-decls -Werror -g -O2 -MT src/target/riscv/riscv-011.lo -MD -MP -MF src/target/riscv/.deps/riscv-011.Tpo -c src/target/riscv/riscv-011.c -o src/target/riscv/riscv-011.o src/target/riscv/riscv-011.c: In function 'poll_target': src/target/riscv/riscv-011.c:1799:6: error: 'reg' may be used uninitialized in this function [-Werror=maybe-uninitialized] reg_cache_set(target, reg, ((data & 0xffffffff) << 32) | value); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/target/riscv/riscv-011.c:1686:17: note: 'reg' was declared here unsigned int reg; ^~~ cc1.exe: all warnings being treated as errors make[2]: *** [Makefile:3250: src/target/riscv/riscv-011.lo] Error 1 Change-Id: I6996dcb866fbace26817636f4bedba09510a087f Signed-off-by: Svetoslav Enchev <svetoslav.enchev@gmail.com> Reviewed-on: http://openocd.zylin.com/4635 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-by: Tim Newsome <tim@sifive.com> Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Diffstat (limited to 'src')
-rw-r--r--src/flash/nor/Makefile.am6
-rw-r--r--src/flash/nor/at91sam4.c81
-rw-r--r--src/flash/nor/at91samd.c5
-rw-r--r--src/flash/nor/cc26xx.c567
-rw-r--r--src/flash/nor/cc26xx.h101
-rw-r--r--src/flash/nor/drivers.c4
-rw-r--r--src/flash/nor/msp432.c1103
-rw-r--r--src/flash/nor/msp432.h127
-rw-r--r--src/flash/nor/nrf5.c75
-rw-r--r--src/flash/nor/psoc5lp.c34
-rw-r--r--src/flash/nor/stm32f1x.c4
-rw-r--r--src/flash/nor/stm32f2x.c6
-rw-r--r--src/flash/nor/stm32h7x.c10
-rw-r--r--src/flash/nor/stm32l4x.c6
-rw-r--r--src/flash/nor/stm32lx.c2
-rw-r--r--src/flash/nor/tcl.c58
-rw-r--r--src/flash/nor/tms470.c36
-rw-r--r--src/jtag/aice/aice_usb.c52
-rw-r--r--src/jtag/aice/aice_usb.h1
-rw-r--r--src/jtag/core.c2
-rw-r--r--src/jtag/drivers/cmsis_dap_usb.c67
-rw-r--r--src/jtag/drivers/jlink.c4
-rw-r--r--src/jtag/drivers/jtag_vpi.c13
-rw-r--r--src/jtag/drivers/stlink_usb.c5
-rw-r--r--src/jtag/drivers/usb_blaster/usb_blaster.c41
-rw-r--r--src/jtag/hla/hla_interface.c2
-rw-r--r--src/jtag/hla/hla_layout.h2
-rw-r--r--src/jtag/interface.h4
-rw-r--r--src/jtag/zy1000/zy1000.c2
-rw-r--r--src/rtos/Makefile.am2
-rw-r--r--src/rtos/nuttx.c405
-rw-r--r--src/rtos/nuttx_header.h71
-rw-r--r--src/rtos/rtos.c2
-rw-r--r--src/server/gdb_server.c13
-rw-r--r--src/server/server.c97
-rw-r--r--src/server/server.h1
-rw-r--r--src/target/aarch64.c21
-rw-r--r--src/target/adi_v5_swd.c11
-rw-r--r--src/target/arm_adi_v5.c89
-rw-r--r--src/target/arm_adi_v5.h3
-rw-r--r--src/target/arm_dap.c5
-rw-r--r--src/target/arm_disassembler.c75
-rw-r--r--src/target/arm_semihosting.c87
-rw-r--r--src/target/armv4_5.c6
-rw-r--r--src/target/armv7a.c7
-rw-r--r--src/target/armv7a.h1
-rw-r--r--src/target/armv7a_cache.c27
-rw-r--r--src/target/armv7m.c6
-rw-r--r--src/target/armv7m_trace.c20
-rw-r--r--src/target/armv7m_trace.h16
-rw-r--r--src/target/armv8.c15
-rw-r--r--src/target/armv8.h14
-rw-r--r--src/target/cortex_a.c19
-rw-r--r--src/target/cortex_m.c43
-rw-r--r--src/target/image.c3
-rw-r--r--src/target/mips_m4k.c2
-rw-r--r--src/target/riscv/riscv-011.c3
-rw-r--r--src/target/semihosting_common.c34
-rw-r--r--src/target/target.c5
59 files changed, 3122 insertions, 401 deletions
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index db936b8..9a58239 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -20,6 +20,7 @@ NOR_DRIVERS = \
%D%/avrf.c \
%D%/bluenrg-x.c \
%D%/cc3220sf.c \
+ %D%/cc26xx.c \
%D%/cfi.c \
%D%/dsp5680xx_flash.c \
%D%/efm32.c \
@@ -36,6 +37,7 @@ NOR_DRIVERS = \
%D%/lpc2900.c \
%D%/lpcspifi.c \
%D%/mdr.c \
+ %D%/msp432.c \
%D%/mrvlqspi.c \
%D%/niietcm4.c \
%D%/non_cfi.c \
@@ -67,9 +69,11 @@ NOR_DRIVERS = \
NORHEADERS = \
%D%/core.h \
%D%/cc3220sf.h \
+ %D%/cc26xx.h \
%D%/cfi.h \
%D%/driver.h \
%D%/imp.h \
%D%/non_cfi.h \
%D%/ocl.h \
- %D%/spi.h
+ %D%/spi.h \
+ %D%/msp432.h
diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c
index 0475216..c5b31e9 100644
--- a/src/flash/nor/at91sam4.c
+++ b/src/flash/nor/at91sam4.c
@@ -682,6 +682,40 @@ static const struct sam4_chip_details all_sam4_details[] = {
},
},
},
+ /*at91sam4sa16c - TFBGA100/VFBGA100/LQFP100*/
+ {
+ .chipid_cidr = 0x28a70ce0,
+ .name = "at91sam4sa16c",
+ .total_flash_size = 1024 * 1024,
+ .total_sram_size = 160 * 1024,
+ .n_gpnvms = 2,
+ .n_banks = 1,
+
+/* .bank[0] = { */
+ {
+ {
+ .probed = 0,
+ .pChip = NULL,
+ .pBank = NULL,
+ .bank_number = 0,
+ .base_address = FLASH_BANK_BASE_S,
+ .controller_address = 0x400e0a00,
+ .flash_wait_states = 5,
+ .present = 1,
+ .size_bytes = 1024 * 1024,
+ .nsectors = 128,
+ .sector_size = 8192,
+ .page_size = 512,
+ },
+/* .bank[1] = {*/
+ {
+ .present = 0,
+ .probed = 0,
+ .bank_number = 1,
+
+ },
+ },
+ },
/*atsam4s16b - LQFP64/QFN64/WLCSP64*/
{
.chipid_cidr = 0x289C0CE0,
@@ -1261,50 +1295,6 @@ static const struct sam4_chip_details all_sam4_details[] = {
},
},
- /*at91sam4sa16c*/
- {
- .chipid_cidr = 0x28a70ce0,
- .name = "at91sam4sa16c",
- .total_flash_size = 1024 * 1024,
- .total_sram_size = 160 * 1024,
- .n_gpnvms = 3,
- .n_banks = 2,
-
-/* .bank[0] = { */
- {
- {
- .probed = 0,
- .pChip = NULL,
- .pBank = NULL,
- .bank_number = 0,
- .base_address = FLASH_BANK0_BASE_SD,
- .controller_address = 0x400e0a00,
- .flash_wait_states = 5,
- .present = 1,
- .size_bytes = 512 * 1024,
- .nsectors = 64,
- .sector_size = 8192,
- .page_size = 512,
- },
-
-/* .bank[1] = { */
- {
- .probed = 0,
- .pChip = NULL,
- .pBank = NULL,
- .bank_number = 1,
- .base_address = FLASH_BANK1_BASE_1024K_SD,
- .controller_address = 0x400e0c00,
- .flash_wait_states = 5,
- .present = 1,
- .size_bytes = 512 * 1024,
- .nsectors = 64,
- .sector_size = 8192,
- .page_size = 512,
- },
- },
- },
-
/* atsamg53n19 */
{
.chipid_cidr = 0x247e0ae0,
@@ -2554,6 +2544,8 @@ static int sam4_GetDetails(struct sam4_bank_private *pPrivate)
pPrivate->pChip->cfg.CHIPID_CIDR);
sam4_explain_chipid_cidr(pPrivate->pChip);
return ERROR_FAIL;
+ } else {
+ LOG_INFO("SAM4 Found chip %s, CIDR 0x%08x", pDetails->name, pDetails->chipid_cidr);
}
/* DANGER: THERE ARE DRAGONS HERE */
@@ -2624,6 +2616,7 @@ static int _sam4_probe(struct flash_bank *bank, int noise)
for (x = 0; x < SAM4_MAX_FLASH_BANKS; x++) {
if (bank->base == pPrivate->pChip->details.bank[x].base_address) {
bank->size = pPrivate->pChip->details.bank[x].size_bytes;
+ LOG_INFO("SAM4 Set flash bank to %08X - %08X, idx %d", bank->base, bank->base + bank->size, x);
break;
}
}
diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c
index 8553ee8..017d144 100644
--- a/src/flash/nor/at91samd.c
+++ b/src/flash/nor/at91samd.c
@@ -115,15 +115,16 @@ static const struct samd_part samd10_parts[] = {
/* Known SAMD11 parts */
static const struct samd_part samd11_parts[] = {
- { 0x0, "SAMD11D14AMU", 16, 4 },
+ { 0x0, "SAMD11D14AM", 16, 4 },
{ 0x1, "SAMD11D13AMU", 8, 4 },
{ 0x2, "SAMD11D12AMU", 4, 4 },
- { 0x3, "SAMD11D14ASU", 16, 4 },
+ { 0x3, "SAMD11D14ASS", 16, 4 },
{ 0x4, "SAMD11D13ASU", 8, 4 },
{ 0x5, "SAMD11D12ASU", 4, 4 },
{ 0x6, "SAMD11C14A", 16, 4 },
{ 0x7, "SAMD11C13A", 8, 4 },
{ 0x8, "SAMD11C12A", 4, 4 },
+ { 0x9, "SAMD11D14AU", 16, 4 },
};
/* Known SAMD20 parts. See Table 12-8 in 42129F–SAM–10/2013 */
diff --git a/src/flash/nor/cc26xx.c b/src/flash/nor/cc26xx.c
new file mode 100644
index 0000000..e6e9e59
--- /dev/null
+++ b/src/flash/nor/cc26xx.c
@@ -0,0 +1,567 @@
+/***************************************************************************
+ * Copyright (C) 2017 by Texas Instruments, Inc. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include "cc26xx.h"
+#include <helper/binarybuffer.h>
+#include <helper/time_support.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+#include <target/image.h>
+
+#define FLASH_TIMEOUT 8000
+
+struct cc26xx_bank {
+ const char *family_name;
+ uint32_t icepick_id;
+ uint32_t user_id;
+ uint32_t device_type;
+ uint32_t sector_length;
+ bool probed;
+ struct working_area *working_area;
+ struct armv7m_algorithm armv7m_info;
+ const uint8_t *algo_code;
+ uint32_t algo_size;
+ uint32_t algo_working_size;
+ uint32_t buffer_addr[2];
+ uint32_t params_addr[2];
+};
+
+static int cc26xx_auto_probe(struct flash_bank *bank);
+
+static uint32_t cc26xx_device_type(uint32_t icepick_id, uint32_t user_id)
+{
+ uint32_t device_type = 0;
+
+ switch (icepick_id & ICEPICK_ID_MASK) {
+ case CC26X0_ICEPICK_ID:
+ device_type = CC26X0_TYPE;
+ break;
+ case CC26X1_ICEPICK_ID:
+ device_type = CC26X1_TYPE;
+ break;
+ case CC13X0_ICEPICK_ID:
+ device_type = CC13X0_TYPE;
+ break;
+ case CC13X2_CC26X2_ICEPICK_ID:
+ default:
+ if ((user_id & USER_ID_CC13_MASK) != 0)
+ device_type = CC13X2_TYPE;
+ else
+ device_type = CC26X2_TYPE;
+ break;
+ }
+
+ return device_type;
+}
+
+static uint32_t cc26xx_sector_length(uint32_t icepick_id)
+{
+ uint32_t sector_length;
+
+ switch (icepick_id & ICEPICK_ID_MASK) {
+ case CC26X0_ICEPICK_ID:
+ case CC26X1_ICEPICK_ID:
+ case CC13X0_ICEPICK_ID:
+ /* Chameleon family device */
+ sector_length = CC26X0_SECTOR_LENGTH;
+ break;
+ case CC13X2_CC26X2_ICEPICK_ID:
+ default:
+ /* Agama family device */
+ sector_length = CC26X2_SECTOR_LENGTH;
+ break;
+ }
+
+ return sector_length;
+}
+
+static int cc26xx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr)
+{
+ struct target *target = bank->target;
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+
+ uint32_t status_addr = params_addr + CC26XX_STATUS_OFFSET;
+ uint32_t status = CC26XX_BUFFER_FULL;
+ long long start_ms;
+ long long elapsed_ms;
+
+ int retval = ERROR_OK;
+
+ start_ms = timeval_ms();
+ while (CC26XX_BUFFER_FULL == status) {
+ retval = target_read_u32(target, status_addr, &status);
+ if (ERROR_OK != retval)
+ return retval;
+
+ elapsed_ms = timeval_ms() - start_ms;
+ if (elapsed_ms > 500)
+ keep_alive();
+ if (elapsed_ms > FLASH_TIMEOUT)
+ break;
+ };
+
+ if (CC26XX_BUFFER_EMPTY != status) {
+ LOG_ERROR("%s: Flash operation failed", cc26xx_bank->family_name);
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static int cc26xx_init(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+
+ int retval;
+
+ /* Make sure we've probed the flash to get the device and size */
+ retval = cc26xx_auto_probe(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Check for working area to use for flash helper algorithm */
+ if (NULL != cc26xx_bank->working_area)
+ target_free_working_area(target, cc26xx_bank->working_area);
+ retval = target_alloc_working_area(target, cc26xx_bank->algo_working_size,
+ &cc26xx_bank->working_area);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Confirm the defined working address is the area we need to use */
+ if (CC26XX_ALGO_BASE_ADDRESS != cc26xx_bank->working_area->address)
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+
+ /* Write flash helper algorithm into target memory */
+ retval = target_write_buffer(target, CC26XX_ALGO_BASE_ADDRESS,
+ cc26xx_bank->algo_size, cc26xx_bank->algo_code);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("%s: Failed to load flash helper algorithm",
+ cc26xx_bank->family_name);
+ target_free_working_area(target, cc26xx_bank->working_area);
+ return retval;
+ }
+
+ /* Initialize the ARMv7 specific info to run the algorithm */
+ cc26xx_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+ cc26xx_bank->armv7m_info.core_mode = ARM_MODE_THREAD;
+
+ /* Begin executing the flash helper algorithm */
+ retval = target_start_algorithm(target, 0, NULL, 0, NULL,
+ CC26XX_ALGO_BASE_ADDRESS, 0, &cc26xx_bank->armv7m_info);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("%s: Failed to start flash helper algorithm",
+ cc26xx_bank->family_name);
+ target_free_working_area(target, cc26xx_bank->working_area);
+ return retval;
+ }
+
+ /*
+ * At this point, the algorithm is running on the target and
+ * ready to receive commands and data to flash the target
+ */
+
+ return retval;
+}
+
+static int cc26xx_quit(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+
+ int retval;
+
+ /* Regardless of the algo's status, attempt to halt the target */
+ (void)target_halt(target);
+
+ /* Now confirm target halted and clean up from flash helper algorithm */
+ retval = target_wait_algorithm(target, 0, NULL, 0, NULL, 0, FLASH_TIMEOUT,
+ &cc26xx_bank->armv7m_info);
+
+ target_free_working_area(target, cc26xx_bank->working_area);
+ cc26xx_bank->working_area = NULL;
+
+ return retval;
+}
+
+static int cc26xx_mass_erase(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+ struct cc26xx_algo_params algo_params;
+
+ int retval;
+
+ if (TARGET_HALTED != target->state) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ retval = cc26xx_init(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Initialize algorithm parameters */
+ buf_set_u32(algo_params.address, 0, 32, 0);
+ buf_set_u32(algo_params.length, 0, 32, 4);
+ buf_set_u32(algo_params.command, 0, 32, CC26XX_CMD_ERASE_ALL);
+ buf_set_u32(algo_params.status, 0, 32, CC26XX_BUFFER_FULL);
+
+ /* Issue flash helper algorithm parameters for mass erase */
+ retval = target_write_buffer(target, cc26xx_bank->params_addr[0],
+ sizeof(algo_params), (uint8_t *)&algo_params);
+
+ /* Wait for command to complete */
+ if (ERROR_OK == retval)
+ retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[0]);
+
+ /* Regardless of errors, try to close down algo */
+ (void)cc26xx_quit(bank);
+
+ return retval;
+}
+
+FLASH_BANK_COMMAND_HANDLER(cc26xx_flash_bank_command)
+{
+ struct cc26xx_bank *cc26xx_bank;
+
+ if (CMD_ARGC < 6)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ cc26xx_bank = malloc(sizeof(struct cc26xx_bank));
+ if (NULL == cc26xx_bank)
+ return ERROR_FAIL;
+
+ /* Initialize private flash information */
+ memset((void *)cc26xx_bank, 0x00, sizeof(struct cc26xx_bank));
+ cc26xx_bank->family_name = "cc26xx";
+ cc26xx_bank->device_type = CC26XX_NO_TYPE;
+ cc26xx_bank->sector_length = 0x1000;
+
+ /* Finish initialization of bank */
+ bank->driver_priv = cc26xx_bank;
+ bank->next = NULL;
+
+ return ERROR_OK;
+}
+
+static int cc26xx_erase(struct flash_bank *bank, int first, int last)
+{
+ struct target *target = bank->target;
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+ struct cc26xx_algo_params algo_params;
+
+ uint32_t address;
+ uint32_t length;
+ int retval;
+
+ if (TARGET_HALTED != target->state) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* Do a mass erase if user requested all sectors of flash */
+ if ((first == 0) && (last == (bank->num_sectors - 1))) {
+ /* Request mass erase of flash */
+ return cc26xx_mass_erase(bank);
+ }
+
+ address = first * cc26xx_bank->sector_length;
+ length = (last - first + 1) * cc26xx_bank->sector_length;
+
+ retval = cc26xx_init(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Set up algorithm parameters for erase command */
+ buf_set_u32(algo_params.address, 0, 32, address);
+ buf_set_u32(algo_params.length, 0, 32, length);
+ buf_set_u32(algo_params.command, 0, 32, CC26XX_CMD_ERASE_SECTORS);
+ buf_set_u32(algo_params.status, 0, 32, CC26XX_BUFFER_FULL);
+
+ /* Issue flash helper algorithm parameters for erase */
+ retval = target_write_buffer(target, cc26xx_bank->params_addr[0],
+ sizeof(algo_params), (uint8_t *)&algo_params);
+
+ /* If no error, wait for erase to finish */
+ if (ERROR_OK == retval)
+ retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[0]);
+
+ /* Regardless of errors, try to close down algo */
+ (void)cc26xx_quit(bank);
+
+ return retval;
+}
+
+static int cc26xx_protect(struct flash_bank *bank, int set, int first,
+ int last)
+{
+ return ERROR_OK;
+}
+
+static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct target *target = bank->target;
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+ struct cc26xx_algo_params algo_params[2];
+ uint32_t size = 0;
+ long long start_ms;
+ long long elapsed_ms;
+ uint32_t address;
+
+ uint32_t index;
+ int retval;
+
+ if (TARGET_HALTED != target->state) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ retval = cc26xx_init(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Initialize algorithm parameters to default values */
+ buf_set_u32(algo_params[0].command, 0, 32, CC26XX_CMD_PROGRAM);
+ buf_set_u32(algo_params[1].command, 0, 32, CC26XX_CMD_PROGRAM);
+
+ /* Write requested data, ping-ponging between two buffers */
+ index = 0;
+ start_ms = timeval_ms();
+ address = bank->base + offset;
+ while (count > 0) {
+
+ if (count > cc26xx_bank->sector_length)
+ size = cc26xx_bank->sector_length;
+ else
+ size = count;
+
+ /* Put next block of data to flash into buffer */
+ retval = target_write_buffer(target, cc26xx_bank->buffer_addr[index],
+ size, buffer);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("Unable to write data to target memory");
+ break;
+ }
+
+ /* Update algo parameters for next block */
+ buf_set_u32(algo_params[index].address, 0, 32, address);
+ buf_set_u32(algo_params[index].length, 0, 32, size);
+ buf_set_u32(algo_params[index].status, 0, 32, CC26XX_BUFFER_FULL);
+
+ /* Issue flash helper algorithm parameters for block write */
+ retval = target_write_buffer(target, cc26xx_bank->params_addr[index],
+ sizeof(algo_params[index]), (uint8_t *)&algo_params[index]);
+ if (ERROR_OK != retval)
+ break;
+
+ /* Wait for next ping pong buffer to be ready */
+ index ^= 1;
+ retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[index]);
+ if (ERROR_OK != retval)
+ break;
+
+ count -= size;
+ buffer += size;
+ address += size;
+
+ elapsed_ms = timeval_ms() - start_ms;
+ if (elapsed_ms > 500)
+ keep_alive();
+ }
+
+ /* If no error yet, wait for last buffer to finish */
+ if (ERROR_OK == retval) {
+ index ^= 1;
+ retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[index]);
+ }
+
+ /* Regardless of errors, try to close down algo */
+ (void)cc26xx_quit(bank);
+
+ return retval;
+}
+
+static int cc26xx_probe(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+
+ uint32_t sector_length;
+ uint32_t value;
+ int num_sectors;
+ int max_sectors;
+
+ int retval;
+
+ retval = target_read_u32(target, FCFG1_ICEPICK_ID, &value);
+ if (ERROR_OK != retval)
+ return retval;
+ cc26xx_bank->icepick_id = value;
+
+ retval = target_read_u32(target, FCFG1_USER_ID, &value);
+ if (ERROR_OK != retval)
+ return retval;
+ cc26xx_bank->user_id = value;
+
+ cc26xx_bank->device_type = cc26xx_device_type(cc26xx_bank->icepick_id,
+ cc26xx_bank->user_id);
+
+ sector_length = cc26xx_sector_length(cc26xx_bank->icepick_id);
+
+ /* Set up appropriate flash helper algorithm */
+ switch (cc26xx_bank->icepick_id & ICEPICK_ID_MASK) {
+ case CC26X0_ICEPICK_ID:
+ case CC26X1_ICEPICK_ID:
+ case CC13X0_ICEPICK_ID:
+ /* Chameleon family device */
+ cc26xx_bank->algo_code = cc26x0_algo;
+ cc26xx_bank->algo_size = sizeof(cc26x0_algo);
+ cc26xx_bank->algo_working_size = CC26X0_WORKING_SIZE;
+ cc26xx_bank->buffer_addr[0] = CC26X0_ALGO_BUFFER_0;
+ cc26xx_bank->buffer_addr[1] = CC26X0_ALGO_BUFFER_1;
+ cc26xx_bank->params_addr[0] = CC26X0_ALGO_PARAMS_0;
+ cc26xx_bank->params_addr[1] = CC26X0_ALGO_PARAMS_1;
+ max_sectors = CC26X0_MAX_SECTORS;
+ break;
+ case CC13X2_CC26X2_ICEPICK_ID:
+ default:
+ /* Agama family device */
+ cc26xx_bank->algo_code = cc26x2_algo;
+ cc26xx_bank->algo_size = sizeof(cc26x2_algo);
+ cc26xx_bank->algo_working_size = CC26X2_WORKING_SIZE;
+ cc26xx_bank->buffer_addr[0] = CC26X2_ALGO_BUFFER_0;
+ cc26xx_bank->buffer_addr[1] = CC26X2_ALGO_BUFFER_1;
+ cc26xx_bank->params_addr[0] = CC26X2_ALGO_PARAMS_0;
+ cc26xx_bank->params_addr[1] = CC26X2_ALGO_PARAMS_1;
+ max_sectors = CC26X2_MAX_SECTORS;
+ break;
+ }
+
+ retval = target_read_u32(target, CC26XX_FLASH_SIZE_INFO, &value);
+ if (ERROR_OK != retval)
+ return retval;
+ num_sectors = value & 0xff;
+ if (num_sectors > max_sectors)
+ num_sectors = max_sectors;
+
+ bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
+ if (NULL == bank->sectors)
+ return ERROR_FAIL;
+
+ bank->base = CC26XX_FLASH_BASE_ADDR;
+ bank->num_sectors = num_sectors;
+ bank->size = num_sectors * sector_length;
+ bank->write_start_alignment = 0;
+ bank->write_end_alignment = 0;
+ cc26xx_bank->sector_length = sector_length;
+
+ for (int i = 0; i < num_sectors; i++) {
+ bank->sectors[i].offset = i * sector_length;
+ bank->sectors[i].size = sector_length;
+ bank->sectors[i].is_erased = -1;
+ bank->sectors[i].is_protected = 0;
+ }
+
+ /* We've successfully determined the stats on the flash bank */
+ cc26xx_bank->probed = true;
+
+ /* If we fall through to here, then all went well */
+
+ return ERROR_OK;
+}
+
+static int cc26xx_auto_probe(struct flash_bank *bank)
+{
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+
+ int retval = ERROR_OK;
+
+ if (bank->bank_number != 0) {
+ /* Invalid bank number somehow */
+ return ERROR_FAIL;
+ }
+
+ if (!cc26xx_bank->probed)
+ retval = cc26xx_probe(bank);
+
+ return retval;
+}
+
+static int cc26xx_protect_check(struct flash_bank *bank)
+{
+ return ERROR_OK;
+}
+
+static int cc26xx_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+ struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
+ int printed = 0;
+ const char *device;
+
+ switch (cc26xx_bank->device_type) {
+ case CC26X0_TYPE:
+ device = "CC26x0";
+ break;
+ case CC26X1_TYPE:
+ device = "CC26x1";
+ break;
+ case CC13X0_TYPE:
+ device = "CC13x0";
+ break;
+ case CC13X2_TYPE:
+ device = "CC13x2";
+ break;
+ case CC26X2_TYPE:
+ device = "CC26x2";
+ break;
+ case CC26XX_NO_TYPE:
+ default:
+ device = "Unrecognized";
+ break;
+ }
+
+ printed = snprintf(buf, buf_size,
+ "%s device: ICEPick ID 0x%08x, USER ID 0x%08x\n",
+ device, cc26xx_bank->icepick_id, cc26xx_bank->user_id);
+
+ if (printed >= buf_size)
+ return ERROR_BUF_TOO_SMALL;
+
+ return ERROR_OK;
+}
+
+struct flash_driver cc26xx_flash = {
+ .name = "cc26xx",
+ .flash_bank_command = cc26xx_flash_bank_command,
+ .erase = cc26xx_erase,
+ .protect = cc26xx_protect,
+ .write = cc26xx_write,
+ .read = default_flash_read,
+ .probe = cc26xx_probe,
+ .auto_probe = cc26xx_auto_probe,
+ .erase_check = default_flash_blank_check,
+ .protect_check = cc26xx_protect_check,
+ .info = cc26xx_info,
+ .free_driver_priv = default_flash_free_driver_priv,
+};
diff --git a/src/flash/nor/cc26xx.h b/src/flash/nor/cc26xx.h
new file mode 100644
index 0000000..51a09f1
--- /dev/null
+++ b/src/flash/nor/cc26xx.h
@@ -0,0 +1,101 @@
+/***************************************************************************
+ * Copyright (C) 2017 by Texas Instruments, Inc. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef OPENOCD_FLASH_NOR_CC26XX_H
+#define OPENOCD_FLASH_NOR_CC26XX_H
+
+/* Addresses of FCFG1 registers to access ICEPick Device ID and User ID */
+#define FCFG1_ICEPICK_ID 0x50001318
+#define FCFG1_USER_ID 0x50001294
+
+/* ICEPick device ID mask and values */
+#define ICEPICK_ID_MASK 0x0fffffff
+#define ICEPICK_REV_MASK 0xf0000000
+#define CC26X0_ICEPICK_ID 0x0b99a02f
+#define CC26X1_ICEPICK_ID 0x0b9bd02f
+#define CC13X0_ICEPICK_ID 0x0b9be02f
+#define CC13X2_CC26X2_ICEPICK_ID 0x0bb4102f
+
+/* User ID mask for Agama CC13x2 vs CC26x2 */
+#define USER_ID_CC13_MASK 0x00800000
+
+/* Common CC26xx/CC13xx flash and memory parameters */
+#define CC26XX_FLASH_BASE_ADDR 0x00000000
+#define CC26XX_FLASH_SIZE_INFO 0x4003002c
+#define CC26XX_SRAM_SIZE_INFO 0x40082250
+#define CC26XX_ALGO_BASE_ADDRESS 0x20000000
+
+/* Chameleon CC26x0/CC13x0 specific parameters */
+#define CC26X0_MAX_SECTORS 32
+#define CC26X0_SECTOR_LENGTH 0x1000
+#define CC26X0_ALGO_BUFFER_0 0x20001c00
+#define CC26X0_ALGO_BUFFER_1 0x20002c00
+#define CC26X0_ALGO_PARAMS_0 0x20001bd8
+#define CC26X0_ALGO_PARAMS_1 0x20001bec
+#define CC26X0_WORKING_SIZE (CC26X0_ALGO_BUFFER_1 + CC26X0_SECTOR_LENGTH - \
+ CC26XX_ALGO_BASE_ADDRESS)
+
+/* Agama CC26x2/CC13x2 specific parameters */
+#define CC26X2_MAX_SECTORS 128
+#define CC26X2_SECTOR_LENGTH 0x2000
+#define CC26X2_ALGO_BUFFER_0 0x20002000
+#define CC26X2_ALGO_BUFFER_1 0x20004000
+#define CC26X2_ALGO_PARAMS_0 0x20001fd8
+#define CC26X2_ALGO_PARAMS_1 0x20001fec
+#define CC26X2_WORKING_SIZE (CC26X2_ALGO_BUFFER_1 + CC26X2_SECTOR_LENGTH - \
+ CC26XX_ALGO_BASE_ADDRESS)
+
+/* CC26xx flash helper algorithm buffer flags */
+#define CC26XX_BUFFER_EMPTY 0x00000000
+#define CC26XX_BUFFER_FULL 0xffffffff
+
+/* CC26XX flash helper algorithm commands */
+#define CC26XX_CMD_NO_ACTION 0
+#define CC26XX_CMD_ERASE_ALL 1
+#define CC26XX_CMD_PROGRAM 2
+#define CC26XX_CMD_ERASE_AND_PROGRAM 3
+#define CC26XX_CMD_ERASE_AND_PROGRAM_WITH_RETAIN 4
+#define CC26XX_CMD_ERASE_SECTORS 5
+
+/* CC26xx and CC13xx device types */
+#define CC26XX_NO_TYPE 0 /* Device type not determined yet */
+#define CC26X0_TYPE 1 /* CC26x0 Chameleon device */
+#define CC26X1_TYPE 2 /* CC26x1 Chameleon device */
+#define CC26X2_TYPE 3 /* CC26x2 Agama device */
+#define CC13X0_TYPE 4 /* CC13x0 Chameleon device */
+#define CC13X2_TYPE 5 /* CC13x2 Agama device */
+
+/* Flash helper algorithm parameter block struct */
+#define CC26XX_STATUS_OFFSET 0x0c
+struct cc26xx_algo_params {
+ uint8_t address[4];
+ uint8_t length[4];
+ uint8_t command[4];
+ uint8_t status[4];
+};
+
+/* Flash helper algorithm for CC26x0 Chameleon targets */
+const uint8_t cc26x0_algo[] = {
+#include "../../../contrib/loaders/flash/cc26xx/cc26x0_algo.inc"
+};
+
+/* Flash helper algorithm for CC26x2 Agama targets */
+const uint8_t cc26x2_algo[] = {
+#include "../../../contrib/loaders/flash/cc26xx/cc26x2_algo.inc"
+};
+
+#endif /* OPENOCD_FLASH_NOR_CC26XX_H */
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index a094c20..2b3146d 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -33,6 +33,7 @@ extern struct flash_driver atsamv_flash;
extern struct flash_driver avr_flash;
extern struct flash_driver bluenrgx_flash;
extern struct flash_driver cc3220sf_flash;
+extern struct flash_driver cc26xx_flash;
extern struct flash_driver cfi_flash;
extern struct flash_driver dsp5680xx_flash;
extern struct flash_driver efm32_flash;
@@ -50,6 +51,7 @@ extern struct flash_driver lpc2900_flash;
extern struct flash_driver lpcspifi_flash;
extern struct flash_driver mdr_flash;
extern struct flash_driver mrvlqspi_flash;
+extern struct flash_driver msp432_flash;
extern struct flash_driver niietcm4_flash;
extern struct flash_driver nrf5_flash;
extern struct flash_driver nrf51_flash;
@@ -96,6 +98,7 @@ static struct flash_driver *flash_drivers[] = {
&avr_flash,
&bluenrgx_flash,
&cc3220sf_flash,
+ &cc26xx_flash,
&cfi_flash,
&dsp5680xx_flash,
&efm32_flash,
@@ -113,6 +116,7 @@ static struct flash_driver *flash_drivers[] = {
&lpcspifi_flash,
&mdr_flash,
&mrvlqspi_flash,
+ &msp432_flash,
&niietcm4_flash,
&nrf5_flash,
&nrf51_flash,
diff --git a/src/flash/nor/msp432.c b/src/flash/nor/msp432.c
new file mode 100644
index 0000000..5caa052
--- /dev/null
+++ b/src/flash/nor/msp432.c
@@ -0,0 +1,1103 @@
+/***************************************************************************
+ * Copyright (C) 2018 by Texas Instruments, Inc. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include "msp432.h"
+#include <helper/binarybuffer.h>
+#include <helper/time_support.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+#include <target/image.h>
+
+/* MSP432P4 hardware registers */
+#define P4_FLASH_MAIN_SIZE_REG 0xE0043020
+#define P4_FLASH_INFO_SIZE_REG 0xE0043024
+#define P4_DEVICE_ID_REG 0x0020100C
+#define P4_HARDWARE_REV_REG 0x00201010
+
+/* MSP432E4 hardware registers */
+#define E4_DID0_REG 0x400FE000
+#define E4_DID1_REG 0x400FE004
+
+#define FLASH_TIMEOUT 8000
+
+#define SUPPORT_MESSAGE \
+ "Your pre-production MSP432P401x silicon is not fully supported\n" \
+ "You can find more information at www.ti.com/product/MSP432P401R"
+
+struct msp432_bank {
+ uint32_t device_id;
+ uint32_t hardware_rev;
+ int family_type;
+ int device_type;
+ uint32_t sector_length;
+ bool probed[2];
+ bool unlock_bsl;
+ struct working_area *working_area;
+ struct armv7m_algorithm armv7m_info;
+};
+
+static int msp432_auto_probe(struct flash_bank *bank);
+
+static int msp432_device_type(uint32_t family_type, uint32_t device_id,
+ uint32_t hardware_rev)
+{
+ int device_type = MSP432_NO_TYPE;
+
+ if (MSP432E4 == family_type) {
+ /* MSP432E4 device family */
+
+ if (device_id == 0x180C0002) {
+ if (hardware_rev == 0x102DC06E) {
+ /* The 01Y variant */
+ device_type = MSP432E401Y;
+ } else if (hardware_rev == 0x1032E076) {
+ /* The 11Y variant */
+ device_type = MSP432E411Y;
+ } else {
+ /* Reasonable guess that this is a new variant */
+ device_type = MSP432E4X_GUESS;
+ }
+ } else {
+ /* Wild guess that this is an MSP432E4 */
+ device_type = MSP432E4X_GUESS;
+ }
+ } else {
+ /* MSP432P4 device family */
+
+ /* Examine the device ID and hardware revision to get the device type */
+ switch (device_id) {
+ case 0xA000:
+ case 0xA001:
+ case 0xA002:
+ case 0xA003:
+ case 0xA004:
+ case 0xA005:
+ /* Device is definitely MSP432P401x, check hardware revision */
+ if (hardware_rev == 0x41 || hardware_rev == 0x42) {
+ /* Rev A or B of the silicon has been deprecated */
+ device_type = MSP432P401X_DEPR;
+ } else if (hardware_rev >= 0x43 && hardware_rev <= 0x49) {
+ /* Current and future revisions of the MSP432P401x device */
+ device_type = MSP432P401X;
+ } else {
+ /* Unknown or unanticipated hardware revision */
+ device_type = MSP432P401X_GUESS;
+ }
+ break;
+ case 0xA010:
+ case 0xA012:
+ case 0xA016:
+ case 0xA019:
+ case 0xA01F:
+ case 0xA020:
+ case 0xA022:
+ case 0xA026:
+ case 0xA029:
+ case 0xA02F:
+ /* Device is definitely MSP432P411x, check hardware revision */
+ if (hardware_rev >= 0x41 && hardware_rev <= 0x49) {
+ /* Current and future revisions of the MSP432P411x device */
+ device_type = MSP432P411X;
+ } else {
+ /* Unknown or unanticipated hardware revision */
+ device_type = MSP432P411X_GUESS;
+ }
+ break;
+ case 0xFFFF:
+ /* Device is very early silicon that has been deprecated */
+ device_type = MSP432P401X_DEPR;
+ break;
+ default:
+ if (device_id < 0xA010) {
+ /* Wild guess that this is an MSP432P401x */
+ device_type = MSP432P401X_GUESS;
+ } else {
+ /* Reasonable guess that this is a new variant */
+ device_type = MSP432P411X_GUESS;
+ }
+ break;
+ }
+ }
+
+ return device_type;
+}
+
+static const char *msp432_return_text(uint32_t return_code)
+{
+ switch (return_code) {
+ case FLASH_BUSY:
+ return "FLASH_BUSY";
+ case FLASH_SUCCESS:
+ return "FLASH_SUCCESS";
+ case FLASH_ERROR:
+ return "FLASH_ERROR";
+ case FLASH_TIMEOUT_ERROR:
+ return "FLASH_TIMEOUT_ERROR";
+ case FLASH_VERIFY_ERROR:
+ return "FLASH_VERIFY_WRONG";
+ case FLASH_WRONG_COMMAND:
+ return "FLASH_WRONG_COMMAND";
+ case FLASH_POWER_ERROR:
+ return "FLASH_POWER_ERROR";
+ default:
+ return "UNDEFINED_RETURN_CODE";
+ }
+}
+
+static void msp432_init_params(struct msp432_algo_params *algo_params)
+{
+ buf_set_u32(algo_params->flash_command, 0, 32, FLASH_NO_COMMAND);
+ buf_set_u32(algo_params->return_code, 0, 32, 0);
+ buf_set_u32(algo_params->_reserved0, 0, 32, 0);
+ buf_set_u32(algo_params->address, 0, 32, 0);
+ buf_set_u32(algo_params->length, 0, 32, 0);
+ buf_set_u32(algo_params->buffer1_status, 0, 32, BUFFER_INACTIVE);
+ buf_set_u32(algo_params->buffer2_status, 0, 32, BUFFER_INACTIVE);
+ buf_set_u32(algo_params->erase_param, 0, 32, FLASH_ERASE_MAIN);
+ buf_set_u32(algo_params->unlock_bsl, 0, 32, FLASH_LOCK_BSL);
+}
+
+static int msp432_exec_cmd(struct target *target, struct msp432_algo_params
+ *algo_params, uint32_t command)
+{
+ int retval;
+
+ /* Make sure the given params do not include the command */
+ buf_set_u32(algo_params->flash_command, 0, 32, FLASH_NO_COMMAND);
+ buf_set_u32(algo_params->return_code, 0, 32, 0);
+ buf_set_u32(algo_params->buffer1_status, 0, 32, BUFFER_INACTIVE);
+ buf_set_u32(algo_params->buffer2_status, 0, 32, BUFFER_INACTIVE);
+
+ /* Write out parameters to target memory */
+ retval = target_write_buffer(target, ALGO_PARAMS_BASE_ADDR,
+ sizeof(struct msp432_algo_params), (uint8_t *)algo_params);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Write out command to target memory */
+ retval = target_write_buffer(target, ALGO_FLASH_COMMAND_ADDR,
+ sizeof(command), (uint8_t *)&command);
+
+ return retval;
+}
+
+static int msp432_wait_return_code(struct target *target)
+{
+ uint32_t return_code = 0;
+ long long start_ms;
+ long long elapsed_ms;
+
+ int retval = ERROR_OK;
+
+ start_ms = timeval_ms();
+ while ((0 == return_code) || (FLASH_BUSY == return_code)) {
+ retval = target_read_buffer(target, ALGO_RETURN_CODE_ADDR,
+ sizeof(return_code), (uint8_t *)&return_code);
+ if (ERROR_OK != retval)
+ return retval;
+
+ elapsed_ms = timeval_ms() - start_ms;
+ if (elapsed_ms > 500)
+ keep_alive();
+ if (elapsed_ms > FLASH_TIMEOUT)
+ break;
+ };
+
+ if (FLASH_SUCCESS != return_code) {
+ LOG_ERROR("msp432: Flash operation failed: %s",
+ msp432_return_text(return_code));
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static int msp432_wait_inactive(struct target *target, uint32_t buffer)
+{
+ uint32_t status_code = BUFFER_ACTIVE;
+ uint32_t status_addr;
+ long long start_ms;
+ long long elapsed_ms;
+
+ int retval;
+
+ switch (buffer) {
+ case 1: /* Buffer 1 */
+ status_addr = ALGO_BUFFER1_STATUS_ADDR;
+ break;
+ case 2: /* Buffer 2 */
+ status_addr = ALGO_BUFFER2_STATUS_ADDR;
+ break;
+ default:
+ return ERROR_FAIL;
+ }
+
+ start_ms = timeval_ms();
+ while (BUFFER_INACTIVE != status_code) {
+ retval = target_read_buffer(target, status_addr, sizeof(status_code),
+ (uint8_t *)&status_code);
+ if (ERROR_OK != retval)
+ return retval;
+
+ elapsed_ms = timeval_ms() - start_ms;
+ if (elapsed_ms > 500)
+ keep_alive();
+ if (elapsed_ms > FLASH_TIMEOUT)
+ break;
+ };
+
+ if (BUFFER_INACTIVE != status_code) {
+ LOG_ERROR(
+ "msp432: Flash operation failed: buffer not written to flash");
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static int msp432_init(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct msp432_bank *msp432_bank = bank->driver_priv;
+ struct msp432_algo_params algo_params;
+ struct reg_param reg_params[1];
+
+ const uint8_t *loader_code;
+ uint32_t loader_size;
+ uint32_t algo_entry_addr;
+ int retval;
+
+ /* Make sure we've probed the flash to get the device and size */
+ retval = msp432_auto_probe(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Choose appropriate flash helper algorithm */
+ switch (msp432_bank->device_type) {
+ case MSP432P401X:
+ case MSP432P401X_DEPR:
+ case MSP432P401X_GUESS:
+ default:
+ loader_code = msp432p401x_algo;
+ loader_size = sizeof(msp432p401x_algo);
+ algo_entry_addr = P4_ALGO_ENTRY_ADDR;
+ break;
+ case MSP432P411X:
+ case MSP432P411X_GUESS:
+ loader_code = msp432p411x_algo;
+ loader_size = sizeof(msp432p411x_algo);
+ algo_entry_addr = P4_ALGO_ENTRY_ADDR;
+ break;
+ case MSP432E401Y:
+ case MSP432E411Y:
+ case MSP432E4X_GUESS:
+ loader_code = msp432e4x_algo;
+ loader_size = sizeof(msp432e4x_algo);
+ algo_entry_addr = E4_ALGO_ENTRY_ADDR;
+ break;
+ }
+
+ /* Issue warnings if this is a device we may not be able to flash */
+ if (MSP432P401X_GUESS == msp432_bank->device_type ||
+ MSP432P411X_GUESS == msp432_bank->device_type) {
+ /* Explicit device type check failed. Report this. */
+ LOG_WARNING(
+ "msp432: Unrecognized MSP432P4 Device ID and Hardware "
+ "Rev (%04X, %02X)", msp432_bank->device_id,
+ msp432_bank->hardware_rev);
+ } else if (MSP432P401X_DEPR == msp432_bank->device_type) {
+ LOG_WARNING(
+ "msp432: MSP432P401x pre-production device (deprecated "
+ "silicon)\n" SUPPORT_MESSAGE);
+ } else if (MSP432E4X_GUESS == msp432_bank->device_type) {
+ /* Explicit device type check failed. Report this. */
+ LOG_WARNING(
+ "msp432: Unrecognized MSP432E4 DID0 and DID1 values "
+ "(%08X, %08X)", msp432_bank->device_id,
+ msp432_bank->hardware_rev);
+ }
+
+ /* Check for working area to use for flash helper algorithm */
+ if (NULL != msp432_bank->working_area)
+ target_free_working_area(target, msp432_bank->working_area);
+ retval = target_alloc_working_area(target, ALGO_WORKING_SIZE,
+ &msp432_bank->working_area);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Confirm the defined working address is the area we need to use */
+ if (ALGO_BASE_ADDR != msp432_bank->working_area->address)
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+
+ /* Write flash helper algorithm into target memory */
+ retval = target_write_buffer(target, ALGO_BASE_ADDR, loader_size,
+ loader_code);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Initialize the ARMv7 specific info to run the algorithm */
+ msp432_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+ msp432_bank->armv7m_info.core_mode = ARM_MODE_THREAD;
+
+ /* Initialize algorithm parameters to default values */
+ msp432_init_params(&algo_params);
+
+ /* Write out parameters to target memory */
+ retval = target_write_buffer(target, ALGO_PARAMS_BASE_ADDR,
+ sizeof(algo_params), (uint8_t *)&algo_params);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Initialize stack pointer for flash helper algorithm */
+ init_reg_param(&reg_params[0], "sp", 32, PARAM_OUT);
+ buf_set_u32(reg_params[0].value, 0, 32, ALGO_STACK_POINTER_ADDR);
+
+ /* Begin executing the flash helper algorithm */
+ retval = target_start_algorithm(target, 0, 0, 1, reg_params,
+ algo_entry_addr, 0, &msp432_bank->armv7m_info);
+ destroy_reg_param(&reg_params[0]);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("msp432: Failed to start flash helper algorithm");
+ return retval;
+ }
+
+ /*
+ * At this point, the algorithm is running on the target and
+ * ready to receive commands and data to flash the target
+ */
+
+ /* Issue the init command to the flash helper algorithm */
+ retval = msp432_exec_cmd(target, &algo_params, FLASH_INIT);
+ if (ERROR_OK != retval)
+ return retval;
+
+ retval = msp432_wait_return_code(target);
+
+ return retval;
+}
+
+static int msp432_quit(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct msp432_bank *msp432_bank = bank->driver_priv;
+ struct msp432_algo_params algo_params;
+
+ int retval;
+
+ /* Initialize algorithm parameters to default values */
+ msp432_init_params(&algo_params);
+
+ /* Issue the exit command to the flash helper algorithm */
+ retval = msp432_exec_cmd(target, &algo_params, FLASH_EXIT);
+ if (ERROR_OK != retval)
+ return retval;
+
+ (void)msp432_wait_return_code(target);
+
+ /* Regardless of the return code, attempt to halt the target */
+ (void)target_halt(target);
+
+ /* Now confirm target halted and clean up from flash helper algorithm */
+ retval = target_wait_algorithm(target, 0, NULL, 0, NULL, 0, FLASH_TIMEOUT,
+ &msp432_bank->armv7m_info);
+
+ target_free_working_area(target, msp432_bank->working_area);
+ msp432_bank->working_area = NULL;
+
+ return retval;
+}
+
+static int msp432_mass_erase(struct flash_bank *bank, bool all)
+{
+ struct target *target = bank->target;
+ struct msp432_bank *msp432_bank = bank->driver_priv;
+ struct msp432_algo_params algo_params;
+
+ int retval;
+
+ if (TARGET_HALTED != target->state) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ retval = msp432_init(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Initialize algorithm parameters to default values */
+ msp432_init_params(&algo_params);
+ if (all) {
+ buf_set_u32(algo_params.erase_param, 0, 32,
+ FLASH_ERASE_MAIN | FLASH_ERASE_INFO);
+ if (msp432_bank->unlock_bsl)
+ buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL);
+ }
+
+ /* Issue the mass erase command to the flash helper algorithm */
+ retval = msp432_exec_cmd(target, &algo_params, FLASH_MASS_ERASE);
+ if (ERROR_OK != retval) {
+ (void)msp432_quit(bank);
+ return retval;
+ }
+
+ retval = msp432_wait_return_code(target);
+ if (ERROR_OK != retval) {
+ (void)msp432_quit(bank);
+ return retval;
+ }
+
+ retval = msp432_quit(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ return retval;
+}
+
+COMMAND_HANDLER(msp432_mass_erase_command)
+{
+ struct flash_bank *bank;
+ struct msp432_bank *msp432_bank;
+ bool all;
+ int retval;
+
+ if (0 == CMD_ARGC) {
+ all = false;
+ } else if (1 == CMD_ARGC) {
+ /* Check argument for how much to erase */
+ if (0 == strcmp(CMD_ARGV[0], "main"))
+ all = false;
+ else if (0 == strcmp(CMD_ARGV[0], "all"))
+ all = true;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ } else {
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ retval = get_flash_bank_by_num(0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ msp432_bank = bank->driver_priv;
+
+ if (MSP432E4 == msp432_bank->family_type) {
+ /* MSP432E4 does not have main vs info regions, ignore "all" */
+ all = false;
+ }
+
+ retval = msp432_mass_erase(bank, all);
+ if (ERROR_OK != retval)
+ return retval;
+
+ if (MSP432E4 == msp432_bank->family_type) {
+ /* MSP432E4 does not have main vs info regions */
+ LOG_INFO("msp432: Mass erase of flash is complete");
+ } else {
+ LOG_INFO("msp432: Mass erase of %s is complete",
+ all ? "main + info flash" : "main flash");
+ }
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(msp432_bsl_command)
+{
+ struct flash_bank *bank;
+ struct msp432_bank *msp432_bank;
+ int retval;
+
+ if (1 < CMD_ARGC)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ retval = get_flash_bank_by_num(0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ msp432_bank = bank->driver_priv;
+
+ if (MSP432E4 == msp432_bank->family_type) {
+ LOG_WARNING("msp432: MSP432E4 does not have a BSL region");
+ return ERROR_OK;
+ }
+
+ if (1 == CMD_ARGC) {
+ if (0 == strcmp(CMD_ARGV[0], "lock"))
+ msp432_bank->unlock_bsl = false;
+ else if (0 == strcmp(CMD_ARGV[0], "unlock"))
+ msp432_bank->unlock_bsl = true;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ LOG_INFO("msp432: BSL flash region is currently %slocked",
+ msp432_bank->unlock_bsl ? "un" : "");
+
+ return ERROR_OK;
+}
+
+FLASH_BANK_COMMAND_HANDLER(msp432_flash_bank_command)
+{
+ struct msp432_bank *msp432_bank;
+
+ if (CMD_ARGC < 6)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ msp432_bank = malloc(sizeof(struct msp432_bank));
+ if (NULL == msp432_bank)
+ return ERROR_FAIL;
+
+ /* Initialize private flash information */
+ msp432_bank->device_id = 0;
+ msp432_bank->hardware_rev = 0;
+ msp432_bank->family_type = MSP432_NO_FAMILY;
+ msp432_bank->device_type = MSP432_NO_TYPE;
+ msp432_bank->sector_length = 0x1000;
+ msp432_bank->probed[0] = false;
+ msp432_bank->probed[1] = false;
+ msp432_bank->unlock_bsl = false;
+ msp432_bank->working_area = NULL;
+
+ /* Finish initialization of bank 0 (main flash) */
+ bank->driver_priv = msp432_bank;
+ bank->next = NULL;
+
+ return ERROR_OK;
+}
+
+static int msp432_erase(struct flash_bank *bank, int first, int last)
+{
+ struct target *target = bank->target;
+ struct msp432_bank *msp432_bank = bank->driver_priv;
+ struct msp432_algo_params algo_params;
+
+ int retval;
+
+ if (TARGET_HALTED != target->state) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* Do a mass erase if user requested all sectors of main flash */
+ if ((0 == bank->bank_number) && (first == 0) &&
+ (last == (bank->num_sectors - 1))) {
+ /* Request mass erase of main flash */
+ return msp432_mass_erase(bank, false);
+ }
+
+ retval = msp432_init(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Initialize algorithm parameters to default values */
+ msp432_init_params(&algo_params);
+
+ /* Adjust params if this is the info bank */
+ if (1 == bank->bank_number) {
+ buf_set_u32(algo_params.erase_param, 0, 32, FLASH_ERASE_INFO);
+ /* And flag if BSL is unlocked */
+ if (msp432_bank->unlock_bsl)
+ buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL);
+ }
+
+ /* Erase requested sectors one by one */
+ for (int i = first; i <= last; i++) {
+
+ /* Skip TVL (read-only) sector of the info bank */
+ if (1 == bank->bank_number && 1 == i)
+ continue;
+
+ /* Skip BSL sectors of info bank if locked */
+ if (1 == bank->bank_number && (2 == i || 3 == i) &&
+ !msp432_bank->unlock_bsl)
+ continue;
+
+ /* Convert sector number to starting address of sector */
+ buf_set_u32(algo_params.address, 0, 32, bank->base +
+ (i * msp432_bank->sector_length));
+
+ /* Issue the sector erase command to the flash helper algorithm */
+ retval = msp432_exec_cmd(target, &algo_params, FLASH_SECTOR_ERASE);
+ if (ERROR_OK != retval) {
+ (void)msp432_quit(bank);
+ return retval;
+ }
+
+ retval = msp432_wait_return_code(target);
+ if (ERROR_OK != retval) {
+ (void)msp432_quit(bank);
+ return retval;
+ }
+ }
+
+ retval = msp432_quit(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ return retval;
+}
+
+static int msp432_protect(struct flash_bank *bank, int set, int first,
+ int last)
+{
+ return ERROR_OK;
+}
+
+static int msp432_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct target *target = bank->target;
+ struct msp432_bank *msp432_bank = bank->driver_priv;
+ struct msp432_algo_params algo_params;
+ uint32_t size;
+ uint32_t data_ready = BUFFER_DATA_READY;
+ long long start_ms;
+ long long elapsed_ms;
+
+ int retval;
+
+ if (TARGET_HALTED != target->state) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /*
+ * Block attempts to write to read-only sectors of flash
+ * The TVL region in sector 1 of the info flash is always read-only
+ * The BSL region in sectors 2 and 3 of the info flash may be unlocked
+ * The helper algorithm will hang on attempts to write to TVL
+ */
+ if (1 == bank->bank_number) {
+ /* Set read-only start to TVL sector */
+ uint32_t start = 0x1000;
+ /* Set read-only end after BSL region if locked */
+ uint32_t end = (msp432_bank->unlock_bsl) ? 0x2000 : 0x4000;
+ /* Check if request includes anything in read-only sectors */
+ if ((offset + count - 1) < start || offset >= end) {
+ /* The request includes no bytes in read-only sectors */
+ /* Fall out and process the request normally */
+ } else {
+ /* Send a request for anything before read-only sectors */
+ if (offset < start) {
+ uint32_t start_count = MIN(start - offset, count);
+ retval = msp432_write(bank, buffer, offset, start_count);
+ if (ERROR_OK != retval)
+ return retval;
+ }
+ /* Send a request for anything after read-only sectors */
+ if ((offset + count - 1) >= end) {
+ uint32_t skip = end - offset;
+ count -= skip;
+ offset += skip;
+ buffer += skip;
+ return msp432_write(bank, buffer, offset, count);
+ } else {
+ /* Request is entirely in read-only sectors */
+ return ERROR_OK;
+ }
+ }
+ }
+
+ retval = msp432_init(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Initialize algorithm parameters to default values */
+ msp432_init_params(&algo_params);
+
+ /* Set up parameters for requested flash write operation */
+ buf_set_u32(algo_params.address, 0, 32, bank->base + offset);
+ buf_set_u32(algo_params.length, 0, 32, count);
+
+ /* Check if this is the info bank */
+ if (1 == bank->bank_number) {
+ /* And flag if BSL is unlocked */
+ if (msp432_bank->unlock_bsl)
+ buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL);
+ }
+
+ /* Set up flash helper algorithm to continuous flash mode */
+ retval = msp432_exec_cmd(target, &algo_params, FLASH_CONTINUOUS);
+ if (ERROR_OK != retval) {
+ (void)msp432_quit(bank);
+ return retval;
+ }
+
+ /* Write requested data, one buffer at a time */
+ start_ms = timeval_ms();
+ while (count > 0) {
+
+ if (count > ALGO_BUFFER_SIZE)
+ size = ALGO_BUFFER_SIZE;
+ else
+ size = count;
+
+ /* Put next block of data to flash into buffer */
+ retval = target_write_buffer(target, ALGO_BUFFER1_ADDR, size, buffer);
+ if (ERROR_OK != retval) {
+ LOG_ERROR("Unable to write data to target memory");
+ (void)msp432_quit(bank);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ /* Signal the flash helper algorithm that data is ready to flash */
+ retval = target_write_buffer(target, ALGO_BUFFER1_STATUS_ADDR,
+ sizeof(data_ready), (uint8_t *)&data_ready);
+ if (ERROR_OK != retval) {
+ (void)msp432_quit(bank);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ retval = msp432_wait_inactive(target, 1);
+ if (ERROR_OK != retval) {
+ (void)msp432_quit(bank);
+ return retval;
+ }
+
+ count -= size;
+ buffer += size;
+
+ elapsed_ms = timeval_ms() - start_ms;
+ if (elapsed_ms > 500)
+ keep_alive();
+ }
+
+ /* Confirm that the flash helper algorithm is finished */
+ retval = msp432_wait_return_code(target);
+ if (ERROR_OK != retval) {
+ (void)msp432_quit(bank);
+ return retval;
+ }
+
+ retval = msp432_quit(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ return retval;
+}
+
+static int msp432_probe(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct msp432_bank *msp432_bank = bank->driver_priv;
+
+ char *name;
+
+ uint32_t device_id;
+ uint32_t hardware_rev;
+
+ uint32_t base;
+ uint32_t sector_length;
+ uint32_t size;
+ int num_sectors;
+ int bank_id;
+
+ int retval;
+
+ bank_id = bank->bank_number;
+
+ /* Read the flash size register to determine this is a P4 or not */
+ /* MSP432P4s will return the size of flash. MSP432E4s will return zero */
+ retval = target_read_u32(target, P4_FLASH_MAIN_SIZE_REG, &size);
+ if (ERROR_OK != retval)
+ return retval;
+
+ if (0 == size) {
+ /* This is likely an MSP432E4 */
+ msp432_bank->family_type = MSP432E4;
+
+ retval = target_read_u32(target, E4_DID0_REG, &device_id);
+ if (ERROR_OK != retval)
+ return retval;
+
+ msp432_bank->device_id = device_id;
+
+ retval = target_read_u32(target, E4_DID1_REG, &hardware_rev);
+ if (ERROR_OK != retval)
+ return retval;
+
+ msp432_bank->hardware_rev = hardware_rev;
+ } else {
+ /* This is likely an MSP432P4 */
+ msp432_bank->family_type = MSP432P4;
+
+ retval = target_read_u32(target, P4_DEVICE_ID_REG, &device_id);
+ if (ERROR_OK != retval)
+ return retval;
+
+ msp432_bank->device_id = device_id & 0xFFFF;
+
+ retval = target_read_u32(target, P4_HARDWARE_REV_REG, &hardware_rev);
+ if (ERROR_OK != retval)
+ return retval;
+
+ msp432_bank->hardware_rev = hardware_rev & 0xFF;
+ }
+
+ msp432_bank->device_type = msp432_device_type(msp432_bank->family_type,
+ msp432_bank->device_id, msp432_bank->hardware_rev);
+
+ /* If not already allocated, create the info bank for MSP432P4 */
+ /* We could not determine it was needed until device was probed */
+ if (MSP432P4 == msp432_bank->family_type) {
+ /* If we've been given bank 1, then this was already done */
+ if (0 == bank_id) {
+ /* And only allocate it if it doesn't exist yet */
+ if (NULL == bank->next) {
+ struct flash_bank *info_bank;
+ info_bank = malloc(sizeof(struct flash_bank));
+ if (NULL == info_bank)
+ return ERROR_FAIL;
+
+ name = malloc(strlen(bank->name)+1);
+ if (NULL == name) {
+ free(info_bank);
+ return ERROR_FAIL;
+ }
+ strcpy(name, bank->name);
+
+ /* Initialize bank 1 (info region) */
+ info_bank->name = name;
+ info_bank->target = bank->target;
+ info_bank->driver = bank->driver;
+ info_bank->driver_priv = bank->driver_priv;
+ info_bank->bank_number = 1;
+ info_bank->base = 0x00200000;
+ info_bank->size = 0;
+ info_bank->chip_width = 0;
+ info_bank->bus_width = 0;
+ info_bank->erased_value = 0xff;
+ info_bank->default_padded_value = 0xff;
+ info_bank->write_start_alignment = 0;
+ info_bank->write_end_alignment = 0;
+ info_bank->minimal_write_gap = FLASH_WRITE_GAP_SECTOR;
+ info_bank->num_sectors = 0;
+ info_bank->sectors = NULL;
+ info_bank->num_prot_blocks = 0;
+ info_bank->prot_blocks = NULL;
+ info_bank->next = NULL;
+
+ /* Enable the new bank */
+ bank->next = info_bank;
+ }
+ }
+ }
+
+ if (MSP432P4 == msp432_bank->family_type) {
+ /* Set up MSP432P4 specific flash parameters */
+ if (0 == bank_id) {
+ retval = target_read_u32(target, P4_FLASH_MAIN_SIZE_REG, &size);
+ if (ERROR_OK != retval)
+ return retval;
+
+ base = P4_FLASH_MAIN_BASE;
+ sector_length = P4_SECTOR_LENGTH;
+ num_sectors = size / sector_length;
+ } else if (1 == bank_id) {
+ if (msp432_bank->device_type == MSP432P411X ||
+ msp432_bank->device_type == MSP432P411X_GUESS) {
+ /* MSP432P411x has an info size register, use that for size */
+ retval = target_read_u32(target, P4_FLASH_INFO_SIZE_REG, &size);
+ if (ERROR_OK != retval)
+ return retval;
+ } else {
+ /* All other MSP432P401x devices have fixed info region size */
+ size = 0x4000; /* 16 KB info region */
+ }
+ base = P4_FLASH_INFO_BASE;
+ sector_length = P4_SECTOR_LENGTH;
+ num_sectors = size / sector_length;
+ } else {
+ /* Invalid bank number somehow */
+ return ERROR_FAIL;
+ }
+ } else {
+ /* Set up MSP432E4 specific flash parameters */
+ base = E4_FLASH_BASE;
+ size = E4_FLASH_SIZE;
+ sector_length = E4_SECTOR_LENGTH;
+ num_sectors = size / sector_length;
+ }
+
+ if (NULL != bank->sectors) {
+ free(bank->sectors);
+ bank->sectors = NULL;
+ }
+
+ bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
+ if (NULL == bank->sectors)
+ return ERROR_FAIL;
+
+ bank->base = base;
+ bank->size = size;
+ bank->write_start_alignment = 0;
+ bank->write_end_alignment = 0;
+ bank->num_sectors = num_sectors;
+ msp432_bank->sector_length = sector_length;
+
+ for (int i = 0; i < num_sectors; i++) {
+ bank->sectors[i].offset = i * sector_length;
+ bank->sectors[i].size = sector_length;
+ bank->sectors[i].is_erased = -1;
+ bank->sectors[i].is_protected = 0;
+ }
+
+ /* We've successfully determined the stats on this flash bank */
+ msp432_bank->probed[bank_id] = true;
+
+ /* If we fall through to here, then all went well */
+
+ return ERROR_OK;
+}
+
+static int msp432_auto_probe(struct flash_bank *bank)
+{
+ struct msp432_bank *msp432_bank = bank->driver_priv;
+
+ int retval = ERROR_OK;
+
+ if (bank->bank_number < 0 || bank->bank_number > 1) {
+ /* Invalid bank number somehow */
+ return ERROR_FAIL;
+ }
+
+ if (!msp432_bank->probed[bank->bank_number])
+ retval = msp432_probe(bank);
+
+ return retval;
+}
+
+static int msp432_protect_check(struct flash_bank *bank)
+{
+ return ERROR_OK;
+}
+
+static int msp432_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+ struct msp432_bank *msp432_bank = bank->driver_priv;
+ int printed = 0;
+
+ switch (msp432_bank->device_type) {
+ case MSP432P401X_DEPR:
+ if (0xFFFF == msp432_bank->device_id) {
+ /* Very early pre-production silicon currently deprecated */
+ printed = snprintf(buf, buf_size,
+ "MSP432P401x pre-production device (deprecated silicon)\n"
+ SUPPORT_MESSAGE);
+ } else {
+ /* Revision A or B silicon, also deprecated */
+ printed = snprintf(buf, buf_size,
+ "MSP432P401x Device Rev %c (deprecated silicon)\n"
+ SUPPORT_MESSAGE, (char)msp432_bank->hardware_rev);
+ }
+ break;
+ case MSP432P401X:
+ printed = snprintf(buf, buf_size,
+ "MSP432P401x Device Rev %c\n",
+ (char)msp432_bank->hardware_rev);
+ break;
+ case MSP432P411X:
+ printed = snprintf(buf, buf_size,
+ "MSP432P411x Device Rev %c\n",
+ (char)msp432_bank->hardware_rev);
+ break;
+ case MSP432E401Y:
+ printed = snprintf(buf, buf_size, "MSP432E401Y Device\n");
+ break;
+ case MSP432E411Y:
+ printed = snprintf(buf, buf_size, "MSP432E411Y Device\n");
+ break;
+ case MSP432E4X_GUESS:
+ printed = snprintf(buf, buf_size,
+ "Unrecognized MSP432E4 DID0 and DID1 IDs (%08X, %08X)",
+ msp432_bank->device_id, msp432_bank->hardware_rev);
+ break;
+ case MSP432P401X_GUESS:
+ case MSP432P411X_GUESS:
+ default:
+ printed = snprintf(buf, buf_size,
+ "Unrecognized MSP432P4 Device ID and Hardware Rev (%04X, %02X)",
+ msp432_bank->device_id, msp432_bank->hardware_rev);
+ break;
+ }
+
+ buf_size -= printed;
+
+ if (0 > buf_size)
+ return ERROR_BUF_TOO_SMALL;
+
+ return ERROR_OK;
+}
+
+static void msp432_flash_free_driver_priv(struct flash_bank *bank)
+{
+ /* A single private struct is shared between main and info banks */
+ /* Only free it on the call for main bank (#0) */
+ if ((0 == bank->bank_number) && (NULL != bank->driver_priv))
+ free(bank->driver_priv);
+ /* Forget about the private struct on both main and info banks */
+ bank->driver_priv = NULL;
+}
+
+static const struct command_registration msp432_exec_command_handlers[] = {
+ {
+ .name = "mass_erase",
+ .handler = msp432_mass_erase_command,
+ .mode = COMMAND_EXEC,
+ .help = "Erase entire flash memory on device.",
+ .usage = "['main' | 'all']",
+ },
+ {
+ .name = "bsl",
+ .handler = msp432_bsl_command,
+ .mode = COMMAND_EXEC,
+ .help = "Allow BSL to be erased or written by flash commands.",
+ .usage = "['unlock' | 'lock']",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration msp432_command_handlers[] = {
+ {
+ .name = "msp432",
+ .mode = COMMAND_EXEC,
+ .help = "MSP432 flash command group",
+ .usage = "",
+ .chain = msp432_exec_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver msp432_flash = {
+ .name = "msp432",
+ .commands = msp432_command_handlers,
+ .flash_bank_command = msp432_flash_bank_command,
+ .erase = msp432_erase,
+ .protect = msp432_protect,
+ .write = msp432_write,
+ .read = default_flash_read,
+ .probe = msp432_probe,
+ .auto_probe = msp432_auto_probe,
+ .erase_check = default_flash_blank_check,
+ .protect_check = msp432_protect_check,
+ .info = msp432_info,
+ .free_driver_priv = msp432_flash_free_driver_priv,
+};
diff --git a/src/flash/nor/msp432.h b/src/flash/nor/msp432.h
new file mode 100644
index 0000000..ffefa8f
--- /dev/null
+++ b/src/flash/nor/msp432.h
@@ -0,0 +1,127 @@
+/***************************************************************************
+ * Copyright (C) 2018 by Texas Instruments, Inc. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef OPENOCD_FLASH_NOR_MSP432_H
+#define OPENOCD_FLASH_NOR_MSP432_H
+
+/* MSP432 family types */
+#define MSP432_NO_FAMILY 0 /* Family type not determined yet */
+#define MSP432E4 1 /* MSP432E4 family of devices */
+#define MSP432P4 2 /* MSP432P4 family of devices */
+
+/* MSP432 device types */
+#define MSP432_NO_TYPE 0 /* Device type not determined yet */
+#define MSP432P401X_DEPR 1 /* Early MSP432P401x offerings, now deprecated */
+#define MSP432P401X 2 /* MSP432P401x device, revision C or higher */
+#define MSP432P411X 3 /* MSP432P411x device, revision A or higher */
+#define MSP432P401X_GUESS 4 /* Assuming it's an MSP432P401x device */
+#define MSP432P411X_GUESS 5 /* Assuming it's an MSP432P411x device */
+#define MSP432E401Y 6 /* MSP432E401Y device */
+#define MSP432E411Y 7 /* MSP432E401Y device */
+#define MSP432E4X_GUESS 8 /* Assuming it's an MSP432E4x device */
+
+/* MSP432P4 flash parameters */
+#define P4_FLASH_MAIN_BASE 0x00000000
+#define P4_FLASH_INFO_BASE 0x00200000
+#define P4_SECTOR_LENGTH 0x1000
+#define P4_ALGO_ENTRY_ADDR 0x01000110
+
+/* MSP432E4 flash paramters */
+#define E4_FLASH_BASE 0x00000000
+#define E4_FLASH_SIZE 0x100000
+#define E4_SECTOR_LENGTH 0x4000
+#define E4_ALGO_ENTRY_ADDR 0x20000110
+
+/* Flash helper algorithm key addresses */
+#define ALGO_BASE_ADDR 0x20000000
+#define ALGO_BUFFER1_ADDR 0x20002000
+#define ALGO_BUFFER2_ADDR 0x20003000
+#define ALGO_PARAMS_BASE_ADDR 0x20000150
+#define ALGO_FLASH_COMMAND_ADDR 0x20000150
+#define ALGO_RETURN_CODE_ADDR 0x20000154
+#define ALGO_FLASH_DEST_ADDR 0x2000015c
+#define ALGO_FLASH_LENGTH_ADDR 0x20000160
+#define ALGO_BUFFER1_STATUS_ADDR 0x20000164
+#define ALGO_BUFFER2_STATUS_ADDR 0x20000168
+#define ALGO_ERASE_PARAM_ADDR 0x2000016c
+#define ALGO_UNLOCK_BSL_ADDR 0x20000170
+#define ALGO_STACK_POINTER_ADDR 0x20002000
+
+/* Flash helper algorithm key sizes */
+#define ALGO_BUFFER_SIZE 0x1000
+#define ALGO_WORKING_SIZE (ALGO_BUFFER2_ADDR + 0x1000 - ALGO_BASE_ADDR)
+
+/* Flash helper algorithm flash commands */
+#define FLASH_NO_COMMAND 0
+#define FLASH_MASS_ERASE 1
+#define FLASH_SECTOR_ERASE 2
+#define FLASH_PROGRAM 4
+#define FLASH_INIT 8
+#define FLASH_EXIT 16
+#define FLASH_CONTINUOUS 32
+
+/* Flash helper algorithm return codes */
+#define FLASH_BUSY 0x00000001
+#define FLASH_SUCCESS 0x00000ACE
+#define FLASH_ERROR 0x0000DEAD
+#define FLASH_TIMEOUT_ERROR 0xDEAD0000
+#define FLASH_VERIFY_ERROR 0xDEADDEAD
+#define FLASH_WRONG_COMMAND 0x00000BAD
+#define FLASH_POWER_ERROR 0x00DEAD00
+
+/* Flash helper algorithm buffer status values */
+#define BUFFER_INACTIVE 0x00
+#define BUFFER_ACTIVE 0x01
+#define BUFFER_DATA_READY 0x10
+
+/* Flash helper algorithm erase parameters */
+#define FLASH_ERASE_MAIN 0x01
+#define FLASH_ERASE_INFO 0x02
+
+/* Flash helper algorithm lock/unlock BSL options */
+#define FLASH_LOCK_BSL 0x00
+#define FLASH_UNLOCK_BSL 0x0b
+
+/* Flash helper algorithm parameter block struct */
+struct msp432_algo_params {
+ uint8_t flash_command[4];
+ uint8_t return_code[4];
+ uint8_t _reserved0[4];
+ uint8_t address[4];
+ uint8_t length[4];
+ uint8_t buffer1_status[4];
+ uint8_t buffer2_status[4];
+ uint8_t erase_param[4];
+ uint8_t unlock_bsl[4];
+};
+
+/* Flash helper algorithm for MSP432P401x targets */
+const uint8_t msp432p401x_algo[] = {
+#include "../../../contrib/loaders/flash/msp432/msp432p401x_algo.inc"
+};
+
+/* Flash helper algorithm for MSP432P411x targets */
+const uint8_t msp432p411x_algo[] = {
+#include "../../../contrib/loaders/flash/msp432/msp432p411x_algo.inc"
+};
+
+/* Flash helper algorithm for MSP432E4x targets */
+const uint8_t msp432e4x_algo[] = {
+#include "../../../contrib/loaders/flash/msp432/msp432e4x_algo.inc"
+};
+
+#endif /* OPENOCD_FLASH_NOR_MSP432_H */
diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c
index 31dd5aa..16459c7 100644
--- a/src/flash/nor/nrf5.c
+++ b/src/flash/nor/nrf5.c
@@ -108,6 +108,7 @@ enum nrf5_nvmc_config_bits {
struct nrf5_info {
uint32_t code_page_size;
+ uint32_t refcount;
struct {
bool probed;
@@ -204,6 +205,7 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = {
/* nRF52832 Devices */
NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512),
+ NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512),
};
static int nrf5_bank_is_probed(struct flash_bank *bank)
@@ -531,7 +533,6 @@ static int nrf5_probe(struct flash_bank *bank)
bank->sectors[0].size = bank->size;
bank->sectors[0].offset = 0;
- /* mark as unknown */
bank->sectors[0].is_erased = 0;
bank->sectors[0].is_protected = 0;
@@ -553,17 +554,6 @@ static int nrf5_auto_probe(struct flash_bank *bank)
return nrf5_probe(bank);
}
-static struct flash_sector *nrf5_find_sector_by_address(struct flash_bank *bank, uint32_t address)
-{
- struct nrf5_info *chip = bank->driver_priv;
-
- for (int i = 0; i < bank->num_sectors; i++)
- if (bank->sectors[i].offset <= address &&
- address < (bank->sectors[i].offset + chip->code_page_size))
- return &bank->sectors[i];
- return NULL;
-}
-
static int nrf5_erase_all(struct nrf5_info *chip)
{
LOG_DEBUG("Erasing all non-volatile memory");
@@ -615,9 +605,6 @@ static int nrf5_erase_page(struct flash_bank *bank,
sector->offset);
}
- if (res == ERROR_OK)
- sector->is_erased = 1;
-
return res;
}
@@ -743,48 +730,22 @@ static int nrf5_write_pages(struct flash_bank *bank, uint32_t start, uint32_t en
{
int res = ERROR_FAIL;
struct nrf5_info *chip = bank->driver_priv;
- struct flash_sector *sector;
- uint32_t offset;
assert(start % chip->code_page_size == 0);
assert(end % chip->code_page_size == 0);
- /* Erase all sectors */
- for (offset = start; offset < end; offset += chip->code_page_size) {
- sector = nrf5_find_sector_by_address(bank, offset);
- if (!sector) {
- LOG_ERROR("Invalid sector @ 0x%08"PRIx32, offset);
- return ERROR_FLASH_SECTOR_INVALID;
- }
-
- if (sector->is_protected) {
- LOG_ERROR("Can't erase protected sector @ 0x%08"PRIx32, offset);
- goto error;
- }
-
- if (sector->is_erased != 1) { /* 1 = erased, 0= not erased, -1 = unknown */
- res = nrf5_erase_page(bank, chip, sector);
- if (res != ERROR_OK) {
- LOG_ERROR("Failed to erase sector @ 0x%08"PRIx32, sector->offset);
- goto error;
- }
- }
- sector->is_erased = 0;
- }
-
res = nrf5_nvmc_write_enable(chip);
if (res != ERROR_OK)
goto error;
res = nrf5_ll_flash_write(chip, start, buffer, (end - start));
if (res != ERROR_OK)
- goto set_read_only;
+ goto error;
return nrf5_nvmc_read_only(chip);
-set_read_only:
- nrf5_nvmc_read_only(chip);
error:
+ nrf5_nvmc_read_only(chip);
LOG_ERROR("Failed to write to nrf5 flash");
return res;
}
@@ -876,11 +837,9 @@ static int nrf5_uicr_flash_write(struct flash_bank *bank,
if (res != ERROR_OK)
return res;
- if (sector->is_erased != 1) {
- res = nrf5_erase_page(bank, chip, sector);
- if (res != ERROR_OK)
- return res;
- }
+ res = nrf5_erase_page(bank, chip, sector);
+ if (res != ERROR_OK)
+ return res;
res = nrf5_nvmc_write_enable(chip);
if (res != ERROR_OK)
@@ -911,6 +870,18 @@ static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer,
return chip->bank[bank->bank_number].write(bank, chip, buffer, offset, count);
}
+static void nrf5_free_driver_priv(struct flash_bank *bank)
+{
+ struct nrf5_info *chip = bank->driver_priv;
+ if (chip == NULL)
+ return;
+
+ chip->refcount--;
+ if (chip->refcount == 0) {
+ free(chip);
+ bank->driver_priv = NULL;
+ }
+}
FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
{
@@ -946,6 +917,7 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
break;
}
+ chip->refcount++;
chip->bank[bank->bank_number].probed = false;
bank->driver_priv = chip;
@@ -992,9 +964,6 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command)
return res;
}
- for (int i = 0; i < bank->num_sectors; i++)
- bank->sectors[i].is_erased = 1;
-
res = nrf5_protect_check(bank);
if (res != ERROR_OK) {
LOG_ERROR("Failed to check chip's write protection");
@@ -1005,8 +974,6 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command)
if (res != ERROR_OK)
return res;
- bank->sectors[0].is_erased = 1;
-
return ERROR_OK;
}
@@ -1175,6 +1142,7 @@ struct flash_driver nrf5_flash = {
.auto_probe = nrf5_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = nrf5_protect_check,
+ .free_driver_priv = nrf5_free_driver_priv,
};
/* We need to retain the flash-driver name as well as the commands
@@ -1192,4 +1160,5 @@ struct flash_driver nrf51_flash = {
.auto_probe = nrf5_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = nrf5_protect_check,
+ .free_driver_priv = nrf5_free_driver_priv,
};
diff --git a/src/flash/nor/psoc5lp.c b/src/flash/nor/psoc5lp.c
index ae8e3d3..b88abbb 100644
--- a/src/flash/nor/psoc5lp.c
+++ b/src/flash/nor/psoc5lp.c
@@ -234,7 +234,8 @@ static void psoc5lp_get_part_number(const struct psoc5lp_device *dev, char *str)
}
/* Package does not matter. */
- strncpy(str + 8, "xx", 2);
+ str[8] = 'x';
+ str[9] = 'x';
/* Temperate range cannot uniquely be identified. */
str[10] = 'x';
@@ -859,6 +860,7 @@ struct flash_driver psoc5lp_nvl_flash = {
.erase = psoc5lp_nvl_erase,
.erase_check = psoc5lp_nvl_erase_check,
.write = psoc5lp_nvl_write,
+ .free_driver_priv = default_flash_free_driver_priv,
};
/*
@@ -1067,6 +1069,7 @@ struct flash_driver psoc5lp_eeprom_flash = {
.erase = psoc5lp_eeprom_erase,
.erase_check = default_flash_blank_check,
.write = psoc5lp_eeprom_write,
+ .free_driver_priv = default_flash_free_driver_priv,
};
/*
@@ -1077,6 +1080,10 @@ struct psoc5lp_flash_bank {
bool probed;
const struct psoc5lp_device *device;
bool ecc_enabled;
+ /* If ecc is disabled, num_sectors counts both std and ecc sectors.
+ * If ecc is enabled, num_sectors indicates just the number of std sectors.
+ * However ecc sector descriptors bank->sector[num_sectors..2*num_sectors-1]
+ * are used for driver private flash operations */
};
static int psoc5lp_erase(struct flash_bank *bank, int first, int last)
@@ -1121,21 +1128,25 @@ static int psoc5lp_erase_check(struct flash_bank *bank)
return ERROR_TARGET_NOT_HALTED;
}
+ int num_sectors = bank->num_sectors;
+ if (psoc_bank->ecc_enabled)
+ num_sectors *= 2; /* count both std and ecc sector always */
+
struct target_memory_check_block *block_array;
- block_array = malloc(bank->num_sectors * sizeof(struct target_memory_check_block));
+ block_array = malloc(num_sectors * sizeof(struct target_memory_check_block));
if (block_array == NULL)
return ERROR_FAIL;
- for (i = 0; i < bank->num_sectors; i++) {
+ for (i = 0; i < num_sectors; i++) {
block_array[i].address = bank->base + bank->sectors[i].offset;
block_array[i].size = bank->sectors[i].size;
block_array[i].result = UINT32_MAX; /* erase state unknown */
}
bool fast_check = true;
- for (i = 0; i < bank->num_sectors; ) {
+ for (i = 0; i < num_sectors; ) {
retval = armv7m_blank_check_memory(target,
- block_array + i, bank->num_sectors - i,
+ block_array + i, num_sectors - i,
bank->erased_value);
if (retval < 1) {
/* Run slow fallback if the first run gives no result
@@ -1148,15 +1159,15 @@ static int psoc5lp_erase_check(struct flash_bank *bank)
}
if (fast_check) {
- if (!psoc_bank->ecc_enabled) {
- int half_sectors = bank->num_sectors / 2;
- for (i = 0; i < half_sectors / 2; i++)
+ if (psoc_bank->ecc_enabled) {
+ for (i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased =
(block_array[i].result != 1)
- ? block_array[i + half_sectors].result
- : block_array[i].result;
+ ? block_array[i].result
+ : block_array[i + bank->num_sectors].result;
+ /* if std sector is erased, use status of ecc sector */
} else {
- for (i = 0; i < bank->num_sectors; i++)
+ for (i = 0; i < num_sectors; i++)
bank->sectors[i].is_erased = block_array[i].result;
}
retval = ERROR_OK;
@@ -1571,4 +1582,5 @@ struct flash_driver psoc5lp_flash = {
.erase = psoc5lp_erase,
.erase_check = psoc5lp_erase_check,
.write = psoc5lp_write,
+ .free_driver_priv = default_flash_free_driver_priv,
};
diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c
index 015988a..faada9a 100644
--- a/src/flash/nor/stm32f1x.c
+++ b/src/flash/nor/stm32f1x.c
@@ -585,8 +585,10 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
retval = target_write_buffer(target, write_algorithm->address,
sizeof(stm32x_flash_write_code), stm32x_flash_write_code);
- if (retval != ERROR_OK)
+ if (retval != ERROR_OK) {
+ target_free_working_area(target, write_algorithm);
return retval;
+ }
/* memory buffer */
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c
index 8013e58..413d04d 100644
--- a/src/flash/nor/stm32f2x.c
+++ b/src/flash/nor/stm32f2x.c
@@ -252,6 +252,8 @@ static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout)
/* Clear but report errors */
if (status & FLASH_ERROR) {
+ if (retval == ERROR_OK)
+ retval = ERROR_FAIL;
/* If this operation fails, we ignore it and report the original
* retval
*/
@@ -597,8 +599,10 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
retval = target_write_buffer(target, write_algorithm->address,
sizeof(stm32x_flash_write_code),
stm32x_flash_write_code);
- if (retval != ERROR_OK)
+ if (retval != ERROR_OK) {
+ target_free_working_area(target, write_algorithm);
return retval;
+ }
/* memory buffer */
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c
index 009eb9b..fcfcf91 100644
--- a/src/flash/nor/stm32h7x.c
+++ b/src/flash/nor/stm32h7x.c
@@ -64,7 +64,7 @@
#define FLASH_WRPERR (1 << 17) /* Write protection error */
#define FLASH_PGSERR (1 << 18) /* Programming sequence error */
#define FLASH_STRBERR (1 << 19) /* Strobe error */
-#define FLASH_INCERR (1 << 21) /* Increment error */
+#define FLASH_INCERR (1 << 21) /* Inconsistency error */
#define FLASH_OPERR (1 << 22) /* Operation error */
#define FLASH_RDPERR (1 << 23) /* Read Protection error */
#define FLASH_RDSERR (1 << 24) /* Secure Protection error */
@@ -220,6 +220,8 @@ static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout)
/* Clear error + EOP flags but report errors */
if (status & FLASH_ERROR) {
+ if (retval == ERROR_OK)
+ retval = ERROR_FAIL;
/* If this operation fails, we ignore it and report the original retval */
target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CCR), status);
}
@@ -495,7 +497,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last)
retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
if (retval != ERROR_OK) {
- LOG_ERROR("erase time-out error sector %d", i);
+ LOG_ERROR("erase time-out or operation error sector %d", i);
return retval;
}
bank->sectors[i].is_erased = 1;
@@ -581,8 +583,10 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
retval = target_write_buffer(target, write_algorithm->address,
sizeof(stm32x_flash_write_code),
stm32x_flash_write_code);
- if (retval != ERROR_OK)
+ if (retval != ERROR_OK) {
+ target_free_working_area(target, write_algorithm);
return retval;
+ }
/* memory buffer */
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c
index e47313c..4fb7e03 100644
--- a/src/flash/nor/stm32l4x.c
+++ b/src/flash/nor/stm32l4x.c
@@ -187,6 +187,8 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout)
/* Clear but report errors */
if (status & FLASH_ERROR) {
+ if (retval == ERROR_OK)
+ retval = ERROR_FAIL;
/* If this operation fails, we ignore it and report the original
* retval
*/
@@ -474,8 +476,10 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
retval = target_write_buffer(target, write_algorithm->address,
sizeof(stm32l4_flash_write_code),
stm32l4_flash_write_code);
- if (retval != ERROR_OK)
+ if (retval != ERROR_OK) {
+ target_free_working_area(target, write_algorithm);
return retval;
+ }
/* memory buffer */
while (target_alloc_working_area_try(target, buffer_size, &source) !=
diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c
index c68d7c2..3251df3 100644
--- a/src/flash/nor/stm32lx.c
+++ b/src/flash/nor/stm32lx.c
@@ -146,7 +146,7 @@ static const struct stm32lx_rev stm32_425_revs[] = {
{ 0x1000, "A" }, { 0x2000, "B" }, { 0x2008, "Y" },
};
static const struct stm32lx_rev stm32_427_revs[] = {
- { 0x1000, "A" }, { 0x1018, "Y" }, { 0x1038, "X" },
+ { 0x1000, "A" }, { 0x1018, "Y" }, { 0x1038, "X" }, { 0x10f8, "V" },
};
static const struct stm32lx_rev stm32_429_revs[] = {
{ 0x1000, "A" }, { 0x1018, "Z" },
diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c
index 34681db..95ca819 100644
--- a/src/flash/nor/tcl.c
+++ b/src/flash/nor/tcl.c
@@ -288,24 +288,6 @@ COMMAND_HANDLER(handle_flash_erase_address_command)
return retval;
}
-static int flash_check_sector_parameters(struct command_context *cmd_ctx,
- uint32_t first, uint32_t last, uint32_t num_sectors)
-{
- if (!(first <= last)) {
- command_print(cmd_ctx, "ERROR: "
- "first sector must be <= last sector");
- return ERROR_FAIL;
- }
-
- if (!(last <= (num_sectors - 1))) {
- command_print(cmd_ctx, "ERROR: last sector must be <= %" PRIu32,
- num_sectors - 1);
- return ERROR_FAIL;
- }
-
- return ERROR_OK;
-}
-
COMMAND_HANDLER(handle_flash_erase_command)
{
if (CMD_ARGC != 3)
@@ -327,9 +309,18 @@ COMMAND_HANDLER(handle_flash_erase_command)
else
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last);
- retval = flash_check_sector_parameters(CMD_CTX, first, last, p->num_sectors);
- if (retval != ERROR_OK)
- return retval;
+ if (!(first <= last)) {
+ command_print(CMD_CTX, "ERROR: "
+ "first sector must be <= last");
+ return ERROR_FAIL;
+ }
+
+ if (!(last <= (uint32_t)(p->num_sectors - 1))) {
+ command_print(CMD_CTX, "ERROR: "
+ "last sector must be <= %" PRIu32,
+ p->num_sectors - 1);
+ return ERROR_FAIL;
+ }
struct duration bench;
duration_start(&bench);
@@ -375,15 +366,28 @@ COMMAND_HANDLER(handle_flash_protect_command)
bool set;
COMMAND_PARSE_ON_OFF(CMD_ARGV[3], set);
- retval = flash_check_sector_parameters(CMD_CTX, first, last, num_blocks);
- if (retval != ERROR_OK)
- return retval;
+ if (!(first <= last)) {
+ command_print(CMD_CTX, "ERROR: "
+ "first %s must be <= last",
+ (p->num_prot_blocks) ? "block" : "sector");
+ return ERROR_FAIL;
+ }
+
+ if (!(last <= (uint32_t)(num_blocks - 1))) {
+ command_print(CMD_CTX, "ERROR: "
+ "last %s must be <= %" PRIu32,
+ (p->num_prot_blocks) ? "block" : "sector",
+ num_blocks - 1);
+ return ERROR_FAIL;
+ }
retval = flash_driver_protect(p, set, first, last);
if (retval == ERROR_OK) {
- command_print(CMD_CTX, "%s protection for sectors %" PRIu32
+ command_print(CMD_CTX, "%s protection for %s %" PRIu32
" through %" PRIu32 " on flash bank %d",
- (set) ? "set" : "cleared", first, last, p->bank_number);
+ (set) ? "set" : "cleared",
+ (p->num_prot_blocks) ? "blocks" : "sectors",
+ first, last, p->bank_number);
}
return retval;
@@ -502,7 +506,7 @@ COMMAND_HANDLER(handle_flash_fill_command)
if (count == 0)
return ERROR_OK;
- if (address + count >= bank->base + bank->size) {
+ if (address + count * wordsize > bank->base + bank->size) {
LOG_ERROR("Cannot cross flash bank borders");
return ERROR_FAIL;
}
diff --git a/src/flash/nor/tms470.c b/src/flash/nor/tms470.c
index 102bf1b..2435e79 100644
--- a/src/flash/nor/tms470.c
+++ b/src/flash/nor/tms470.c
@@ -151,6 +151,7 @@ static int tms470_read_part_info(struct flash_bank *bank)
if (bank->sectors) {
free(bank->sectors);
bank->sectors = NULL;
+ bank->num_sectors = 0;
}
/*
@@ -754,9 +755,6 @@ static int tms470_erase_sector(struct flash_bank *bank, int sector)
target_write_u32(target, 0xFFFFFFDC, glbctrl);
LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl);
- if (result == ERROR_OK)
- bank->sectors[sector].is_erased = 1;
-
return result;
}
@@ -1044,27 +1042,17 @@ static int tms470_erase_check(struct flash_bank *bank)
* an attempt to reduce the JTAG overhead.
*/
for (sector = 0; sector < bank->num_sectors; sector++) {
- if (bank->sectors[sector].is_erased != 1) {
- uint32_t i, addr = bank->base + bank->sectors[sector].offset;
-
- LOG_INFO("checking flash bank %d sector %d", tms470_info->ordinal, sector);
-
- target_read_buffer(target, addr, bank->sectors[sector].size, buffer);
-
- bank->sectors[sector].is_erased = 1;
- for (i = 0; i < bank->sectors[sector].size; i++) {
- if (buffer[i] != 0xff) {
- LOG_WARNING("tms470 bank %d, sector %d, not erased.",
- tms470_info->ordinal,
- sector);
- LOG_WARNING(
- "at location 0x%08" PRIx32 ": flash data is 0x%02x.",
- addr + i,
- buffer[i]);
-
- bank->sectors[sector].is_erased = 0;
- break;
- }
+ uint32_t i, addr = bank->base + bank->sectors[sector].offset;
+
+ LOG_INFO("checking flash bank %d sector %d", tms470_info->ordinal, sector);
+
+ target_read_buffer(target, addr, bank->sectors[sector].size, buffer);
+
+ bank->sectors[sector].is_erased = 1;
+ for (i = 0; i < bank->sectors[sector].size; i++) {
+ if (buffer[i] != 0xff) {
+ bank->sectors[sector].is_erased = 0;
+ break;
}
}
if (bank->sectors[sector].is_erased != 1) {
diff --git a/src/jtag/aice/aice_usb.c b/src/jtag/aice/aice_usb.c
index 50468f3..d77b26b 100644
--- a/src/jtag/aice/aice_usb.c
+++ b/src/jtag/aice/aice_usb.c
@@ -2289,37 +2289,39 @@ get_delay:
static int aice_usb_set_clock(int set_clock)
{
- if (aice_write_ctrl(AICE_WRITE_CTRL_TCK_CONTROL,
- AICE_TCK_CONTROL_TCK_SCAN) != ERROR_OK)
- return ERROR_FAIL;
+ if (set_clock & AICE_TCK_CONTROL_TCK_SCAN) {
+ if (aice_write_ctrl(AICE_WRITE_CTRL_TCK_CONTROL,
+ AICE_TCK_CONTROL_TCK_SCAN) != ERROR_OK)
+ return ERROR_FAIL;
- /* Read out TCK_SCAN clock value */
- uint32_t scan_clock;
- if (aice_read_ctrl(AICE_READ_CTRL_GET_ICE_STATE, &scan_clock) != ERROR_OK)
- return ERROR_FAIL;
+ /* Read out TCK_SCAN clock value */
+ uint32_t scan_clock;
+ if (aice_read_ctrl(AICE_READ_CTRL_GET_ICE_STATE, &scan_clock) != ERROR_OK)
+ return ERROR_FAIL;
- scan_clock &= 0x0F;
+ scan_clock &= 0x0F;
- uint32_t scan_base_freq;
- if (scan_clock & 0x8)
- scan_base_freq = 48000; /* 48 MHz */
- else
- scan_base_freq = 30000; /* 30 MHz */
+ uint32_t scan_base_freq;
+ if (scan_clock & 0x8)
+ scan_base_freq = 48000; /* 48 MHz */
+ else
+ scan_base_freq = 30000; /* 30 MHz */
- uint32_t set_base_freq;
- if (set_clock & 0x8)
- set_base_freq = 48000;
- else
- set_base_freq = 30000;
+ uint32_t set_base_freq;
+ if (set_clock & 0x8)
+ set_base_freq = 48000;
+ else
+ set_base_freq = 30000;
- uint32_t set_freq;
- uint32_t scan_freq;
- set_freq = set_base_freq >> (set_clock & 0x7);
- scan_freq = scan_base_freq >> (scan_clock & 0x7);
+ uint32_t set_freq;
+ uint32_t scan_freq;
+ set_freq = set_base_freq >> (set_clock & 0x7);
+ scan_freq = scan_base_freq >> (scan_clock & 0x7);
- if (scan_freq < set_freq) {
- LOG_ERROR("User specifies higher jtag clock than TCK_SCAN clock");
- return ERROR_FAIL;
+ if (scan_freq < set_freq) {
+ LOG_ERROR("User specifies higher jtag clock than TCK_SCAN clock");
+ return ERROR_FAIL;
+ }
}
if (aice_write_ctrl(AICE_WRITE_CTRL_TCK_CONTROL, set_clock) != ERROR_OK)
diff --git a/src/jtag/aice/aice_usb.h b/src/jtag/aice/aice_usb.h
index 2911ae5..15cc1f6 100644
--- a/src/jtag/aice/aice_usb.h
+++ b/src/jtag/aice/aice_usb.h
@@ -71,6 +71,7 @@
/* Constants for AICE command WRITE_CTRL:TCK_CONTROL */
#define AICE_TCK_CONTROL_TCK3048 0x08
+#define AICE_TCK_CONTROL_TCK_SCAN 0x10
/* Constants for AICE command WRITE_CTRL:JTAG_PIN_CONTROL */
#define AICE_JTAG_PIN_CONTROL_SRST 0x01
diff --git a/src/jtag/core.c b/src/jtag/core.c
index 5d9b810..f90ae99 100644
--- a/src/jtag/core.c
+++ b/src/jtag/core.c
@@ -1843,7 +1843,7 @@ void adapter_deassert_reset(void)
LOG_ERROR("transport is not selected");
}
-int adapter_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
+int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq)
{
if (jtag->config_trace)
diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c
index b8181d6..4ee4836 100644
--- a/src/jtag/drivers/cmsis_dap_usb.c
+++ b/src/jtag/drivers/cmsis_dap_usb.c
@@ -729,6 +729,20 @@ static void cmsis_dap_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_del
cmsis_dap_swd_queue_cmd(cmd, value, 0);
}
+static int cmsis_dap_get_serial_info(void)
+{
+ uint8_t *data;
+
+ int retval = cmsis_dap_cmd_DAP_Info(INFO_ID_SERNUM, &data);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (data[0]) /* strlen */
+ LOG_INFO("CMSIS-DAP: Serial# = %s", &data[1]);
+
+ return ERROR_OK;
+}
+
static int cmsis_dap_get_version_info(void)
{
uint8_t *data;
@@ -802,8 +816,7 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq)
/* When we are reconnecting, DAP_Connect needs to be rerun, at
* least on Keil ULINK-ME */
- retval = cmsis_dap_cmd_DAP_Connect(seq == LINE_RESET || seq == JTAG_TO_SWD ?
- CONNECT_SWD : CONNECT_JTAG);
+ retval = cmsis_dap_cmd_DAP_Connect(CONNECT_SWD);
if (retval != ERROR_OK)
return retval;
}
@@ -842,17 +855,6 @@ static int cmsis_dap_swd_open(void)
{
int retval;
- if (cmsis_dap_handle == NULL) {
- /* SWD init */
- retval = cmsis_dap_usb_open();
- if (retval != ERROR_OK)
- return retval;
-
- retval = cmsis_dap_get_caps_info();
- if (retval != ERROR_OK)
- return retval;
- }
-
if (!(cmsis_dap_handle->caps & INFO_CAPS_SWD)) {
LOG_ERROR("CMSIS-DAP: SWD not supported");
return ERROR_JTAG_DEVICE_ERROR;
@@ -873,6 +875,22 @@ static int cmsis_dap_init(void)
int retval;
uint8_t *data;
+ retval = cmsis_dap_usb_open();
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = cmsis_dap_get_caps_info();
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = cmsis_dap_get_version_info();
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = cmsis_dap_get_serial_info();
+ if (retval != ERROR_OK)
+ return retval;
+
if (swd_mode) {
retval = cmsis_dap_swd_open();
if (retval != ERROR_OK)
@@ -880,16 +898,6 @@ static int cmsis_dap_init(void)
}
if (cmsis_dap_handle == NULL) {
-
- /* JTAG init */
- retval = cmsis_dap_usb_open();
- if (retval != ERROR_OK)
- return retval;
-
- retval = cmsis_dap_get_caps_info();
- if (retval != ERROR_OK)
- return retval;
-
/* Connect in JTAG mode */
if (!(cmsis_dap_handle->caps & INFO_CAPS_JTAG)) {
LOG_ERROR("CMSIS-DAP: JTAG not supported");
@@ -903,10 +911,6 @@ static int cmsis_dap_init(void)
LOG_INFO("CMSIS-DAP: Interface Initialised (JTAG)");
}
- retval = cmsis_dap_get_version_info();
- if (retval != ERROR_OK)
- return retval;
-
/* INFO_ID_PKT_SZ - short */
retval = cmsis_dap_cmd_DAP_Info(INFO_ID_PKT_SZ, &data);
if (retval != ERROR_OK)
@@ -1458,6 +1462,12 @@ static void cmsis_dap_execute_stableclocks(struct jtag_command *cmd)
cmsis_dap_stableclocks(cmd->cmd.runtest->num_cycles);
}
+static void cmsis_dap_execute_tms(struct jtag_command *cmd)
+{
+ DEBUG_JTAG_IO("TMS: %d bits", cmd->cmd.tms->num_bits);
+ cmsis_dap_cmd_DAP_SWJ_Sequence(cmd->cmd.tms->num_bits, cmd->cmd.tms->bits);
+}
+
/* TODO: Is there need to call cmsis_dap_flush() for the JTAG_PATHMOVE,
* JTAG_RUNTEST, JTAG_STABLECLOCKS? */
static void cmsis_dap_execute_command(struct jtag_command *cmd)
@@ -1488,6 +1498,8 @@ static void cmsis_dap_execute_command(struct jtag_command *cmd)
cmsis_dap_execute_stableclocks(cmd);
break;
case JTAG_TMS:
+ cmsis_dap_execute_tms(cmd);
+ break;
default:
LOG_ERROR("BUG: unknown JTAG command type 0x%X encountered", cmd->type);
exit(-1);
@@ -1650,6 +1662,7 @@ static const char * const cmsis_dap_transport[] = { "swd", "jtag", NULL };
struct jtag_interface cmsis_dap_interface = {
.name = "cmsis-dap",
+ .supported = DEBUG_CAP_TMS_SEQ,
.commands = cmsis_dap_command_handlers,
.swd = &cmsis_dap_swd_driver,
.transports = cmsis_dap_transport,
diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c
index 132ef06..e74965e 100644
--- a/src/jtag/drivers/jlink.c
+++ b/src/jtag/drivers/jlink.c
@@ -1263,7 +1263,7 @@ static bool check_trace_freq(struct jaylink_swo_speed speed,
return false;
}
-static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
+static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq)
{
int ret;
@@ -1275,7 +1275,7 @@ static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
return ERROR_FAIL;
}
- if (pin_protocol != ASYNC_UART) {
+ if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) {
LOG_ERROR("Selected pin protocol is not supported.");
return ERROR_FAIL;
}
diff --git a/src/jtag/drivers/jtag_vpi.c b/src/jtag/drivers/jtag_vpi.c
index a1787d4..1a42b3a 100644
--- a/src/jtag/drivers/jtag_vpi.c
+++ b/src/jtag/drivers/jtag_vpi.c
@@ -204,23 +204,20 @@ static int jtag_vpi_queue_tdi_xfer(uint8_t *bits, int nb_bits, int tap_shift)
static int jtag_vpi_queue_tdi(uint8_t *bits, int nb_bits, int tap_shift)
{
int nb_xfer = DIV_ROUND_UP(nb_bits, XFERT_MAX_SIZE * 8);
- uint8_t *xmit_buffer = bits;
- int xmit_nb_bits = nb_bits;
- int i = 0;
int retval;
while (nb_xfer) {
-
if (nb_xfer == 1) {
- retval = jtag_vpi_queue_tdi_xfer(&xmit_buffer[i], xmit_nb_bits, tap_shift);
+ retval = jtag_vpi_queue_tdi_xfer(bits, nb_bits, tap_shift);
if (retval != ERROR_OK)
return retval;
} else {
- retval = jtag_vpi_queue_tdi_xfer(&xmit_buffer[i], XFERT_MAX_SIZE * 8, NO_TAP_SHIFT);
+ retval = jtag_vpi_queue_tdi_xfer(bits, XFERT_MAX_SIZE * 8, NO_TAP_SHIFT);
if (retval != ERROR_OK)
return retval;
- xmit_nb_bits -= XFERT_MAX_SIZE * 8;
- i += XFERT_MAX_SIZE;
+ nb_bits -= XFERT_MAX_SIZE * 8;
+ if (bits)
+ bits += XFERT_MAX_SIZE;
}
nb_xfer--;
diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c
index 99f96b9..d9ca53e 100644
--- a/src/jtag/drivers/stlink_usb.c
+++ b/src/jtag/drivers/stlink_usb.c
@@ -2194,12 +2194,13 @@ error_open:
return ERROR_FAIL;
}
-int stlink_config_trace(void *handle, bool enabled, enum tpio_pin_protocol pin_protocol,
+int stlink_config_trace(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq)
{
struct stlink_usb_handle_s *h = handle;
- if (enabled && (h->jtag_api < 2 || pin_protocol != ASYNC_UART)) {
+ if (enabled && (h->jtag_api < 2 ||
+ pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART)) {
LOG_ERROR("The attached ST-LINK version doesn't support this trace mode");
return ERROR_FAIL;
}
diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c b/src/jtag/drivers/usb_blaster/usb_blaster.c
index df9f2a1..8ccf871 100644
--- a/src/jtag/drivers/usb_blaster/usb_blaster.c
+++ b/src/jtag/drivers/usb_blaster/usb_blaster.c
@@ -445,6 +445,7 @@ static void ublast_queue_bytes(uint8_t *bytes, int nb_bytes)
* ublast_tms_seq - write a TMS sequence transition to JTAG
* @bits: TMS bits to be written (bit0, bit1 .. bitN)
* @nb_bits: number of TMS bits (between 1 and 8)
+ * @skip: number of TMS bits to skip at the beginning of the series
*
* Write a serie of TMS transitions, where each transition consists in :
* - writing out TCK=0, TMS=<new_state>, TDI=<???>
@@ -452,12 +453,12 @@ static void ublast_queue_bytes(uint8_t *bytes, int nb_bytes)
* The function ensures that at the end of the sequence, the clock (TCK) is put
* low.
*/
-static void ublast_tms_seq(const uint8_t *bits, int nb_bits)
+static void ublast_tms_seq(const uint8_t *bits, int nb_bits, int skip)
{
int i;
DEBUG_JTAG_IO("(bits=%02x..., nb_bits=%d)", bits[0], nb_bits);
- for (i = 0; i < nb_bits; i++)
+ for (i = skip; i < nb_bits; i++)
ublast_clock_tms((bits[i / 8] >> (i % 8)) & 0x01);
ublast_idle_clock();
}
@@ -469,7 +470,7 @@ static void ublast_tms_seq(const uint8_t *bits, int nb_bits)
static void ublast_tms(struct tms_command *cmd)
{
DEBUG_JTAG_IO("(num_bits=%d)", cmd->num_bits);
- ublast_tms_seq(cmd->bits, cmd->num_bits);
+ ublast_tms_seq(cmd->bits, cmd->num_bits, 0);
}
/**
@@ -501,11 +502,12 @@ static void ublast_path_move(struct pathmove_command *cmd)
/**
* ublast_state_move - move JTAG state to the target state
* @state: the target state
+ * @skip: number of bits to skip at the beginning of the path
*
* Input the correct TMS sequence to the JTAG TAP so that we end up in the
* target state. This assumes the current state (tap_get_state()) is correct.
*/
-static void ublast_state_move(tap_state_t state)
+static void ublast_state_move(tap_state_t state, int skip)
{
uint8_t tms_scan;
int tms_len;
@@ -516,7 +518,7 @@ static void ublast_state_move(tap_state_t state)
return;
tms_scan = tap_get_tms_path(tap_get_state(), state);
tms_len = tap_get_tms_path_len(tap_get_state(), state);
- ublast_tms_seq(&tms_scan, tms_len);
+ ublast_tms_seq(&tms_scan, tms_len, skip);
tap_set_state(state);
}
@@ -688,9 +690,9 @@ static void ublast_runtest(int cycles, tap_state_t state)
{
DEBUG_JTAG_IO("%s(cycles=%i, end_state=%d)", __func__, cycles, state);
- ublast_state_move(TAP_IDLE);
+ ublast_state_move(TAP_IDLE, 0);
ublast_queue_tdi(NULL, cycles, SCAN_OUT);
- ublast_state_move(state);
+ ublast_state_move(state, 0);
}
static void ublast_stableclocks(int cycles)
@@ -720,9 +722,9 @@ static int ublast_scan(struct scan_command *cmd)
scan_bits = jtag_build_buffer(cmd, &buf);
if (cmd->ir_scan)
- ublast_state_move(TAP_IRSHIFT);
+ ublast_state_move(TAP_IRSHIFT, 0);
else
- ublast_state_move(TAP_DRSHIFT);
+ ublast_state_move(TAP_DRSHIFT, 0);
log_buf = hexdump(buf, DIV_ROUND_UP(scan_bits, 8));
DEBUG_JTAG_IO("%s(scan=%s, type=%s, bits=%d, buf=[%s], end_state=%d)", __func__,
@@ -733,20 +735,15 @@ static int ublast_scan(struct scan_command *cmd)
ublast_queue_tdi(buf, scan_bits, type);
- /*
- * As our JTAG is in an unstable state (IREXIT1 or DREXIT1), move it
- * forward to a stable IRPAUSE or DRPAUSE.
- */
- ublast_clock_tms(0);
- if (cmd->ir_scan)
- tap_set_state(TAP_IRPAUSE);
- else
- tap_set_state(TAP_DRPAUSE);
-
ret = jtag_read_buffer(buf, cmd);
if (buf)
free(buf);
- ublast_state_move(cmd->end_state);
+ /*
+ * ublast_queue_tdi sends the last bit with TMS=1. We are therefore
+ * already in Exit1-DR/IR and have to skip the first step on our way
+ * to end_state.
+ */
+ ublast_state_move(cmd->end_state, 1);
return ret;
}
@@ -776,7 +773,7 @@ static void ublast_initial_wipeout(void)
/*
* Put JTAG in RESET state (five 1 on TMS)
*/
- ublast_tms_seq(&tms_reset, 5);
+ ublast_tms_seq(&tms_reset, 5, 0);
tap_set_state(TAP_RESET);
}
@@ -805,7 +802,7 @@ static int ublast_execute_queue(void)
ublast_stableclocks(cmd->cmd.stableclocks->num_cycles);
break;
case JTAG_TLR_RESET:
- ublast_state_move(cmd->cmd.statemove->end_state);
+ ublast_state_move(cmd->cmd.statemove->end_state, 0);
break;
case JTAG_PATHMOVE:
ublast_path_move(cmd->cmd.pathmove);
diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c
index cb9ef39..2abed21 100644
--- a/src/jtag/hla/hla_interface.c
+++ b/src/jtag/hla/hla_interface.c
@@ -191,7 +191,7 @@ int hl_interface_override_target(const char **targetname)
return ERROR_FAIL;
}
-int hl_interface_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
+int hl_interface_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq)
{
if (hl_if.layout->api->config_trace)
diff --git a/src/jtag/hla/hla_layout.h b/src/jtag/hla/hla_layout.h
index 40c1321..9f41b59 100644
--- a/src/jtag/hla/hla_layout.h
+++ b/src/jtag/hla/hla_layout.h
@@ -91,7 +91,7 @@ struct hl_layout_api_s {
* its maximum supported rate there
* @returns ERROR_OK on success, an error code on failure.
*/
- int (*config_trace)(void *handle, bool enabled, enum tpio_pin_protocol pin_protocol,
+ int (*config_trace)(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq);
/**
* Poll for new trace data
diff --git a/src/jtag/interface.h b/src/jtag/interface.h
index cdfc676..e6fa0ca 100644
--- a/src/jtag/interface.h
+++ b/src/jtag/interface.h
@@ -309,7 +309,7 @@ struct jtag_interface {
* its maximum supported rate there
* @returns ERROR_OK on success, an error code on failure.
*/
- int (*config_trace)(bool enabled, enum tpio_pin_protocol pin_protocol,
+ int (*config_trace)(bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq);
/**
@@ -328,7 +328,7 @@ extern const char * const jtag_only[];
void adapter_assert_reset(void);
void adapter_deassert_reset(void);
-int adapter_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
+int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq);
int adapter_poll_trace(uint8_t *buf, size_t *size);
diff --git a/src/jtag/zy1000/zy1000.c b/src/jtag/zy1000/zy1000.c
index 67d9907..4e53dd1 100644
--- a/src/jtag/zy1000/zy1000.c
+++ b/src/jtag/zy1000/zy1000.c
@@ -265,8 +265,8 @@ COMMAND_HANDLER(handle_power_command)
bool enable;
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable);
setPower(enable);
- /* fall through */
}
+ /* fall through */
case 0:
LOG_INFO("Target power %s", savePower ? "on" : "off");
break;
diff --git a/src/rtos/Makefile.am b/src/rtos/Makefile.am
index 22f7da5..6f14b42 100644
--- a/src/rtos/Makefile.am
+++ b/src/rtos/Makefile.am
@@ -16,6 +16,7 @@ noinst_LTLIBRARIES += %D%/librtos.la
%D%/mqx.c \
%D%/riscv_debug.c \
%D%/uCOS-III.c \
+ %D%/nuttx.c \
%D%/rtos.h \
%D%/rtos_standard_stackings.h \
%D%/rtos_ecos_stackings.h \
@@ -24,6 +25,7 @@ noinst_LTLIBRARIES += %D%/librtos.la
%D%/rtos_embkernel_stackings.h \
%D%/rtos_mqx_stackings.h \
%D%/rtos_ucos_iii_stackings.h \
+ %D%/nuttx_header.h \
%D%/riscv_debug.h
%C%_librtos_la_CFLAGS = $(AM_CFLAGS)
diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c
new file mode 100644
index 0000000..284b968
--- /dev/null
+++ b/src/rtos/nuttx.c
@@ -0,0 +1,405 @@
+/***************************************************************************
+ * Copyright 2016,2017 Sony Video & Sound Products Inc. *
+ * Masatoshi Tateishi - Masatoshi.Tateishi@jp.sony.com *
+ * Masayuki Ishikawa - Masayuki.Ishikawa@jp.sony.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <jtag/jtag.h>
+#include "target/target.h"
+#include "target/target_type.h"
+#include "target/armv7m.h"
+#include "target/cortex_m.h"
+#include "rtos.h"
+#include "helper/log.h"
+#include "helper/types.h"
+#include "server/gdb_server.h"
+
+#include "nuttx_header.h"
+
+
+int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
+
+#ifdef CONFIG_DISABLE_SIGNALS
+#define SIG_QUEUE_NUM 0
+#else
+#define SIG_QUEUE_NUM 1
+#endif /* CONFIG_DISABLE_SIGNALS */
+
+#ifdef CONFIG_DISABLE_MQUEUE
+#define M_QUEUE_NUM 0
+#else
+#define M_QUEUE_NUM 2
+#endif /* CONFIG_DISABLE_MQUEUE */
+
+#ifdef CONFIG_PAGING
+#define PAGING_QUEUE_NUM 1
+#else
+#define PAGING_QUEUE_NUM 0
+#endif /* CONFIG_PAGING */
+
+
+#define TASK_QUEUE_NUM (6 + SIG_QUEUE_NUM + M_QUEUE_NUM + PAGING_QUEUE_NUM)
+
+
+/* see nuttx/sched/os_start.c */
+static char *nuttx_symbol_list[] = {
+ "g_readytorun", /* 0: must be top of this array */
+ "g_tasklisttable",
+ NULL
+};
+
+/* see nuttx/include/nuttx/sched.h */
+struct tcb {
+ uint32_t flink;
+ uint32_t blink;
+ uint8_t dat[512];
+};
+
+struct {
+ uint32_t addr;
+ uint32_t prio;
+} g_tasklist[TASK_QUEUE_NUM];
+
+static char *task_state_str[] = {
+ "INVALID",
+ "PENDING",
+ "READYTORUN",
+ "RUNNING",
+ "INACTIVE",
+ "WAIT_SEM",
+#ifndef CONFIG_DISABLE_SIGNALS
+ "WAIT_SIG",
+#endif /* CONFIG_DISABLE_SIGNALS */
+#ifndef CONFIG_DISABLE_MQUEUE
+ "WAIT_MQNOTEMPTY",
+ "WAIT_MQNOTFULL",
+#endif /* CONFIG_DISABLE_MQUEUE */
+#ifdef CONFIG_PAGING
+ "WAIT_PAGEFILL",
+#endif /* CONFIG_PAGING */
+};
+
+/* see arch/arm/include/armv7-m/irq_cmnvector.h */
+static const struct stack_register_offset nuttx_stack_offsets_cortex_m[] = {
+ { 0x28, 32 }, /* r0 */
+ { 0x2c, 32 }, /* r1 */
+ { 0x30, 32 }, /* r2 */
+ { 0x34, 32 }, /* r3 */
+ { 0x08, 32 }, /* r4 */
+ { 0x0c, 32 }, /* r5 */
+ { 0x10, 32 }, /* r6 */
+ { 0x14, 32 }, /* r7 */
+ { 0x18, 32 }, /* r8 */
+ { 0x1c, 32 }, /* r9 */
+ { 0x20, 32 }, /* r10 */
+ { 0x24, 32 }, /* r11 */
+ { 0x38, 32 }, /* r12 */
+ { 0, 32 }, /* sp */
+ { 0x3c, 32 }, /* lr */
+ { 0x40, 32 }, /* pc */
+ { 0x44, 32 }, /* xPSR */
+};
+
+
+static const struct rtos_register_stacking nuttx_stacking_cortex_m = {
+ 0x48, /* stack_registers_size */
+ -1, /* stack_growth_direction */
+ 17, /* num_output_registers */
+ 0, /* stack_alignment */
+ nuttx_stack_offsets_cortex_m /* register_offsets */
+};
+
+static const struct stack_register_offset nuttx_stack_offsets_cortex_m_fpu[] = {
+ { 0x6c, 32 }, /* r0 */
+ { 0x70, 32 }, /* r1 */
+ { 0x74, 32 }, /* r2 */
+ { 0x78, 32 }, /* r3 */
+ { 0x08, 32 }, /* r4 */
+ { 0x0c, 32 }, /* r5 */
+ { 0x10, 32 }, /* r6 */
+ { 0x14, 32 }, /* r7 */
+ { 0x18, 32 }, /* r8 */
+ { 0x1c, 32 }, /* r9 */
+ { 0x20, 32 }, /* r10 */
+ { 0x24, 32 }, /* r11 */
+ { 0x7c, 32 }, /* r12 */
+ { 0, 32 }, /* sp */
+ { 0x80, 32 }, /* lr */
+ { 0x84, 32 }, /* pc */
+ { 0x88, 32 }, /* xPSR */
+};
+
+static const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu = {
+ 0x8c, /* stack_registers_size */
+ -1, /* stack_growth_direction */
+ 17, /* num_output_registers */
+ 0, /* stack_alignment */
+ nuttx_stack_offsets_cortex_m_fpu /* register_offsets */
+};
+
+static int pid_offset = PID;
+static int state_offset = STATE;
+static int name_offset = NAME;
+static int xcpreg_offset = XCPREG;
+static int name_size = NAME_SIZE;
+
+static int rcmd_offset(const char *cmd, const char *name)
+{
+ if (strncmp(cmd, name, strlen(name)))
+ return -1;
+
+ if (strlen(cmd) <= strlen(name) + 1)
+ return -1;
+
+ return atoi(cmd + strlen(name));
+}
+
+static int nuttx_thread_packet(struct connection *connection,
+ char const *packet, int packet_size)
+{
+ char cmd[GDB_BUFFER_SIZE / 2] = "";
+
+ if (!strncmp(packet, "qRcmd", 5)) {
+ size_t len = unhexify((uint8_t *)cmd, packet + 6, sizeof(cmd));
+ int offset;
+
+ if (len <= 0)
+ goto pass;
+
+ offset = rcmd_offset(cmd, "nuttx.pid_offset");
+
+ if (offset >= 0) {
+ LOG_INFO("pid_offset: %d", offset);
+ pid_offset = offset;
+ goto retok;
+ }
+
+ offset = rcmd_offset(cmd, "nuttx.state_offset");
+
+ if (offset >= 0) {
+ LOG_INFO("state_offset: %d", offset);
+ state_offset = offset;
+ goto retok;
+ }
+
+ offset = rcmd_offset(cmd, "nuttx.name_offset");
+
+ if (offset >= 0) {
+ LOG_INFO("name_offset: %d", offset);
+ name_offset = offset;
+ goto retok;
+ }
+
+ offset = rcmd_offset(cmd, "nuttx.xcpreg_offset");
+
+ if (offset >= 0) {
+ LOG_INFO("xcpreg_offset: %d", offset);
+ xcpreg_offset = offset;
+ goto retok;
+ }
+
+ offset = rcmd_offset(cmd, "nuttx.name_size");
+
+ if (offset >= 0) {
+ LOG_INFO("name_size: %d", offset);
+ name_size = offset;
+ goto retok;
+ }
+ }
+pass:
+ return rtos_thread_packet(connection, packet, packet_size);
+retok:
+ gdb_put_packet(connection, "OK", 2);
+ return ERROR_OK;
+}
+
+
+static bool nuttx_detect_rtos(struct target *target)
+{
+ if ((target->rtos->symbols != NULL) &&
+ (target->rtos->symbols[0].address != 0) &&
+ (target->rtos->symbols[1].address != 0)) {
+ return true;
+ }
+ return false;
+}
+
+static int nuttx_create(struct target *target)
+{
+
+ target->rtos->gdb_thread_packet = nuttx_thread_packet;
+ LOG_INFO("target type name = %s", target->type->name);
+ return 0;
+}
+
+static int nuttx_update_threads(struct rtos *rtos)
+{
+ uint32_t thread_count;
+ struct tcb tcb;
+ int ret;
+ uint32_t head;
+ uint32_t tcb_addr;
+ uint32_t i;
+ uint8_t state;
+
+ if (rtos->symbols == NULL) {
+ LOG_ERROR("No symbols for NuttX");
+ return -3;
+ }
+
+ /* free previous thread details */
+ rtos_free_threadlist(rtos);
+
+ ret = target_read_buffer(rtos->target, rtos->symbols[1].address,
+ sizeof(g_tasklist), (uint8_t *)&g_tasklist);
+ if (ret) {
+ LOG_ERROR("target_read_buffer : ret = %d\n", ret);
+ return ERROR_FAIL;
+ }
+
+ thread_count = 0;
+
+ for (i = 0; i < TASK_QUEUE_NUM; i++) {
+
+ if (g_tasklist[i].addr == 0)
+ continue;
+
+ ret = target_read_u32(rtos->target, g_tasklist[i].addr,
+ &head);
+
+ if (ret) {
+ LOG_ERROR("target_read_u32 : ret = %d\n", ret);
+ return ERROR_FAIL;
+ }
+
+ /* readytorun head is current thread */
+ if (g_tasklist[i].addr == rtos->symbols[0].address)
+ rtos->current_thread = head;
+
+
+ tcb_addr = head;
+ while (tcb_addr) {
+ struct thread_detail *thread;
+ ret = target_read_buffer(rtos->target, tcb_addr,
+ sizeof(tcb), (uint8_t *)&tcb);
+ if (ret) {
+ LOG_ERROR("target_read_buffer : ret = %d\n",
+ ret);
+ return ERROR_FAIL;
+ }
+ thread_count++;
+
+ rtos->thread_details = realloc(rtos->thread_details,
+ sizeof(struct thread_detail) * thread_count);
+ thread = &rtos->thread_details[thread_count - 1];
+ thread->threadid = tcb_addr;
+ thread->exists = true;
+
+ state = tcb.dat[state_offset - 8];
+ thread->extra_info_str = NULL;
+ if (state < sizeof(task_state_str)/sizeof(char *)) {
+ thread->extra_info_str = malloc(256);
+ snprintf(thread->extra_info_str, 256, "pid:%d, %s",
+ tcb.dat[pid_offset - 8] |
+ tcb.dat[pid_offset - 8 + 1] << 8,
+ task_state_str[state]);
+ }
+
+ if (name_offset) {
+ thread->thread_name_str = malloc(name_size + 1);
+ snprintf(thread->thread_name_str, name_size,
+ "%s", (char *)&tcb.dat[name_offset - 8]);
+ } else {
+ thread->thread_name_str = malloc(sizeof("None"));
+ strcpy(thread->thread_name_str, "None");
+ }
+
+ tcb_addr = tcb.flink;
+ }
+ }
+ rtos->thread_count = thread_count;
+
+ return 0;
+}
+
+
+/*
+ * thread_id = tcb address;
+ */
+static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
+ char **hex_reg_list) {
+ int retval;
+
+ *hex_reg_list = NULL;
+
+ /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4F */
+ bool cm4_fpu_enabled = false;
+ struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
+ if (is_armv7m(armv7m_target)) {
+ if (armv7m_target->fp_feature == FPv4_SP) {
+ /* Found ARM v7m target which includes a FPU */
+ uint32_t cpacr;
+
+ retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Could not read CPACR register to check FPU state");
+ return -1;
+ }
+
+ /* Check if CP10 and CP11 are set to full access. */
+ if (cpacr & 0x00F00000) {
+ /* Found target with enabled FPU */
+ cm4_fpu_enabled = 1;
+ }
+ }
+ }
+
+ const struct rtos_register_stacking *stacking;
+ if (cm4_fpu_enabled)
+ stacking = &nuttx_stacking_cortex_m_fpu;
+ else
+ stacking = &nuttx_stacking_cortex_m;
+
+ return rtos_generic_stack_read(rtos->target, stacking,
+ (uint32_t)thread_id + xcpreg_offset, hex_reg_list);
+}
+
+static int nuttx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+{
+ unsigned int i;
+
+ *symbol_list = (symbol_table_elem_t *) calloc(1,
+ sizeof(symbol_table_elem_t) * ARRAY_SIZE(nuttx_symbol_list));
+
+ for (i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++)
+ (*symbol_list)[i].symbol_name = nuttx_symbol_list[i];
+
+ return 0;
+}
+
+struct rtos_type nuttx_rtos = {
+ .name = "nuttx",
+ .detect_rtos = nuttx_detect_rtos,
+ .create = nuttx_create,
+ .update_threads = nuttx_update_threads,
+ .get_thread_reg_list = nuttx_get_thread_reg_list,
+ .get_symbol_list_to_lookup = nuttx_get_symbol_list_to_lookup,
+};
+
diff --git a/src/rtos/nuttx_header.h b/src/rtos/nuttx_header.h
new file mode 100644
index 0000000..00b0484
--- /dev/null
+++ b/src/rtos/nuttx_header.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+ * Copyright 2016,2017 Sony Video & Sound Products Inc. *
+ * Masatoshi Tateishi - Masatoshi.Tateishi@jp.sony.com *
+ * Masayuki Ishikawa - Masayuki.Ishikawa@jp.sony.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef OPENOCD_RTOS_NUTTX_HEADER_H
+#define OPENOCD_RTOS_NUTTX_HEADER_H
+
+/* gdb script to update the header file
+ according to kernel version and build option
+ before executing function awareness
+ kernel symbol must be loaded : symbol nuttx
+
+define awareness
+ set logging off
+ set logging file nuttx_header.h
+ set logging on
+
+ printf "#define PID %p\n",&((struct tcb_s *)(0))->pid
+ printf "#define XCPREG %p\n",&((struct tcb_s *)(0))->xcp.regs
+ printf "#define STATE %p\n",&((struct tcb_s *)(0))->task_state
+ printf "#define NAME %p\n",&((struct tcb_s *)(0))->name
+ printf "#define NAME_SIZE %d\n",sizeof(((struct tcb_s *)(0))->name)
+ end
+
+
+ OR ~/.gdbinit
+
+
+define hookpost-file
+
+ if &g_readytorun != 0
+ eval "monitor nuttx.pid_offset %d", &((struct tcb_s *)(0))->pid
+ eval "monitor nuttx.xcpreg_offset %d", &((struct tcb_s *)(0))->xcp.regs
+ eval "monitor nuttx.state_offset %d", &((struct tcb_s *)(0))->task_state
+ eval "monitor nuttx.name_offset %d", &((struct tcb_s *)(0))->name
+ eval "monitor nuttx.name_size %d", sizeof(((struct tcb_s *)(0))->name)
+ end
+
+end
+
+*/
+
+/* default offset */
+#define PID 0xc
+#define XCPREG 0x70
+#define STATE 0x19
+#define NAME 0xb8
+#define NAME_SIZE 32
+
+/* defconfig of nuttx */
+/* #define CONFIG_DISABLE_SIGNALS */
+#define CONFIG_DISABLE_MQUEUE
+/* #define CONFIG_PAGING */
+
+
+#endif /* OPENOCD_RTOS_NUTTX_HEADER_H */
diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c
index 4f23040..bd9da0d 100644
--- a/src/rtos/rtos.c
+++ b/src/rtos/rtos.c
@@ -35,6 +35,7 @@ extern struct rtos_type ChibiOS_rtos;
extern struct rtos_type embKernel_rtos;
extern struct rtos_type mqx_rtos;
extern struct rtos_type uCOS_III_rtos;
+extern struct rtos_type nuttx_rtos;
extern struct rtos_type riscv_rtos;
static struct rtos_type *rtos_types[] = {
@@ -46,6 +47,7 @@ static struct rtos_type *rtos_types[] = {
&embKernel_rtos,
&mqx_rtos,
&uCOS_III_rtos,
+ &nuttx_rtos,
&riscv_rtos,
NULL
};
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index b62899d..eb4eea9 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -936,6 +936,7 @@ static int gdb_new_connection(struct connection *connection)
target = get_target_from_connection(connection);
connection->priv = gdb_connection;
+ connection->cmd_ctx->current_target = target;
/* initialize gdb connection information */
gdb_connection->buf_p = gdb_connection->buffer;
@@ -1359,7 +1360,8 @@ static int gdb_set_register_packet(struct connection *connection,
int chars = (DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2);
if ((unsigned int)chars != strlen(separator + 1)) {
- LOG_ERROR("gdb sent a packet with wrong register size");
+ LOG_ERROR("gdb sent %zu bits for a %d-bit register (%s)",
+ strlen(separator + 1) * 4, chars * 4, reg_list[reg_num]->name);
free(bin_buf);
return ERROR_SERVER_REMOTE_CLOSED;
}
@@ -3020,9 +3022,12 @@ static int gdb_v_packet(struct connection *connection,
static int gdb_detach(struct connection *connection)
{
- target_call_event_callbacks(get_target_from_connection(connection),
- TARGET_EVENT_GDB_DETACH);
-
+ /*
+ * Only reply "OK" to GDB
+ * it will close the connection and this will trigger a call to
+ * gdb_connection_closed() that will in turn trigger the event
+ * TARGET_EVENT_GDB_DETACH
+ */
return gdb_put_packet(connection, "OK", 2);
}
diff --git a/src/server/server.c b/src/server/server.c
index 4e80656..f8273d4 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -46,9 +46,13 @@
static struct service *services;
-/* shutdown_openocd == 1: exit the main event loop, and quit the
- * debugger; 2: quit with non-zero return code */
-static int shutdown_openocd;
+enum shutdown_reason {
+ CONTINUE_MAIN_LOOP, /* stay in main event loop */
+ SHUTDOWN_REQUESTED, /* set by shutdown command; exit the event loop and quit the debugger */
+ SHUTDOWN_WITH_ERROR_CODE, /* set by shutdown command; quit with non-zero return code */
+ SHUTDOWN_WITH_SIGNAL_CODE /* set by sig_handler; exec shutdown then exit with signal as return code */
+};
+static enum shutdown_reason shutdown_openocd = CONTINUE_MAIN_LOOP;
/* store received signal to exit application by killing ourselves */
static int last_signal;
@@ -360,6 +364,35 @@ static void remove_connections(struct service *service)
}
}
+int remove_service(const char *name, const char *port)
+{
+ struct service *tmp;
+ struct service *prev;
+
+ prev = services;
+
+ for (tmp = services; tmp; prev = tmp, tmp = tmp->next) {
+ if (!strcmp(tmp->name, name) && !strcmp(tmp->port, port)) {
+ remove_connections(tmp);
+
+ if (tmp == services)
+ services = tmp->next;
+ else
+ prev->next = tmp->next;
+
+ if (tmp->type != CONNECTION_STDINOUT)
+ close_socket(tmp->fd);
+
+ free(tmp->priv);
+ free_service(tmp);
+
+ return ERROR_OK;
+ }
+ }
+
+ return ERROR_OK;
+}
+
static int remove_services(void)
{
struct service *c = services;
@@ -413,7 +446,7 @@ int server_loop(struct command_context *command_context)
LOG_ERROR("couldn't set SIGPIPE to SIG_IGN");
#endif
- while (!shutdown_openocd) {
+ while (shutdown_openocd == CONTINUE_MAIN_LOOP) {
/* monitor sockets for activity */
fd_max = 0;
FD_ZERO(&read_fds);
@@ -505,7 +538,7 @@ int server_loop(struct command_context *command_context)
for (service = services; service; service = service->next) {
/* handle new connections on listeners */
if ((service->fd != -1)
- && (FD_ISSET(service->fd, &read_fds))) {
+ && (FD_ISSET(service->fd, &read_fds))) {
if (service->max_connections != 0)
add_connection(service, command_context);
else {
@@ -537,7 +570,7 @@ int server_loop(struct command_context *command_context)
service->type == CONNECTION_STDINOUT) {
/* if connection uses a pipe then
* shutdown openocd on error */
- shutdown_openocd = 1;
+ shutdown_openocd = SHUTDOWN_REQUESTED;
}
remove_connection(service, c);
LOG_INFO("dropped '%s' connection",
@@ -555,29 +588,48 @@ int server_loop(struct command_context *command_context)
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
- shutdown_openocd = 1;
+ shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE;
}
#endif
}
- return shutdown_openocd != 2 ? ERROR_OK : ERROR_FAIL;
+ /* when quit for signal or CTRL-C, run (eventually user implemented) "shutdown" */
+ if (shutdown_openocd == SHUTDOWN_WITH_SIGNAL_CODE)
+ command_run_line(command_context, "shutdown");
+
+ return shutdown_openocd == SHUTDOWN_WITH_ERROR_CODE ? ERROR_FAIL : ERROR_OK;
}
+void sig_handler(int sig)
+{
+ /* store only first signal that hits us */
+ if (shutdown_openocd == CONTINUE_MAIN_LOOP) {
+ shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE;
+ last_signal = sig;
+ LOG_DEBUG("Terminating on Signal %d", sig);
+ } else
+ LOG_DEBUG("Ignored extra Signal %d", sig);
+}
+
+
#ifdef _WIN32
BOOL WINAPI ControlHandler(DWORD dwCtrlType)
{
- shutdown_openocd = 1;
+ shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE;
return TRUE;
}
-#endif
-
-void sig_handler(int sig)
+#else
+static void sigkey_handler(int sig)
{
- /* store only first signal that hits us */
- if (!last_signal)
- last_signal = sig;
- shutdown_openocd = 1;
+ /* ignore keystroke generated signals if not in foreground process group */
+
+ if (tcgetpgrp(STDIN_FILENO) > 0)
+ sig_handler(sig);
+ else
+ LOG_DEBUG("Ignored Signal %d", sig);
}
+#endif
+
int server_preinit(void)
{
@@ -600,8 +652,13 @@ int server_preinit(void)
SetConsoleCtrlHandler(ControlHandler, TRUE);
signal(SIGBREAK, sig_handler);
-#endif
signal(SIGINT, sig_handler);
+#else
+ signal(SIGHUP, sig_handler);
+ signal(SIGPIPE, sig_handler);
+ signal(SIGQUIT, sigkey_handler);
+ signal(SIGINT, sigkey_handler);
+#endif
signal(SIGTERM, sig_handler);
signal(SIGABRT, sig_handler);
@@ -682,11 +739,11 @@ COMMAND_HANDLER(handle_shutdown_command)
{
LOG_USER("shutdown command invoked");
- shutdown_openocd = 1;
+ shutdown_openocd = SHUTDOWN_REQUESTED;
if (CMD_ARGC == 1) {
if (!strcmp(CMD_ARGV[0], "error")) {
- shutdown_openocd = 2;
+ shutdown_openocd = SHUTDOWN_WITH_ERROR_CODE;
return ERROR_FAIL;
}
}
@@ -743,7 +800,7 @@ static const struct command_registration server_command_handlers[] = {
.mode = COMMAND_ANY,
.usage = "[name]",
.help = "Specify address by name on which to listen for "
- "incoming TCP/IP connections",
+ "incoming TCP/IP connections",
},
COMMAND_REGISTRATION_DONE
};
diff --git a/src/server/server.h b/src/server/server.h
index d4eae94..96e0b48 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -78,6 +78,7 @@ int add_service(char *name, const char *port,
int max_connections, new_connection_handler_t new_connection_handler,
input_handler_t in_handler, connection_closed_handler_t close_handler,
void *priv);
+int remove_service(const char *name, const char *port);
int server_preinit(void);
int server_init(struct command_context *cmd_ctx);
diff --git a/src/target/aarch64.c b/src/target/aarch64.c
index df1e49c..454de9e 100644
--- a/src/target/aarch64.c
+++ b/src/target/aarch64.c
@@ -28,6 +28,7 @@
#include "target_type.h"
#include "armv8_opcodes.h"
#include "armv8_cache.h"
+#include "arm_semihosting.h"
#include <helper/time_support.h>
enum restart_mode {
@@ -522,6 +523,9 @@ static int aarch64_poll(struct target *target)
if (target->smp)
update_halt_gdb(target, debug_reason);
+ if (arm_semihosting(target, &retval) != 0)
+ return retval;
+
switch (prev_target_state) {
case TARGET_RUNNING:
case TARGET_UNKNOWN:
@@ -543,6 +547,9 @@ static int aarch64_poll(struct target *target)
static int aarch64_halt(struct target *target)
{
+ struct armv8_common *armv8 = target_to_armv8(target);
+ armv8->last_run_control_op = ARMV8_RUNCONTROL_HALT;
+
if (target->smp)
return aarch64_halt_smp(target, false);
@@ -831,6 +838,9 @@ static int aarch64_resume(struct target *target, int current,
int retval = 0;
uint64_t addr = address;
+ struct armv8_common *armv8 = target_to_armv8(target);
+ armv8->last_run_control_op = ARMV8_RUNCONTROL_RESUME;
+
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
@@ -1069,6 +1079,8 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres
int retval;
uint32_t edecr;
+ armv8->last_run_control_op = ARMV8_RUNCONTROL_STEP;
+
if (target->state != TARGET_HALTED) {
LOG_WARNING("target not halted");
return ERROR_TARGET_NOT_HALTED;
@@ -1682,17 +1694,19 @@ static int aarch64_deassert_reset(struct target *target)
if (retval != ERROR_OK)
return retval;
+ retval = aarch64_init_debug_access(target);
+ if (retval != ERROR_OK)
+ return retval;
+
if (target->reset_halt) {
if (target->state != TARGET_HALTED) {
LOG_WARNING("%s: ran after reset and before halt ...",
target_name(target));
retval = target_halt(target);
- if (retval != ERROR_OK)
- return retval;
}
}
- return aarch64_init_debug_access(target);
+ return retval;
}
static int aarch64_write_cpu_memory_slow(struct target *target,
@@ -2351,6 +2365,7 @@ static int aarch64_init_target(struct command_context *cmd_ctx,
struct target *target)
{
/* examine_first() does a bunch of this */
+ arm_semihosting_init(target);
return ERROR_OK;
}
diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c
index 0de272d..b520223 100644
--- a/src/target/adi_v5_swd.c
+++ b/src/target/adi_v5_swd.c
@@ -276,6 +276,16 @@ static int swd_run(struct adiv5_dap *dap)
return swd_run_inner(dap);
}
+/** Put the SWJ-DP back to JTAG mode */
+static void swd_quit(struct adiv5_dap *dap)
+{
+ const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
+
+ swd->switch_seq(SWD_TO_JTAG);
+ /* flush the queue before exit */
+ swd->run();
+}
+
const struct dap_ops swd_dap_ops = {
.connect = swd_connect,
.queue_dp_read = swd_queue_dp_read,
@@ -284,6 +294,7 @@ const struct dap_ops swd_dap_ops = {
.queue_ap_write = swd_queue_ap_write,
.queue_ap_abort = swd_queue_ap_abort,
.run = swd_run,
+ .quit = swd_quit,
};
/*
diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c
index d0a58bd..302ea78 100644
--- a/src/target/arm_adi_v5.c
+++ b/src/target/arm_adi_v5.c
@@ -102,8 +102,10 @@ static int mem_ap_setup_csw(struct adiv5_ap *ap, uint32_t csw)
if (csw != ap->csw_value) {
/* LOG_DEBUG("DAP: Set CSW %x",csw); */
int retval = dap_queue_ap_write(ap, MEM_AP_REG_CSW, csw);
- if (retval != ERROR_OK)
+ if (retval != ERROR_OK) {
+ ap->csw_value = 0;
return retval;
+ }
ap->csw_value = csw;
}
return ERROR_OK;
@@ -114,8 +116,10 @@ static int mem_ap_setup_tar(struct adiv5_ap *ap, uint32_t tar)
if (!ap->tar_valid || tar != ap->tar_value) {
/* LOG_DEBUG("DAP: Set TAR %x",tar); */
int retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR, tar);
- if (retval != ERROR_OK)
+ if (retval != ERROR_OK) {
+ ap->tar_valid = false;
return retval;
+ }
ap->tar_value = tar;
ap->tar_valid = true;
}
@@ -1612,13 +1616,12 @@ COMMAND_HANDLER(dap_memaccess_command)
COMMAND_HANDLER(dap_apsel_command)
{
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
- uint32_t apsel, apid;
- int retval;
+ uint32_t apsel;
switch (CMD_ARGC) {
case 0:
- apsel = dap->apsel;
- break;
+ command_print(CMD_CTX, "%" PRIi32, dap->apsel);
+ return ERROR_OK;
case 1:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
/* AP address is in bits 31:24 of DP_SELECT */
@@ -1630,18 +1633,7 @@ COMMAND_HANDLER(dap_apsel_command)
}
dap->apsel = apsel;
-
- retval = dap_queue_ap_read(dap_ap(dap, apsel), AP_REG_IDR, &apid);
- if (retval != ERROR_OK)
- return retval;
- retval = dap_run(dap);
- if (retval != ERROR_OK)
- return retval;
-
- command_print(CMD_CTX, "ap %" PRIi32 " selected, identification register 0x%8.8" PRIx32,
- apsel, apid);
-
- return retval;
+ return ERROR_OK;
}
COMMAND_HANDLER(dap_apcsw_command)
@@ -1722,6 +1714,7 @@ COMMAND_HANDLER(dap_apreg_command)
{
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
uint32_t apsel, reg, value;
+ struct adiv5_ap *ap;
int retval;
if (CMD_ARGC < 2 || CMD_ARGC > 3)
@@ -1731,6 +1724,7 @@ COMMAND_HANDLER(dap_apreg_command)
/* AP address is in bits 31:24 of DP_SELECT */
if (apsel >= 256)
return ERROR_COMMAND_SYNTAX_ERROR;
+ ap = dap_ap(dap, apsel);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg);
if (reg >= 256 || (reg & 3))
@@ -1738,9 +1732,21 @@ COMMAND_HANDLER(dap_apreg_command)
if (CMD_ARGC == 3) {
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value);
- retval = dap_queue_ap_write(dap_ap(dap, apsel), reg, value);
+ switch (reg) {
+ case MEM_AP_REG_CSW:
+ ap->csw_default = 0; /* invalid, force write */
+ retval = mem_ap_setup_csw(ap, value);
+ break;
+ case MEM_AP_REG_TAR:
+ ap->tar_valid = false; /* invalid, force write */
+ retval = mem_ap_setup_tar(ap, value);
+ break;
+ default:
+ retval = dap_queue_ap_write(ap, reg, value);
+ break;
+ }
} else {
- retval = dap_queue_ap_read(dap_ap(dap, apsel), reg, &value);
+ retval = dap_queue_ap_read(ap, reg, &value);
}
if (retval == ERROR_OK)
retval = dap_run(dap);
@@ -1754,6 +1760,37 @@ COMMAND_HANDLER(dap_apreg_command)
return retval;
}
+COMMAND_HANDLER(dap_dpreg_command)
+{
+ struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
+ uint32_t reg, value;
+ int retval;
+
+ if (CMD_ARGC < 1 || CMD_ARGC > 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], reg);
+ if (reg >= 256 || (reg & 3))
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (CMD_ARGC == 2) {
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
+ retval = dap_queue_dp_write(dap, reg, value);
+ } else {
+ retval = dap_queue_dp_read(dap, reg, &value);
+ }
+ if (retval == ERROR_OK)
+ retval = dap_run(dap);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (CMD_ARGC == 1)
+ command_print(CMD_CTX, "0x%08" PRIx32, value);
+
+ return retval;
+}
+
COMMAND_HANDLER(dap_ti_be_32_quirks_command)
{
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
@@ -1789,7 +1826,7 @@ const struct command_registration dap_instance_commands[] = {
{
.name = "apsel",
.handler = dap_apsel_command,
- .mode = COMMAND_EXEC,
+ .mode = COMMAND_ANY,
.help = "Set the currently selected AP (default 0) "
"and display the result",
.usage = "[ap_num]",
@@ -1797,7 +1834,7 @@ const struct command_registration dap_instance_commands[] = {
{
.name = "apcsw",
.handler = dap_apcsw_command,
- .mode = COMMAND_EXEC,
+ .mode = COMMAND_ANY,
.help = "Set CSW default bits",
.usage = "[value [mask]]",
},
@@ -1819,6 +1856,14 @@ const struct command_registration dap_instance_commands[] = {
.usage = "ap_num reg [value]",
},
{
+ .name = "dpreg",
+ .handler = dap_dpreg_command,
+ .mode = COMMAND_EXEC,
+ .help = "read/write a register from DP "
+ "(reg is byte address (bank << 4 | reg) of a word register, like 0 4 8...)",
+ .usage = "reg [value]",
+ },
+ {
.name = "baseaddr",
.handler = dap_baseaddr_command,
.mode = COMMAND_EXEC,
diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h
index 22c3166..883ac8b 100644
--- a/src/target/arm_adi_v5.h
+++ b/src/target/arm_adi_v5.h
@@ -286,6 +286,9 @@ struct dap_ops {
/** Executes all queued DAP operations but doesn't check
* sticky error conditions */
int (*sync)(struct adiv5_dap *dap);
+
+ /** Optional; called at OpenOCD exit */
+ void (*quit)(struct adiv5_dap *dap);
};
/*
diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c
index 8c08180..3be4d71 100644
--- a/src/target/arm_dap.c
+++ b/src/target/arm_dap.c
@@ -132,8 +132,13 @@ static int dap_init_all(void)
int dap_cleanup_all(void)
{
struct arm_dap_object *obj, *tmp;
+ struct adiv5_dap *dap;
list_for_each_entry_safe(obj, tmp, &all_dap, lh) {
+ dap = &obj->dap;
+ if (dap->ops && dap->ops->quit)
+ dap->ops->quit(dap);
+
free(obj->name);
free(obj);
}
diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c
index 17948d6..8eb8194 100644
--- a/src/target/arm_disassembler.c
+++ b/src/target/arm_disassembler.c
@@ -118,15 +118,78 @@ static int evaluate_pld(uint32_t opcode,
uint32_t address, struct arm_instruction *instruction)
{
/* PLD */
- if ((opcode & 0x0d70f000) == 0x0550f000) {
+ if ((opcode & 0x0d30f000) == 0x0510f000) {
+ uint8_t Rn;
+ uint8_t U;
+ unsigned offset;
+
instruction->type = ARM_PLD;
+ Rn = (opcode & 0xf0000) >> 16;
+ U = (opcode & 0x00800000) >> 23;
+ if (Rn == 0xf) {
+ /* literal */
+ offset = opcode & 0x0fff;
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD %s%d",
+ address, opcode, U ? "" : "-", offset);
+ } else {
+ uint8_t I, R;
- snprintf(instruction->text,
- 128,
- "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD ...TODO...",
- address,
- opcode);
+ I = (opcode & 0x02000000) >> 25;
+ R = (opcode & 0x00400000) >> 22;
+
+ if (I) {
+ /* register PLD{W} [<Rn>,+/-<Rm>{, <shift>}] */
+ offset = (opcode & 0x0F80) >> 7;
+ uint8_t Rm;
+ Rm = opcode & 0xf;
+
+ if (offset == 0) {
+ /* No shift */
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d]",
+ address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm);
+
+ } else {
+ uint8_t shift;
+ shift = (opcode & 0x60) >> 5;
+ if (shift == 0x0) {
+ /* LSL */
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, LSL #0x%x)",
+ address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset);
+ } else if (shift == 0x1) {
+ /* LSR */
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, LSR #0x%x)",
+ address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset);
+ } else if (shift == 0x2) {
+ /* ASR */
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, ASR #0x%x)",
+ address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset);
+ } else if (shift == 0x3) {
+ /* ROR */
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, ROR #0x%x)",
+ address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset);
+ }
+ }
+ } else {
+ /* immediate PLD{W} [<Rn>, #+/-<imm12>] */
+ offset = opcode & 0x0fff;
+ if (offset == 0) {
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d]",
+ address, opcode, R ? "" : "W", Rn);
+ } else {
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, #%s%d]",
+ address, opcode, R ? "" : "W", Rn, U ? "" : "-", offset);
+ }
+ }
+ }
return ERROR_OK;
}
/* DSB */
diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c
index 57f3139..9117a74 100644
--- a/src/target/arm_semihosting.c
+++ b/src/target/arm_semihosting.c
@@ -46,6 +46,7 @@
#include "arm7_9_common.h"
#include "armv7m.h"
#include "armv7a.h"
+#include "armv8.h"
#include "cortex_m.h"
#include "register.h"
#include "arm_opcodes.h"
@@ -55,10 +56,35 @@
#include <helper/log.h>
#include <sys/stat.h>
+static int arm_semihosting_resume(struct target *target, int *retval)
+{
+ if (is_armv8(target_to_armv8(target))) {
+ struct armv8_common *armv8 = target_to_armv8(target);
+ if (armv8->last_run_control_op == ARMV8_RUNCONTROL_RESUME) {
+ *retval = target_resume(target, 1, 0, 0, 0);
+ if (*retval != ERROR_OK) {
+ LOG_ERROR("Failed to resume target");
+ return 0;
+ }
+ } else if (armv8->last_run_control_op == ARMV8_RUNCONTROL_STEP)
+ target->debug_reason = DBG_REASON_SINGLESTEP;
+ } else {
+ *retval = target_resume(target, 1, 0, 0, 0);
+ if (*retval != ERROR_OK) {
+ LOG_ERROR("Failed to resume target");
+ return 0;
+ }
+ }
+ return 1;
+}
+
static int post_result(struct target *target)
{
struct arm *arm = target_to_arm(target);
+ if (!target->semihosting)
+ return ERROR_FAIL;
+
/* REVISIT this looks wrong ... ARM11 and Cortex-A8
* should work this way at least sometimes.
*/
@@ -88,6 +114,16 @@ static int post_result(struct target *target)
if (spsr & 0x20)
arm->core_state = ARM_STATE_THUMB;
+ } else if (is_armv8(target_to_armv8(target))) {
+ if (arm->core_state == ARM_STATE_AARCH64) {
+ /* return value in R0 */
+ buf_set_u64(arm->core_cache->reg_list[0].value, 0, 64, target->semihosting->result);
+ arm->core_cache->reg_list[0].dirty = 1;
+
+ uint64_t pc = buf_get_u64(arm->core_cache->reg_list[32].value, 0, 64);
+ buf_set_u64(arm->pc->value, 0, 64, pc + 4);
+ arm->pc->dirty = 1;
+ }
} else {
/* resume execution, this will be pc+2 to skip over the
* bkpt instruction */
@@ -235,6 +271,24 @@ int arm_semihosting(struct target *target, int *retval)
/* bkpt 0xAB */
if (insn != 0xBEAB)
return 0;
+ } else if (is_armv8(target_to_armv8(target))) {
+ if (target->debug_reason != DBG_REASON_BREAKPOINT)
+ return 0;
+
+ if (arm->core_state == ARM_STATE_AARCH64) {
+ uint32_t insn = 0;
+ r = arm->pc;
+ uint64_t pc64 = buf_get_u64(r->value, 0, 64);
+ *retval = target_read_u32(target, pc64, &insn);
+
+ if (*retval != ERROR_OK)
+ return 1;
+
+ /* bkpt 0xAB */
+ if (insn != 0xD45E0000)
+ return 0;
+ } else
+ return 1;
} else {
LOG_ERROR("Unsupported semi-hosting Target");
return 0;
@@ -244,13 +298,18 @@ int arm_semihosting(struct target *target, int *retval)
* operation to complete.
*/
if (!semihosting->hit_fileio) {
- /* TODO: update for 64-bits */
- uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32);
- uint32_t r1 = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32);
-
- semihosting->op = r0;
- semihosting->param = r1;
- semihosting->word_size_bytes = 4;
+ if (is_armv8(target_to_armv8(target)) &&
+ arm->core_state == ARM_STATE_AARCH64) {
+ /* Read op and param from register x0 and x1 respectively. */
+ semihosting->op = buf_get_u64(arm->core_cache->reg_list[0].value, 0, 64);
+ semihosting->param = buf_get_u64(arm->core_cache->reg_list[1].value, 0, 64);
+ semihosting->word_size_bytes = 8;
+ } else {
+ /* Read op and param from register r0 and r1 respectively. */
+ semihosting->op = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32);
+ semihosting->param = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32);
+ semihosting->word_size_bytes = 4;
+ }
/* Check for ARM operation numbers. */
if (0 <= semihosting->op && semihosting->op <= 0x31) {
@@ -265,19 +324,11 @@ int arm_semihosting(struct target *target, int *retval)
}
}
- /* Post result to target if we are not waiting on a fileio
+ /* Resume if target it is resumable and we are not waiting on a fileio
* operation to complete:
*/
- if (semihosting->is_resumable && !semihosting->hit_fileio) {
- /* Resume right after the BRK instruction. */
- *retval = target_resume(target, 1, 0, 0, 0);
- if (*retval != ERROR_OK) {
- LOG_ERROR("Failed to resume target");
- return 0;
- }
-
- return 1;
- }
+ if (semihosting->is_resumable && !semihosting->hit_fileio)
+ return arm_semihosting_resume(target, retval);
return 0;
}
diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c
index 5ee8ead..96a63e4 100644
--- a/src/target/armv4_5.c
+++ b/src/target/armv4_5.c
@@ -752,7 +752,7 @@ int arm_arch_state(struct target *target)
}
/* avoid filling log waiting for fileio reply */
- if (target->semihosting->hit_fileio)
+ if (target->semihosting && target->semihosting->hit_fileio)
return ERROR_OK;
LOG_USER("target halted in %s state due to %s, current mode: %s\n"
@@ -762,8 +762,8 @@ int arm_arch_state(struct target *target)
arm_mode_name(arm->core_mode),
buf_get_u32(arm->cpsr->value, 0, 32),
buf_get_u32(arm->pc->value, 0, 32),
- target->semihosting->is_active ? ", semihosting" : "",
- target->semihosting->is_fileio ? " fileio" : "");
+ (target->semihosting && target->semihosting->is_active) ? ", semihosting" : "",
+ (target->semihosting && target->semihosting->is_fileio) ? " fileio" : "");
return ERROR_OK;
}
diff --git a/src/target/armv7a.c b/src/target/armv7a.c
index fab7363..eecfa70 100644
--- a/src/target/armv7a.c
+++ b/src/target/armv7a.c
@@ -124,7 +124,7 @@ done:
return retval;
}
-static int armv7a_read_ttbcr(struct target *target)
+int armv7a_read_ttbcr(struct target *target)
{
struct armv7a_common *armv7a = target_to_armv7a(target);
struct arm_dpm *dpm = armv7a->arm.dpm;
@@ -554,9 +554,6 @@ int armv7a_identify_cache(struct target *target)
struct armv7a_cache_common *cache =
&(armv7a->armv7a_mmu.armv7a_cache);
- if (!armv7a->is_armv7r)
- armv7a_read_ttbcr(target);
-
retval = dpm->prepare(dpm);
if (retval != ERROR_OK)
goto done;
@@ -729,8 +726,6 @@ int armv7a_arch_state(struct target *target)
arm_arch_state(target);
- armv7a_read_ttbcr(target);
-
if (armv7a->is_armv7r) {
LOG_USER("D-Cache: %s, I-Cache: %s",
state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled],
diff --git a/src/target/armv7a.h b/src/target/armv7a.h
index 33f6f5d..57779c6 100644
--- a/src/target/armv7a.h
+++ b/src/target/armv7a.h
@@ -194,6 +194,7 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val);
int armv7a_handle_cache_info_command(struct command_context *cmd_ctx,
struct armv7a_cache_common *armv7a_cache);
+int armv7a_read_ttbcr(struct target *target);
extern const struct command_registration armv7a_command_handlers[];
diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c
index 3e5f8d6..7435aab 100644
--- a/src/target/armv7a_cache.c
+++ b/src/target/armv7a_cache.c
@@ -70,6 +70,7 @@ static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cach
LOG_DEBUG("cl %" PRId32, cl);
do {
+ keep_alive();
c_way = size->way;
do {
uint32_t value = (c_index << size->index_shift)
@@ -89,6 +90,7 @@ static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cach
} while (c_index >= 0);
done:
+ keep_alive();
return retval;
}
@@ -164,7 +166,7 @@ int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
uint32_t linelen = armv7a_cache->dminline;
uint32_t va_line, va_end;
- int retval;
+ int retval, i = 0;
retval = armv7a_l1_d_cache_sanity_check(target);
if (retval != ERROR_OK)
@@ -198,6 +200,8 @@ int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
}
while (va_line < va_end) {
+ if ((i++ & 0x3f) == 0)
+ keep_alive();
/* DCIMVAC - Invalidate data cache line by VA to PoC. */
retval = dpm->instr_write_data_r0(dpm,
ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line);
@@ -206,11 +210,13 @@ int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
va_line += linelen;
}
+ keep_alive();
dpm->finish(dpm);
return retval;
done:
LOG_ERROR("d-cache invalidate failed");
+ keep_alive();
dpm->finish(dpm);
return retval;
@@ -224,7 +230,7 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
uint32_t linelen = armv7a_cache->dminline;
uint32_t va_line, va_end;
- int retval;
+ int retval, i = 0;
retval = armv7a_l1_d_cache_sanity_check(target);
if (retval != ERROR_OK)
@@ -238,6 +244,8 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
va_end = virt + size;
while (va_line < va_end) {
+ if ((i++ & 0x3f) == 0)
+ keep_alive();
/* DCCMVAC - Data Cache Clean by MVA to PoC */
retval = dpm->instr_write_data_r0(dpm,
ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line);
@@ -246,11 +254,13 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
va_line += linelen;
}
+ keep_alive();
dpm->finish(dpm);
return retval;
done:
LOG_ERROR("d-cache invalidate failed");
+ keep_alive();
dpm->finish(dpm);
return retval;
@@ -264,7 +274,7 @@ int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
uint32_t linelen = armv7a_cache->dminline;
uint32_t va_line, va_end;
- int retval;
+ int retval, i = 0;
retval = armv7a_l1_d_cache_sanity_check(target);
if (retval != ERROR_OK)
@@ -278,6 +288,8 @@ int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
va_end = virt + size;
while (va_line < va_end) {
+ if ((i++ & 0x3f) == 0)
+ keep_alive();
/* DCCIMVAC */
retval = dpm->instr_write_data_r0(dpm,
ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
@@ -286,11 +298,13 @@ int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
va_line += linelen;
}
+ keep_alive();
dpm->finish(dpm);
return retval;
done:
LOG_ERROR("d-cache invalidate failed");
+ keep_alive();
dpm->finish(dpm);
return retval;
@@ -342,7 +356,7 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
&armv7a->armv7a_mmu.armv7a_cache;
uint32_t linelen = armv7a_cache->iminline;
uint32_t va_line, va_end;
- int retval;
+ int retval, i = 0;
retval = armv7a_l1_i_cache_sanity_check(target);
if (retval != ERROR_OK)
@@ -356,6 +370,8 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
va_end = virt + size;
while (va_line < va_end) {
+ if ((i++ & 0x3f) == 0)
+ keep_alive();
/* ICIMVAU - Invalidate instruction cache by VA to PoU. */
retval = dpm->instr_write_data_r0(dpm,
ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line);
@@ -368,10 +384,13 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
goto done;
va_line += linelen;
}
+ keep_alive();
+ dpm->finish(dpm);
return retval;
done:
LOG_ERROR("i-cache invalidate failed");
+ keep_alive();
dpm->finish(dpm);
return retval;
diff --git a/src/target/armv7m.c b/src/target/armv7m.c
index 1b4e5b1..7d3bd73 100644
--- a/src/target/armv7m.c
+++ b/src/target/armv7m.c
@@ -541,7 +541,7 @@ int armv7m_arch_state(struct target *target)
uint32_t ctrl, sp;
/* avoid filling log waiting for fileio reply */
- if (target->semihosting->hit_fileio)
+ if (target->semihosting && target->semihosting->hit_fileio)
return ERROR_OK;
ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
@@ -556,8 +556,8 @@ int armv7m_arch_state(struct target *target)
buf_get_u32(arm->pc->value, 0, 32),
(ctrl & 0x02) ? 'p' : 'm',
sp,
- target->semihosting->is_active ? ", semihosting" : "",
- target->semihosting->is_fileio ? " fileio" : "");
+ (target->semihosting && target->semihosting->is_active) ? ", semihosting" : "",
+ (target->semihosting && target->semihosting->is_fileio) ? " fileio" : "");
return ERROR_OK;
}
diff --git a/src/target/armv7m_trace.c b/src/target/armv7m_trace.c
index c1e4f5b..62f0f8e 100644
--- a/src/target/armv7m_trace.c
+++ b/src/target/armv7m_trace.c
@@ -62,7 +62,7 @@ int armv7m_trace_tpiu_config(struct target *target)
target_unregister_timer_callback(armv7m_poll_trace, target);
- retval = adapter_config_trace(trace_config->config_type == INTERNAL,
+ retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL,
trace_config->pin_protocol,
trace_config->port_size,
&trace_config->trace_freq);
@@ -83,7 +83,7 @@ int armv7m_trace_tpiu_config(struct target *target)
trace_config->trace_freq, trace_config->traceclkin_freq,
trace_freq);
trace_config->trace_freq = trace_freq;
- retval = adapter_config_trace(trace_config->config_type == INTERNAL,
+ retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL,
trace_config->pin_protocol,
trace_config->port_size,
&trace_config->trace_freq);
@@ -115,7 +115,7 @@ int armv7m_trace_tpiu_config(struct target *target)
if (retval != ERROR_OK)
return retval;
- if (trace_config->config_type == INTERNAL)
+ if (trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL)
target_register_timer_callback(armv7m_poll_trace, 1, 1, target);
target_call_event_callbacks(target, TARGET_EVENT_TRACE_CONFIG);
@@ -173,7 +173,7 @@ COMMAND_HANDLER(handle_tpiu_config_command)
if (CMD_ARGC == cmd_idx + 1) {
close_trace_file(armv7m);
- armv7m->trace_config.config_type = DISABLED;
+ armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_DISABLED;
if (CMD_CTX->mode == COMMAND_EXEC)
return armv7m_trace_tpiu_config(target);
else
@@ -183,13 +183,13 @@ COMMAND_HANDLER(handle_tpiu_config_command)
!strcmp(CMD_ARGV[cmd_idx], "internal")) {
close_trace_file(armv7m);
- armv7m->trace_config.config_type = EXTERNAL;
+ armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_EXTERNAL;
if (!strcmp(CMD_ARGV[cmd_idx], "internal")) {
cmd_idx++;
if (CMD_ARGC == cmd_idx)
return ERROR_COMMAND_SYNTAX_ERROR;
- armv7m->trace_config.config_type = INTERNAL;
+ armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_INTERNAL;
if (strcmp(CMD_ARGV[cmd_idx], "-") != 0) {
armv7m->trace_config.trace_file = fopen(CMD_ARGV[cmd_idx], "ab");
@@ -204,7 +204,7 @@ COMMAND_HANDLER(handle_tpiu_config_command)
return ERROR_COMMAND_SYNTAX_ERROR;
if (!strcmp(CMD_ARGV[cmd_idx], "sync")) {
- armv7m->trace_config.pin_protocol = SYNC;
+ armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_SYNC;
cmd_idx++;
if (CMD_ARGC == cmd_idx)
@@ -213,9 +213,9 @@ COMMAND_HANDLER(handle_tpiu_config_command)
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[cmd_idx], armv7m->trace_config.port_size);
} else {
if (!strcmp(CMD_ARGV[cmd_idx], "manchester"))
- armv7m->trace_config.pin_protocol = ASYNC_MANCHESTER;
+ armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER;
else if (!strcmp(CMD_ARGV[cmd_idx], "uart"))
- armv7m->trace_config.pin_protocol = ASYNC_UART;
+ armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_UART;
else
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -237,7 +237,7 @@ COMMAND_HANDLER(handle_tpiu_config_command)
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.trace_freq);
cmd_idx++;
} else {
- if (armv7m->trace_config.config_type != INTERNAL) {
+ if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_INTERNAL) {
LOG_ERROR("Trace port frequency can't be omitted in external capture mode");
return ERROR_COMMAND_SYNTAX_ERROR;
}
diff --git a/src/target/armv7m_trace.h b/src/target/armv7m_trace.h
index 4f99394..c63f36d 100644
--- a/src/target/armv7m_trace.h
+++ b/src/target/armv7m_trace.h
@@ -27,15 +27,15 @@
*/
enum trace_config_type {
- DISABLED, /**< tracing is disabled */
- EXTERNAL, /**< trace output is captured externally */
- INTERNAL /**< trace output is handled by OpenOCD adapter driver */
+ TRACE_CONFIG_TYPE_DISABLED, /**< tracing is disabled */
+ TRACE_CONFIG_TYPE_EXTERNAL, /**< trace output is captured externally */
+ TRACE_CONFIG_TYPE_INTERNAL /**< trace output is handled by OpenOCD adapter driver */
};
-enum tpio_pin_protocol {
- SYNC, /**< synchronous trace output */
- ASYNC_MANCHESTER, /**< asynchronous output with Manchester coding */
- ASYNC_UART /**< asynchronous output with NRZ coding */
+enum tpiu_pin_protocol {
+ TPIU_PIN_PROTOCOL_SYNC, /**< synchronous trace output */
+ TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER, /**< asynchronous output with Manchester coding */
+ TPIU_PIN_PROTOCOL_ASYNC_UART /**< asynchronous output with NRZ coding */
};
enum itm_ts_prescaler {
@@ -50,7 +50,7 @@ struct armv7m_trace_config {
enum trace_config_type config_type;
/** Currently active trace output mode */
- enum tpio_pin_protocol pin_protocol;
+ enum tpiu_pin_protocol pin_protocol;
/** TPIU formatter enable/disable (in async mode) */
bool formatter;
/** Synchronous output port width */
diff --git a/src/target/armv8.c b/src/target/armv8.c
index 20f2b67..dfa2c67 100644
--- a/src/target/armv8.c
+++ b/src/target/armv8.c
@@ -1017,11 +1017,24 @@ int armv8_handle_cache_info_command(struct command_context *cmd_ctx,
return ERROR_OK;
}
+static int armv8_setup_semihosting(struct target *target, int enable)
+{
+ struct arm *arm = target_to_arm(target);
+
+ if (arm->core_state != ARM_STATE_AARCH64) {
+ LOG_ERROR("semihosting only supported in AArch64 state\n");
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
int armv8_init_arch_info(struct target *target, struct armv8_common *armv8)
{
struct arm *arm = &armv8->arm;
arm->arch_info = armv8;
target->arch_info = &armv8->arm;
+ arm->setup_semihosting = armv8_setup_semihosting;
/* target is useful in all function arm v4 5 compatible */
armv8->arm.target = target;
armv8->arm.common_magic = ARM_COMMON_MAGIC;
@@ -1050,7 +1063,7 @@ int armv8_aarch64_state(struct target *target)
armv8_mode_name(arm->core_mode),
buf_get_u32(arm->cpsr->value, 0, 32),
buf_get_u64(arm->pc->value, 0, 64),
- target->semihosting->is_active ? ", semihosting" : "");
+ (target->semihosting && target->semihosting->is_active) ? ", semihosting" : "");
return ERROR_OK;
}
diff --git a/src/target/armv8.h b/src/target/armv8.h
index b346462..dfd54ed 100644
--- a/src/target/armv8.h
+++ b/src/target/armv8.h
@@ -113,6 +113,12 @@ enum {
ARMV8_LAST_REG,
};
+enum run_control_op {
+ ARMV8_RUNCONTROL_UNKNOWN = 0,
+ ARMV8_RUNCONTROL_RESUME = 1,
+ ARMV8_RUNCONTROL_HALT = 2,
+ ARMV8_RUNCONTROL_STEP = 3,
+};
#define ARMV8_COMMON_MAGIC 0x0A450AAA
@@ -210,6 +216,9 @@ struct armv8_common {
struct arm_cti *cti;
+ /* last run-control command issued to this target (resume, halt, step) */
+ enum run_control_op last_run_control_op;
+
/* Direct processor core register read and writes */
int (*read_reg_u64)(struct armv8_common *armv8, int num, uint64_t *value);
int (*write_reg_u64)(struct armv8_common *armv8, int num, uint64_t value);
@@ -232,6 +241,11 @@ target_to_armv8(struct target *target)
return container_of(target->arch_info, struct armv8_common, arm);
}
+static inline bool is_armv8(struct armv8_common *armv8)
+{
+ return armv8->common_magic == ARMV8_COMMON_MAGIC;
+}
+
/* register offsets from armv8.debug_base */
#define CPUV8_DBG_MAINID0 0xD00
#define CPUV8_DBG_CPUFEATURE0 0xD20
diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c
index 8985051..4aae5e4 100644
--- a/src/target/cortex_a.c
+++ b/src/target/cortex_a.c
@@ -1297,6 +1297,9 @@ static int cortex_a_post_debug_entry(struct target *target)
LOG_DEBUG("cp15_control_reg: %8.8" PRIx32, cortex_a->cp15_control_reg);
cortex_a->cp15_control_reg_curr = cortex_a->cp15_control_reg;
+ if (!armv7a->is_armv7r)
+ armv7a_read_ttbcr(target);
+
if (armv7a->armv7a_mmu.armv7a_cache.info == -1)
armv7a_identify_cache(target);
@@ -3226,6 +3229,20 @@ static int cortex_a_virt2phys(struct target *target,
struct armv7a_common *armv7a = target_to_armv7a(target);
struct adiv5_dap *swjdp = armv7a->arm.dap;
uint8_t apsel = swjdp->apsel;
+ int mmu_enabled = 0;
+
+ /*
+ * If the MMU was not enabled at debug entry, there is no
+ * way of knowing if there was ever a valid configuration
+ * for it and thus it's not safe to enable it. In this case,
+ * just return the virtual address as physical.
+ */
+ cortex_a_mmu(target, &mmu_enabled);
+ if (!mmu_enabled) {
+ *phys = virt;
+ return ERROR_OK;
+ }
+
if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap->ap_num)) {
uint32_t ret;
retval = armv7a_mmu_translate_va(target,
@@ -3421,7 +3438,7 @@ static const struct command_registration cortex_a_exec_command_handlers[] = {
{
.name = "dacrfixup",
.handler = handle_cortex_a_dacrfixup_command,
- .mode = COMMAND_EXEC,
+ .mode = COMMAND_ANY,
.help = "set domain access control (DACR) to all-manager "
"on memory access",
.usage = "['on'|'off']",
diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c
index b6043fc..ca3dbec 100644
--- a/src/target/cortex_m.c
+++ b/src/target/cortex_m.c
@@ -165,7 +165,7 @@ static int cortex_m_single_step_core(struct target *target)
struct armv7m_common *armv7m = &cortex_m->armv7m;
int retval;
- /* Mask interrupts before clearing halt, if done already. This avoids
+ /* Mask interrupts before clearing halt, if not done already. This avoids
* Erratum 377497 (fixed in r1p0) where setting MASKINTS while clearing
* HALT can put the core into an unknown state.
*/
@@ -237,8 +237,11 @@ static int cortex_m_endreset_event(struct target *target)
return retval;
}
- /* clear any interrupt masking */
- cortex_m_write_debug_halt_mask(target, 0, C_MASKINTS);
+ /* Restore proper interrupt masking setting. */
+ if (cortex_m->isrmasking_mode == CORTEX_M_ISRMASK_ON)
+ cortex_m_write_debug_halt_mask(target, C_MASKINTS, 0);
+ else
+ cortex_m_write_debug_halt_mask(target, 0, C_MASKINTS);
/* Enable features controlled by ITM and DWT blocks, and catch only
* the vectors we were told to pay attention to.
@@ -1137,6 +1140,10 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint
breakpoint->set = fp_num + 1;
fpcr_value = breakpoint->address | 1;
if (cortex_m->fp_rev == 0) {
+ if (breakpoint->address > 0x1FFFFFFF) {
+ LOG_ERROR("Cortex-M Flash Patch Breakpoint rev.1 cannot handle HW breakpoint above address 0x1FFFFFFE");
+ return ERROR_FAIL;
+ }
uint32_t hilo;
hilo = (breakpoint->address & 0x2) ? FPCR_REPLACE_BKPT_HIGH : FPCR_REPLACE_BKPT_LOW;
fpcr_value = (fpcr_value & 0x1FFFFFFC) | hilo | 1;
@@ -2076,7 +2083,7 @@ int cortex_m_examine(struct target *target)
if (retval != ERROR_OK)
return retval;
- if (armv7m->trace_config.config_type != DISABLED) {
+ if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_DISABLED) {
armv7m_trace_tpiu_config(target);
armv7m_trace_itm_config(target);
}
@@ -2270,20 +2277,6 @@ static int cortex_m_verify_pointer(struct command_context *cmd_ctx,
* cortexm3_target structure, which is only used with CM3 targets.
*/
-static const struct {
- char name[10];
- unsigned mask;
-} vec_ids[] = {
- { "hard_err", VC_HARDERR, },
- { "int_err", VC_INTERR, },
- { "bus_err", VC_BUSERR, },
- { "state_err", VC_STATERR, },
- { "chk_err", VC_CHKERR, },
- { "nocp_err", VC_NOCPERR, },
- { "mm_err", VC_MMERR, },
- { "reset", VC_CORERESET, },
-};
-
COMMAND_HANDLER(handle_cortex_m_vector_catch_command)
{
struct target *target = get_current_target(CMD_CTX);
@@ -2292,6 +2285,20 @@ COMMAND_HANDLER(handle_cortex_m_vector_catch_command)
uint32_t demcr = 0;
int retval;
+ static const struct {
+ char name[10];
+ unsigned mask;
+ } vec_ids[] = {
+ { "hard_err", VC_HARDERR, },
+ { "int_err", VC_INTERR, },
+ { "bus_err", VC_BUSERR, },
+ { "state_err", VC_STATERR, },
+ { "chk_err", VC_CHKERR, },
+ { "nocp_err", VC_NOCPERR, },
+ { "mm_err", VC_MMERR, },
+ { "reset", VC_CORERESET, },
+ };
+
retval = cortex_m_verify_pointer(CMD_CTX, cortex_m);
if (retval != ERROR_OK)
return retval;
diff --git a/src/target/image.c b/src/target/image.c
index 9f56bea..0d98c57 100644
--- a/src/target/image.c
+++ b/src/target/image.c
@@ -1048,8 +1048,7 @@ int image_calculate_checksum(uint8_t *buffer, uint32_t nbytes, uint32_t *checksu
static bool first_init;
if (!first_init) {
/* Initialize the CRC table and the decoding table. */
- int i, j;
- unsigned int c;
+ unsigned int i, j, c;
for (i = 0; i < 256; i++) {
/* as per gdb */
for (c = i << 24, j = 8; j > 0; --j)
diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c
index 78718ca..20c707b 100644
--- a/src/target/mips_m4k.c
+++ b/src/target/mips_m4k.c
@@ -344,6 +344,8 @@ static int mips_m4k_assert_reset(struct target *target)
jtag_add_reset(1, 1);
else if (!srst_asserted)
jtag_add_reset(0, 1);
+ } else if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) {
+ target_handle_event(target, TARGET_EVENT_RESET_ASSERT);
} else {
if (mips_m4k->is_pic32mx) {
LOG_DEBUG("Using MTAP reset to reset processor...");
diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c
index 142b27f..db9aad3 100644
--- a/src/target/riscv/riscv-011.c
+++ b/src/target/riscv/riscv-011.c
@@ -240,6 +240,7 @@ static unsigned int slot_offset(const struct target *target, slot_t slot)
case SLOT1: return 5;
case SLOT_LAST: return info->dramsize-1;
}
+ break;
case 64:
switch (slot) {
case SLOT0: return 4;
@@ -1775,6 +1776,8 @@ static riscv_error_t handle_halt_routine(struct target *target)
break;
default:
assert(0);
+ LOG_ERROR("Got invalid register result %d", result);
+ goto error;
}
if (riscv_xlen(target) == 32) {
reg_cache_set(target, reg, data & 0xffffffff);
diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c
index beeb474..5920789 100644
--- a/src/target/semihosting_common.c
+++ b/src/target/semihosting_common.c
@@ -225,6 +225,10 @@ int semihosting_common(struct target *target)
else {
int fd = semihosting_get_field(target, 0, fields);
if (semihosting->is_fileio) {
+ if (fd == 0 || fd == 1 || fd == 2) {
+ semihosting->result = 0;
+ break;
+ }
semihosting->hit_fileio = true;
fileio_info->identifier = "close";
fileio_info->param_1 = fd;
@@ -445,8 +449,8 @@ int semihosting_common(struct target *target)
* - –1 if an error occurs.
*/
if (semihosting->is_fileio) {
- LOG_ERROR("SYS_FLEN not supported by semihosting fileio");
- return ERROR_FAIL;
+ semihosting->result = -1;
+ semihosting->sys_errno = EINVAL;
}
retval = semihosting_read_fields(target, 1, fields);
if (retval != ERROR_OK)
@@ -690,9 +694,19 @@ int semihosting_common(struct target *target)
/* TODO: implement the :semihosting-features special file.
* */
if (semihosting->is_fileio) {
- if (strcmp((char *)fn, ":tt") == 0)
- semihosting->result = 0;
- else {
+ if (strcmp((char *)fn, ":semihosting-features") == 0) {
+ semihosting->result = -1;
+ semihosting->sys_errno = EINVAL;
+ } else if (strcmp((char *)fn, ":tt") == 0) {
+ if (mode == 0)
+ semihosting->result = 0;
+ else if (mode == 4)
+ semihosting->result = 1;
+ else if (mode == 8)
+ semihosting->result = 2;
+ else
+ semihosting->result = -1;
+ } else {
semihosting->hit_fileio = true;
fileio_info->identifier = "open";
fileio_info->param_1 = addr;
@@ -1397,8 +1411,9 @@ static int semihosting_read_fields(struct target *target, size_t number,
uint8_t *fields)
{
struct semihosting *semihosting = target->semihosting;
- return target_read_memory(target, semihosting->param,
- semihosting->word_size_bytes, number, fields);
+ /* Use 4-byte multiples to trigger fast memory access. */
+ return target_read_memory(target, semihosting->param, 4,
+ number * (semihosting->word_size_bytes / 4), fields);
}
/**
@@ -1408,8 +1423,9 @@ static int semihosting_write_fields(struct target *target, size_t number,
uint8_t *fields)
{
struct semihosting *semihosting = target->semihosting;
- return target_write_memory(target, semihosting->param,
- semihosting->word_size_bytes, number, fields);
+ /* Use 4-byte multiples to trigger fast memory access. */
+ return target_write_memory(target, semihosting->param, 4,
+ number * (semihosting->word_size_bytes / 4), fields);
}
/**
diff --git a/src/target/target.c b/src/target/target.c
index dc2cedd..8240e65 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -4146,8 +4146,9 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
* argv[3] = memory address
* argv[4] = count of times to read
*/
+
if (argc < 4 || argc > 5) {
- Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems [phys]");
+ Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]");
return JIM_ERR;
}
varname = Jim_GetString(argv[0], &len);
@@ -6430,7 +6431,7 @@ static const struct command_registration target_exec_command_handlers[] = {
.handler = handle_bp_command,
.mode = COMMAND_EXEC,
.help = "list or set hardware or software breakpoint",
- .usage = "<address> [<asid>]<length> ['hw'|'hw_ctx']",
+ .usage = "<address> [<asid>] <length> ['hw'|'hw_ctx']",
},
{
.name = "rbp",