diff --git a/.travis.yml b/.travis.yml index 35bf8c435..37a599339 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,6 +30,7 @@ matrix: env: - BUILD=i686-linux-gnu - CFLAGS=-m32 + - CONFIGURE_ARGS="--disable-target64" - EXECUTABLE=openocd compiler: clang addons: diff --git a/HACKING b/HACKING index 162da8698..0bea65a75 100644 --- a/HACKING +++ b/HACKING @@ -1,13 +1,20 @@ // This file is part of the Doxygen Developer Manual /** @page patchguide Patch Guidelines -\attention If you're behind a corporate wall with http only access to the -world, you can still use these instructions! - \attention You can't send patches to the mailing list anymore at all. Nowadays you are expected to send patches to the OpenOCD Gerrit GIT server for a review. +\attention If you already have a Gerrit account and want to try a +different sign in method, please first sign in as usually, press your +name in the upper-right corner, go to @a Settings, select @a +Identities pane, press Link Another Identity button. In case +you already have duplicated accounts, ask administrators for manual +merging. + +\attention If you're behind a corporate wall with http only access to the +world, you can still use these instructions! + @section gerrit Submitting patches to the OpenOCD Gerrit server OpenOCD is to some extent a "self service" open source project, so to diff --git a/configure.ac b/configure.ac index 562ec5a7c..f4f66ab43 100644 --- a/configure.ac +++ b/configure.ac @@ -114,6 +114,7 @@ m4_define([USB1_ADAPTERS], [[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]], [[ulink], [Keil ULINK JTAG Programmer], [ULINK]], [[usb_blaster_2], [Altera USB-Blaster II Compatible], [USB_BLASTER_2]], + [[ft232r], [Bitbang mode of FT232R based devices], [FT232R]], [[vsllink], [Versaloon-Link JTAG Programmer], [VSLLINK]]]) m4_define([USB_ADAPTERS], diff --git a/contrib/loaders/flash/bluenrg-x/Makefile b/contrib/loaders/flash/bluenrg-x/Makefile new file mode 100644 index 000000000..1a5cfc013 --- /dev/null +++ b/contrib/loaders/flash/bluenrg-x/Makefile @@ -0,0 +1,27 @@ +BIN2C = ../../../../src/helper/bin2char.sh + +CROSS_COMPILE ?= arm-none-eabi- + +CC=$(CROSS_COMPILE)gcc +OBJCOPY=$(CROSS_COMPILE)objcopy +OBJDUMP=$(CROSS_COMPILE)objdump + +CFLAGS = -c -mthumb -mcpu=cortex-m0 -O3 -g + +all: bluenrg-x_write.inc + +.PHONY: clean + +.INTERMEDIATE: bluenrg-x_write.o + +%.o: %.c + $(CC) $(CFLAGS) -Wall -Wextra -Wa,-adhln=$*.lst $< -o $@ + +%.bin: %.o + $(OBJCOPY) -Obinary $< $@ + +%.inc: %.bin + $(BIN2C) < $< > $@ + +clean: + -rm -f *.o *.lst *.bin *.inc diff --git a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c new file mode 100644 index 000000000..3dd17b2fc --- /dev/null +++ b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c @@ -0,0 +1,132 @@ +/* To be built with arm-none-eabi-gcc -c -mthumb -mcpu=cortex-m0 -O3 bluenrgx.c */ +/* Then postprocess output of command "arm-none-eabi-objdump -d bluenrgx.o" to make a C array of bytes */ + +#include + +/* Status Values ----------------------------------------------------------*/ +#define SUCCESS 0 +#define ERR_UNALIGNED 1 +#define ERR_INVALID_ADDRESS 2 +#define ERR_INVALID_TYPE 3 +#define ERR_WRITE_PROTECTED 4 +#define ERR_WRITE_FAILED 5 +#define ERR_ERASE_REQUIRED 6 +#define ERR_VERIFY_FAILED 7 + +/* Flash Controller defines ---------------------------------------------------*/ +#define FLASH_REG_COMMAND ((volatile uint32_t *)0x40100000) +#define FLASH_REG_CONFIG ((volatile uint32_t *)0x40100004) +#define FLASH_REG_IRQSTAT ((volatile uint32_t *)0x40100008) +#define FLASH_REG_IRQMASK ((volatile uint32_t *)0x4010000C) +#define FLASH_REG_IRQRAW ((volatile uint32_t *)0x40100010) +#define FLASH_REG_ADDRESS ((volatile uint32_t *)0x40100018) +#define FLASH_REG_UNLOCKM ((volatile uint32_t *)0x4010001C) +#define FLASH_REG_UNLOCKL ((volatile uint32_t *)0x40100020) +#define FLASH_REG_DATA0 ((volatile uint32_t *)0x40100040) +#define FLASH_REG_DATA1 ((volatile uint32_t *)0x40100044) +#define FLASH_REG_DATA2 ((volatile uint32_t *)0x40100048) +#define FLASH_REG_DATA3 ((volatile uint32_t *)0x4010004C) +#define FLASH_SIZE_REG 0x40100014 + +#define MFB_MASS_ERASE 0x01 +#define MFB_PAGE_ERASE 0x02 + +#define DO_ERASE 0x0100 +#define DO_VERIFY 0x0200 +#define FLASH_CMD_ERASE_PAGE 0x11 +#define FLASH_CMD_MASSERASE 0x22 +#define FLASH_CMD_WRITE 0x33 +#define FLASH_CMD_BURSTWRITE 0xCC +#define FLASH_INT_CMDDONE 0x01 +#define MFB_BOTTOM (0x10040000) +#define MFB_SIZE_B ((16 * (((*(uint32_t *) FLASH_SIZE_REG) + 1) >> 12)) * 1024) +#define MFB_SIZE_W (MFB_SIZE_B/4) +#define MFB_TOP (MFB_BOTTOM+MFB_SIZE_B-1) +#define MFB_PAGE_SIZE_B (2048) +#define MFB_PAGE_SIZE_W (MFB_PAGE_SIZE_B/4) + +#define AREA_ERROR 0x01 +#define AREA_MFB 0x04 + +#define FLASH_WORD_LEN 4 + +typedef struct { + volatile uint8_t *wp; + uint8_t *rp; +} work_area_t; + +/* Flash Commands --------------------------------------------------------*/ +static inline __attribute__((always_inline)) uint32_t flashWrite(uint32_t address, uint8_t **data, + uint32_t writeLength) +{ + uint32_t index, flash_word[4]; + uint8_t i; + + *FLASH_REG_IRQMASK = 0; + for (index = 0; index < writeLength; index += (FLASH_WORD_LEN*4)) { + for (i = 0; i < 4; i++) + flash_word[i] = (*(uint32_t *) (*data + i*4)); + + /* Clear the IRQ flags */ + *FLASH_REG_IRQRAW = 0x0000003F; + /* Load the flash address to write */ + *FLASH_REG_ADDRESS = (uint16_t)((address + index) >> 2); + /* Prepare and load the data to flash */ + *FLASH_REG_DATA0 = flash_word[0]; + *FLASH_REG_DATA1 = flash_word[1]; + *FLASH_REG_DATA2 = flash_word[2]; + *FLASH_REG_DATA3 = flash_word[3]; + /* Flash write command */ + *FLASH_REG_COMMAND = FLASH_CMD_BURSTWRITE; + /* Wait the end of the flash write command */ + while ((*FLASH_REG_IRQRAW & FLASH_INT_CMDDONE) == 0) + ; + *data += (FLASH_WORD_LEN * 4); + } + + return SUCCESS; +} + +__attribute__((naked)) __attribute__((noreturn)) void write(uint8_t *work_area_p, + uint8_t *fifo_end, + uint8_t *target_address, + uint32_t count) +{ + uint32_t retval; + volatile work_area_t *work_area = (work_area_t *) work_area_p; + uint8_t *fifo_start = (uint8_t *) work_area->rp; + + while (count) { + volatile int32_t fifo_linear_size; + + /* Wait for some data in the FIFO */ + while (work_area->rp == work_area->wp) + ; + if (work_area->wp == 0) { + /* Aborted by other party */ + break; + } + if (work_area->rp > work_area->wp) { + fifo_linear_size = fifo_end-work_area->rp; + } else { + fifo_linear_size = (work_area->wp - work_area->rp); + if (fifo_linear_size < 0) + fifo_linear_size = 0; + } + if (fifo_linear_size < 16) { + /* We should never get here */ + continue; + } + + retval = flashWrite((uint32_t) target_address, (uint8_t **) &work_area->rp, fifo_linear_size); + if (retval != SUCCESS) { + work_area->rp = (uint8_t *)retval; + break; + } + target_address += fifo_linear_size; + if (work_area->rp >= fifo_end) + work_area->rp = fifo_start; + count -= fifo_linear_size; + } + __asm("bkpt 0"); +} diff --git a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc new file mode 100644 index 000000000..47f331228 --- /dev/null +++ b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc @@ -0,0 +1,18 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x05,0x93,0x43,0x68,0x05,0x00,0x07,0x93,0x05,0x9b,0x06,0x91,0x03,0x92,0x35,0x4c, +0x00,0x2b,0x5c,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0xfb,0xd0,0x2b,0x68,0x00,0x2b, +0x55,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0x52,0xd9,0x6b,0x68,0x06,0x9a,0xd3,0x1a, +0x09,0x93,0x09,0x9b,0x0f,0x2b,0xed,0xdd,0x00,0x21,0x09,0x9b,0x04,0x93,0x1a,0x1e, +0x29,0x4b,0x19,0x60,0x32,0xd0,0x29,0x4b,0x00,0x20,0x98,0x46,0x28,0x4b,0x6a,0x68, +0x9c,0x46,0x28,0x4b,0x28,0x4e,0x9b,0x46,0x28,0x4b,0x9a,0x46,0x28,0x4b,0x99,0x46, +0x01,0x23,0x51,0x68,0x17,0x68,0x00,0x91,0x91,0x68,0x01,0x91,0xd1,0x68,0x02,0x91, +0x3f,0x21,0x21,0x60,0x03,0x99,0x09,0x18,0x89,0x03,0x09,0x0c,0x31,0x60,0x41,0x46, +0x0f,0x60,0x67,0x46,0x00,0x99,0x39,0x60,0x5f,0x46,0x01,0x99,0x39,0x60,0x57,0x46, +0x02,0x99,0x39,0x60,0x49,0x46,0xcc,0x27,0x0f,0x60,0x21,0x68,0x0b,0x42,0xfc,0xd0, +0x04,0x99,0x10,0x32,0x10,0x30,0x6a,0x60,0x81,0x42,0xda,0xd8,0x03,0x9a,0x09,0x9b, +0x94,0x46,0x9c,0x44,0x63,0x46,0x06,0x9a,0x03,0x93,0x6b,0x68,0x9a,0x42,0x01,0xd8, +0x07,0x9b,0x6b,0x60,0x05,0x9a,0x09,0x9b,0xd3,0x1a,0x05,0x93,0xa2,0xd1,0x00,0xbe, +0x2b,0x68,0x6a,0x68,0x9b,0x1a,0x09,0x93,0x09,0x9b,0x00,0x2b,0xa9,0xda,0x00,0x23, +0x09,0x93,0xa6,0xe7,0x10,0x00,0x10,0x40,0x0c,0x00,0x10,0x40,0x40,0x00,0x10,0x40, +0x44,0x00,0x10,0x40,0x48,0x00,0x10,0x40,0x18,0x00,0x10,0x40,0x4c,0x00,0x10,0x40, +0x00,0x00,0x10,0x40, diff --git a/doc/openocd.texi b/doc/openocd.texi index 898ffb948..3069b37a4 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -1595,8 +1595,11 @@ proc enable_fast_clock @{@} @{ proc init_board @{@} @{ reset_config trst_and_srst trst_pulls_srst + $_TARGETNAME configure -event reset-start @{ + adapter_khz 100 + @} + $_TARGETNAME configure -event reset-init @{ - adapter_khz 1 enable_fast_clock adapter_khz 10000 @} @@ -2197,6 +2200,13 @@ The default behaviour is @option{disable}; use @option{enable} see these errors reported. @end deffn +@deffn {Config Command} gdb_report_register_access_error (@option{enable}|@option{disable}) +Specifies whether register accesses requested by GDB register read/write +packets report errors or not. +The default behaviour is @option{disable}; +use @option{enable} see these errors reported. +@end deffn + @deffn {Config Command} gdb_target_description (@option{enable}|@option{disable}) Set to @option{enable} to cause OpenOCD to send the target descriptions to gdb via qXfer:features:read packet. The default behaviour is @option{enable}. @@ -2556,6 +2566,36 @@ For example adapter definitions, see the configuration files shipped in the @end deffn +@deffn {Interface Driver} {ft232r} +This driver is implementing synchronous bitbang mode of an FTDI FT232R +USB UART bridge IC. + +List of connections (pin numbers for SSOP): +@itemize @minus +@item RXD(5) - TDI +@item TXD(1) - TCK +@item RTS(3) - TDO +@item CTS(11) - TMS +@item DTR(2) - TRST +@item DCD(10) - SRST +@end itemize + +These interfaces have several commands, used to configure the driver +before initializing the JTAG scan chain: + +@deffn {Config Command} {ft232r_vid_pid} @var{vid} @var{pid} +The vendor ID and product ID of the adapter. If not specified, default +0x0403:0x6001 is used. +@end deffn + +@deffn {Config Command} {ft232r_serial_desc} @var{serial} +Specifies the @var{serial} of the adapter to use, in case the +vendor provides unique IDs and more than one adapter is connected to +the host. If not specified, serial numbers are not considered. +@end deffn + +@end deffn + @deffn {Interface Driver} {remote_bitbang} Drive JTAG from a remote process. This sets up a UNIX or TCP socket connection with a remote process and sends ASCII encoded bitbang requests to that process @@ -3969,6 +4009,84 @@ with these TAPs, any targets associated with them, and any on-chip resources; then a @file{board.cfg} with off-chip resources, clocking, and so forth. +@anchor{dapdeclaration} +@section DAP declaration (ARMv7 and ARMv8 targets) +@cindex DAP declaration + +Since OpenOCD version 0.11.0, the Debug Access Port (DAP) is +no longer implicitly created together with the target. It must be +explicitly declared using the @command{dap create} command. For all +ARMv7 and ARMv8 targets, the option "@option{-dap} @var{dap_name}" has to be used +instead of "@option{-chain-position} @var{dotted.name}" when the target is created. + +The @command{dap} command group supports the following sub-commands: + +@deffn Command {dap create} dap_name @option{-chain-position} dotted.name +Declare a DAP instance named @var{dap_name} linked to the JTAG tap +@var{dotted.name}. This also creates a new command (@command{dap_name}) +which is used for various purposes including additional configuration. +There can only be one DAP for each JTAG tap in the system. +@end deffn + +@deffn Command {dap names} +This command returns a list of all registered DAP objects. It it useful mainly +for TCL scripting. +@end deffn + +@deffn Command {dap info} [num] +Displays the ROM table for MEM-AP @var{num}, +defaulting to the currently selected AP of the currently selected target. +@end deffn + +@deffn Command {dap init} +Initialize all registered DAPs. This command is used internally +during initialization. It can be issued at any time after the +initialization, too. +@end deffn + +The following commands exist as subcommands of DAP instances: + +@deffn Command {$dap_name info} [num] +Displays the ROM table for MEM-AP @var{num}, +defaulting to the currently selected AP. +@end deffn + +@deffn Command {$dap_name apid} [num] +Displays ID register from AP @var{num}, defaulting to the currently selected AP. +@end deffn + +@deffn Command {$dap_name apreg} ap_num reg [value] +Displays content of a register @var{reg} from AP @var{ap_num} +or set a new value @var{value}. +@var{reg} is byte address of a word register, 0, 4, 8 ... 0xfc. +@end deffn + +@deffn Command {$dap_name apsel} [num] +Select AP @var{num}, defaulting to 0. +@end deffn + +@deffn Command {$dap_name baseaddr} [num] +Displays debug base address from MEM-AP @var{num}, +defaulting to the currently selected AP. +@end deffn + +@deffn Command {$dap_name memaccess} [value] +Displays the number of extra tck cycles in the JTAG idle to use for MEM-AP +memory bus access [0-255], giving additional time to respond to reads. +If @var{value} is defined, first assigns that. +@end deffn + +@deffn Command {$dap_name apcsw} [0 / 1] +fix CSW_SPROT from register AP_REG_CSW on selected dap. +Defaulting to 0. +@end deffn + +@deffn Command {$dap_name ti_be_32_quirks} [@option{enable}] +Set/get quirks mode for TI TMS450/TMS570 processors +Disabled by default +@end deffn + + @node CPU Configuration @chapter CPU Configuration @cindex GDB target @@ -4135,10 +4253,11 @@ to be much more board-specific. The key steps you use might look something like this @example -target create MyTarget cortex_m -chain-position mychip.cpu -$MyTarget configure -work-area-phys 0x08000 -work-area-size 8096 -$MyTarget configure -event reset-deassert-pre @{ jtag_rclk 5 @} -$MyTarget configure -event reset-init @{ myboard_reinit @} +dap create mychip.dap -chain-position mychip.cpu +target create MyTarget cortex_m -dap mychip.dap +MyTarget configure -work-area-phys 0x08000 -work-area-size 8096 +MyTarget configure -event reset-deassert-pre @{ jtag_rclk 5 @} +MyTarget configure -event reset-init @{ myboard_reinit @} @end example You should specify a working area if you can; typically it uses some @@ -4188,7 +4307,8 @@ and in other places the target needs to be identified. @command{$target_name configure} are permitted. If the target is big-endian, set it here with @code{-endian big}. -You @emph{must} set the @code{-chain-position @var{dotted.name}} here. +You @emph{must} set the @code{-chain-position @var{dotted.name}} or +@code{-dap @var{dap_name}} here. @end itemize @end deffn @@ -4207,6 +4327,10 @@ and changing its endianness. @item @code{-chain-position} @var{dotted.name} -- names the TAP used to access this target. +@item @code{-dap} @var{dap_name} -- names the DAP used to access +this target. @xref{dapdeclaration,,DAP declaration}, on how to +create and manage DAP instances. + @item @code{-endian} (@option{big}|@option{little}) -- specifies whether the CPU uses big or little endian conventions @@ -4217,6 +4341,9 @@ Calling this twice with two different event names assigns two different handlers, but calling it twice with the same event name assigns only one handler. +Current target is temporarily overridden to the event issuing target +before handler code starts and switched back after handler is done. + @item @code{-work-area-backup} (@option{0}|@option{1}) -- says whether the work area gets backed up; by default, @emph{it is not backed up.} @@ -4254,9 +4381,11 @@ access the target for debugging. Use this option with systems where multiple, independent cores are connected to separate access ports of the same DAP. -@item @code{-ctibase} @var{address} -- set base address of Cross-Trigger interface (CTI) connected -to the target. Currently, only the @code{aarch64} target makes use of this option, where it is -a mandatory configuration for the target run control. +@item @code{-cti} @var{cti_name} -- set Cross-Trigger Interface (CTI) connected +to the target. Currently, only the @code{aarch64} target makes use of this option, +where it is a mandatory configuration for the target run control. +@xref{armcrosstrigger,,ARM Cross-Trigger Interface}, +for instruction on how to declare and control a CTI instance. @end itemize @end deffn @@ -4427,16 +4556,14 @@ buttons and events. The two examples below act the same, but one creates and invokes a small procedure while the other inlines it. @example -proc my_attach_proc @{ @} @{ - echo "Reset..." - reset halt +proc my_init_proc @{ @} @{ + echo "Disabling watchdog..." + mww 0xfffffd44 0x00008000 @} -mychip.cpu configure -event gdb-attach my_attach_proc -mychip.cpu configure -event gdb-attach @{ - echo "Reset..." - # To make flash probe and gdb load to flash work - # we need a reset init. - reset init +mychip.cpu configure -event reset-init my_init_proc +mychip.cpu configure -event reset-init @{ + echo "Disabling watchdog..." + mww 0xfffffd44 0x00008000 @} @end example @@ -4446,7 +4573,7 @@ The following target events are defined: @item @b{debug-halted} @* The target has halted for debug reasons (i.e.: breakpoint) @item @b{debug-resumed} -@* The target has resumed (i.e.: gdb said run) +@* The target has resumed (i.e.: GDB said run) @item @b{early-halted} @* Occurs early in the halt process @item @b{examine-start} @@ -4454,11 +4581,17 @@ The following target events are defined: @item @b{examine-end} @* After target examine is called with no errors. @item @b{gdb-attach} -@* When GDB connects. This is before any communication with the target, so this -can be used to set up the target so it is possible to probe flash. Probing flash -is necessary during gdb connect if gdb load is to write the image to flash. Another -use of the flash memory map is for GDB to automatically hardware/software breakpoints -depending on whether the breakpoint is in RAM or read only memory. +@* When GDB connects. Issued before any GDB communication with the target +starts. GDB expects the target is halted during attachment. +@xref{gdbmeminspect,,GDB as a non-intrusive memory inspector}, how to +connect GDB to running target. +The event can be also used to set up the target so it is possible to probe flash. +Probing flash is necessary during GDB connect if you want to use +@pxref{programmingusinggdb,,programming using GDB}. +Another use of the flash memory map is for GDB to automatically choose +hardware or software breakpoints depending on whether the breakpoint +is in RAM or read only memory. +Default is @code{halt} @item @b{gdb-detach} @* When GDB disconnects @item @b{gdb-end} @@ -4473,13 +4606,13 @@ depending on whether the breakpoint is in RAM or read only memory. @item @b{gdb-flash-write-end} @* After GDB writes to the flash (default is @code{reset halt}) @item @b{gdb-start} -@* Before the target steps, gdb is trying to start/resume the target +@* Before the target steps, GDB is trying to start/resume the target @item @b{halted} @* The target has halted @item @b{reset-assert-pre} @* Issued as part of @command{reset} processing -after @command{reset_init} was triggered -but before either SRST alone is re-asserted on the scan chain, +after @command{reset-start} was triggered +but before either SRST alone is asserted on the scan chain, or @code{reset-assert} is triggered. @item @b{reset-assert} @* Issued as part of @command{reset} processing @@ -4513,8 +4646,8 @@ multiplexing, and so on. (You may be able to switch to a fast JTAG clock rate here, after the target clocks are fully set up.) @item @b{reset-start} -@* Issued as part of @command{reset} processing -before @command{reset_init} is called. +@* Issued as the first step in @command{reset} processing +before @command{reset-assert-pre} is called. This is the most robust place to use @command{jtag_rclk} or @command{adapter_khz} to switch to a low JTAG clock rate, @@ -5193,6 +5326,26 @@ and prepares reset vector catch in case of reset halt. Command is used internally in event event reset-deassert-post. @end deffn +@deffn Command {at91samd nvmuserrow} +Writes or reads the entire 64 bit wide NVM user row register which is located at +0x804000. This register includes various fuses lock-bits and factory calibration +data. Reading the register is done by invoking this command without any +arguments. Writing is possible by giving 1 or 2 hex values. The first argument +is the register value to be written and the second one is an optional changemask. +Every bit which value in changemask is 0 will stay unchanged. The lock- and +reserved-bits are masked out and cannot be changed. + +@example +# Read user row +>at91samd nvmuserrow +NVMUSERROW: 0xFFFFFC5DD8E0C788 +# Write 0xFFFFFC5DD8E0C788 to user row +>at91samd nvmuserrow 0xFFFFFC5DD8E0C788 +# Write 0x12300 to user row but leave other bits and low byte unchanged +>at91samd nvmuserrow 0x12345 0xFFF00 +@end example +@end deffn + @end deffn @anchor{at91sam3} @@ -5341,6 +5494,30 @@ The AVR 8-bit microcontrollers from Atmel integrate flash memory. @comment - defines mass_erase ... pointless given flash_erase_address @end deffn +@deffn {Flash Driver} bluenrg-x +STMicroelectronics BlueNRG-1 and BlueNRG-2 Bluetooth low energy wireless system-on-chip. They include ARM Cortex-M0 core and internal flash memory. +The driver automatically recognizes these chips using +the chip identification registers, and autoconfigures itself. + +@example +flash bank $_FLASHNAME bluenrg-x 0 0 0 0 $_TARGETNAME +@end example + +Note that when users ask to erase all the sectors of the flash, a mass erase command is used which is faster than erasing +each single sector one by one. + +@example +flash erase_sector 0 0 79 # It will perform a mass erase on BlueNRG-1 +@end example + +@example +flash erase_sector 0 0 127 # It will perform a mass erase on BlueNRG-2 +@end example + +Triggering a mass erase is also useful when users want to disable readout protection. + +@end deffn + @deffn {Flash Driver} efm32 All members of the EFM32 microcontroller family from Energy Micro include internal flash and use ARM Cortex-M3 cores. The driver automatically recognizes @@ -5891,6 +6068,62 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @end deffn +@deffn {Flash Driver} psoc6 +Supports PSoC6 (CY8C6xxx) family of Cypress microcontrollers. +PSoC6 is a dual-core device with CM0+ and CM4 cores. Both cores share +the same Flash/RAM/MMIO address space. + +Flash in PSoC6 is split into three regions: +@itemize @bullet +@item Main Flash - this is the main storage for user application. +Total size varies among devices, sector size: 256 kBytes, row size: +512 bytes. Supports erase operation on individual rows. +@item Work Flash - intended to be used as storage for user data +(e.g. EEPROM emulation). Total size: 32 KBytes, sector size: 32 KBytes, +row size: 512 bytes. +@item Supervisory Flash - special region which contains device-specific +service data. This region does not support erase operation. Only few rows can +be programmed by the user, most of the rows are read only. Programming +operation will erase row automatically. +@end itemize + +All three flash regions are supported by the driver. Flash geometry is detected +automatically by parsing data in SPCIF_GEOMETRY register. + +PSoC6 is equipped with NOR Flash so erased Flash reads as 0x00. + +@example +flash bank main_flash_cm0 psoc6 0x10000000 0 0 0 $@{TARGET@}.cm0 +flash bank work_flash_cm0 psoc6 0x14000000 0 0 0 $@{TARGET@}.cm0 +flash bank super_flash_user_cm0 psoc6 0x16000800 0 0 0 $@{TARGET@}.cm0 +flash bank super_flash_nar_cm0 psoc6 0x16001A00 0 0 0 $@{TARGET@}.cm0 +flash bank super_flash_key_cm0 psoc6 0x16005A00 0 0 0 $@{TARGET@}.cm0 +flash bank super_flash_toc2_cm0 psoc6 0x16007C00 0 0 0 $@{TARGET@}.cm0 + +flash bank main_flash_cm4 psoc6 0x10000000 0 0 0 $@{TARGET@}.cm4 +flash bank work_flash_cm4 psoc6 0x14000000 0 0 0 $@{TARGET@}.cm4 +flash bank super_flash_user_cm4 psoc6 0x16000800 0 0 0 $@{TARGET@}.cm4 +flash bank super_flash_nar_cm4 psoc6 0x16001A00 0 0 0 $@{TARGET@}.cm4 +flash bank super_flash_key_cm4 psoc6 0x16005A00 0 0 0 $@{TARGET@}.cm4 +flash bank super_flash_toc2_cm4 psoc6 0x16007C00 0 0 0 $@{TARGET@}.cm4 +@end example + +psoc6-specific commands +@deffn Command {psoc6 reset_halt} +Command can be used to simulate broken Vector Catch from gdbinit or tcl scripts. +When invoked for CM0+ target, it will set break point at application entry point +and issue SYSRESETREQ. This will reset both cores and all peripherals. CM0+ will +reset CM4 during boot anyway so this is safe. On CM4 target, VECTRESET is used +instead of SYSRESETREQ to avoid unwanted reset of CM0+; +@end deffn + +@deffn Command {psoc6 mass_erase} num +Erases the contents given flash bank. The @var{num} parameter is a value shown +by @command{flash banks}. +Note: only Main and Work flash regions support Erase operation. +@end deffn +@end deffn + @deffn {Flash Driver} sim3x All members of the SiM3 microcontroller family from Silicon Laboratories include internal flash and use ARM Cortex-M3 cores. It supports both JTAG @@ -7012,9 +7245,11 @@ the initial log output channel is stderr. Add @var{directory} to the file/script search path. @end deffn -@deffn Command bindto [name] -Specify address by name on which to listen for incoming TCP/IP connections. -By default, OpenOCD will listen on all available interfaces. +@deffn Command bindto [@var{name}] +Specify hostname or IPv4 address on which to listen for incoming +TCP/IP connections. By default, OpenOCD will listen on the loopback +interface only. If your network environment is safe, @code{bindto +0.0.0.0} can be used to cover all available interfaces. @end deffn @anchor{targetstatehandling} @@ -7659,6 +7894,50 @@ Reports whether the capture clock is locked or not. @end deffn @end deffn +@anchor{armcrosstrigger} +@section ARM Cross-Trigger Interface +@cindex CTI + +The ARM Cross-Trigger Interface (CTI) is a generic CoreSight component +that connects event sources like tracing components or CPU cores with each +other through a common trigger matrix (CTM). For ARMv8 architecture, a +CTI is mandatory for core run control and each core has an individual +CTI instance attached to it. OpenOCD has limited support for CTI using +the @emph{cti} group of commands. + +@deffn Command {cti create} cti_name @option{-dap} dap_name @option{-ap-num} apn @option{-ctibase} base_address +Creates a CTI instance @var{cti_name} on the DAP instance @var{dap_name} on MEM-AP +@var{apn}. The @var{base_address} must match the base address of the CTI +on the respective MEM-AP. All arguments are mandatory. This creates a +new command @command{$cti_name} which is used for various purposes +including additional configuration. +@end deffn + +@deffn Command {$cti_name enable} @option{on|off} +Enable (@option{on}) or disable (@option{off}) the CTI. +@end deffn + +@deffn Command {$cti_name dump} +Displays a register dump of the CTI. +@end deffn + +@deffn Command {$cti_name write } @var{reg_name} @var{value} +Write @var{value} to the CTI register with the symbolic name @var{reg_name}. +@end deffn + +@deffn Command {$cti_name read} @var{reg_name} +Print the value read from the CTI register with the symbolic name @var{reg_name}. +@end deffn + +@deffn Command {$cti_name testmode} @option{on|off} +Enable (@option{on}) or disable (@option{off}) the integration test mode +of the CTI. +@end deffn + +@deffn Command {cti names} +Prints a list of names of all CTI objects created. This command is mainly +useful in TCL scripting. +@end deffn @section Generic ARM @cindex ARM @@ -8138,55 +8417,6 @@ cores @emph{except the ARM1176} use the same six bits. @cindex ARMv7 @cindex ARMv8 -@subsection ARMv7 and ARMv8 Debug Access Port (DAP) specific commands -@cindex Debug Access Port -@cindex DAP -These commands are specific to ARM architecture v7 and v8 Debug Access Port (DAP), -included on Cortex-M and Cortex-A systems. -They are available in addition to other core-specific commands that may be available. - -@deffn Command {dap apid} [num] -Displays ID register from AP @var{num}, -defaulting to the currently selected AP. -@end deffn - -@deffn Command {dap apreg} ap_num reg [value] -Displays content of a register @var{reg} from AP @var{ap_num} -or set a new value @var{value}. -@var{reg} is byte address of a word register, 0, 4, 8 ... 0xfc. -@end deffn - -@deffn Command {dap apsel} [num] -Select AP @var{num}, defaulting to 0. -@end deffn - -@deffn Command {dap baseaddr} [num] -Displays debug base address from MEM-AP @var{num}, -defaulting to the currently selected AP. -@end deffn - -@deffn Command {dap info} [num] -Displays the ROM table for MEM-AP @var{num}, -defaulting to the currently selected AP. -@end deffn - -@deffn Command {dap memaccess} [value] -Displays the number of extra tck cycles in the JTAG idle to use for MEM-AP -memory bus access [0-255], giving additional time to respond to reads. -If @var{value} is defined, first assigns that. -@end deffn - -@deffn Command {dap apcsw} [0 / 1] -fix CSW_SPROT from register AP_REG_CSW on selected dap. -Defaulting to 0. -@end deffn - -@deffn Command {dap ti_be_32_quirks} [@option{enable}] -Set/get quirks mode for TI TMS450/TMS570 processors -Disabled by default -@end deffn - - @subsection ARMv7-A specific commands @cindex Cortex-A @@ -9095,19 +9325,6 @@ With that particular hardware (Cortex-M3) the hardware breakpoints only work for code running from flash memory. Most other ARM systems do not have such restrictions. -Another example of useful GDB configuration came from a user who -found that single stepping his Cortex-M3 didn't work well with IRQs -and an RTOS until he told GDB to disable the IRQs while stepping: - -@example -define hook-step -mon cortex_m maskisr on -end -define hookpost-step -mon cortex_m maskisr off -end -@end example - Rather than typing such commands interactively, you may prefer to save them in a file and have GDB execute them as it starts, perhaps using a @file{.gdbinit} in your project directory or starting GDB @@ -9147,14 +9364,60 @@ GDB will look at the target memory map when a load command is given, if any areas to be programmed lie within the target flash area the vFlash packets will be used. -If the target needs configuring before GDB programming, an event -script can be executed: +If the target needs configuring before GDB programming, set target +event gdb-flash-erase-start: @example -$_TARGETNAME configure -event EVENTNAME BODY +$_TARGETNAME configure -event gdb-flash-erase-start BODY @end example +@xref{targetevents,,Target Events}, for other GDB programming related events. To verify any flash programming the GDB command @option{compare-sections} can be used. + +@section Using GDB as a non-intrusive memory inspector +@cindex Using GDB as a non-intrusive memory inspector +@anchor{gdbmeminspect} + +If your project controls more than a blinking LED, let's say a heavy industrial +robot or an experimental nuclear reactor, stopping the controlling process +just because you want to attach GDB is not a good option. + +OpenOCD does not support GDB non-stop mode (might be implemented in the future). +Though there is a possible setup where the target does not get stopped +and GDB treats it as it were running. +If the target supports background access to memory while it is running, +you can use GDB in this mode to inspect memory (mainly global variables) +without any intrusion of the target process. + +Remove default setting of gdb-attach event. @xref{targetevents,,Target Events}. +Place following command after target configuration: +@example +$_TARGETNAME configure -event gdb-attach @{@} +@end example + +If any of installed flash banks does not support probe on running target, +switch off gdb_memory_map: +@example +gdb_memory_map disable +@end example + +Ensure GDB is configured without interrupt-on-connect. +Some GDB versions set it by default, some does not. +@example +set remote interrupt-on-connect off +@end example + +If you switched gdb_memory_map off, you may want to setup GDB memory map +manually or issue @command{set mem inaccessible-by-default off} + +Now you can issue GDB command @command{target remote ...} and inspect memory +of a running target. Do not use GDB commands @command{continue}, +@command{step} or @command{next} as they synchronize GDB with your target +and GDB would require stopping the target to get the prompt back. + +Do not use this mode under an IDE like Eclipse as it caches values of +previously shown varibles. + @anchor{usingopenocdsmpwithgdb} @section Using OpenOCD SMP with GDB @cindex SMP diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index cc72088b4..712141205 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -18,6 +18,7 @@ NOR_DRIVERS = \ %D%/ath79.c \ %D%/atsamv.c \ %D%/avrf.c \ + %D%/bluenrg-x.c \ %D%/cfi.c \ %D%/dsp5680xx_flash.c \ %D%/efm32.c \ @@ -42,6 +43,7 @@ NOR_DRIVERS = \ %D%/ocl.c \ %D%/pic32mx.c \ %D%/psoc4.c \ + %D%/psoc6.c \ %D%/sim3x.c \ %D%/spi.c \ %D%/stmsmi.c \ diff --git a/src/flash/nor/ambiqmicro.c b/src/flash/nor/ambiqmicro.c index b2c30e6f4..13b2b26ae 100644 --- a/src/flash/nor/ambiqmicro.c +++ b/src/flash/nor/ambiqmicro.c @@ -901,4 +901,5 @@ struct flash_driver ambiqmicro_flash = { .erase_check = default_flash_blank_check, .protect_check = ambiqmicro_protect_check, .info = get_ambiqmicro_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index ad88c5143..64716d96f 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -83,6 +83,9 @@ #define SAMD_GET_SERIES(id) (((id >> 16) & 0x3F)) #define SAMD_GET_DEVSEL(id) (id & 0xFF) +/* Bits to mask out lockbits in user row */ +#define NVMUSERROW_LOCKBIT_MASK ((uint64_t)0x0000FFFFFFFFFFFF) + struct samd_part { uint8_t id; const char *name; @@ -159,23 +162,22 @@ static const struct samd_part samd21_parts[] = { { 0xC, "SAMD21E16A", 64, 8 }, { 0xD, "SAMD21E15A", 32, 4 }, { 0xE, "SAMD21E14A", 16, 2 }, - /* Below are B Variants (Table 3-7 from rev I of datasheet) */ - { 0x20, "SAMD21J16B", 64, 8 }, - { 0x21, "SAMD21J15B", 32, 4 }, - { 0x23, "SAMD21G16B", 64, 8 }, - { 0x24, "SAMD21G15B", 32, 4 }, - { 0x26, "SAMD21E16B", 64, 8 }, - { 0x27, "SAMD21E15B", 32, 4 }, -}; -/* Known SAMR21 parts. */ -static const struct samd_part samr21_parts[] = { + /* SAMR21 parts have integrated SAMD21 with a radio */ { 0x19, "SAMR21G18A", 256, 32 }, { 0x1A, "SAMR21G17A", 128, 32 }, { 0x1B, "SAMR21G16A", 64, 32 }, { 0x1C, "SAMR21E18A", 256, 32 }, { 0x1D, "SAMR21E17A", 128, 32 }, { 0x1E, "SAMR21E16A", 64, 32 }, + + /* SAMD21 B Variants (Table 3-7 from rev I of datasheet) */ + { 0x20, "SAMD21J16B", 64, 8 }, + { 0x21, "SAMD21J15B", 32, 4 }, + { 0x23, "SAMD21G16B", 64, 8 }, + { 0x24, "SAMD21G15B", 32, 4 }, + { 0x26, "SAMD21E16B", 64, 8 }, + { 0x27, "SAMD21E15B", 32, 4 }, }; /* Known SAML21 parts. */ @@ -200,6 +202,10 @@ static const struct samd_part saml21_parts[] = { { 0x1A, "SAML21E17B", 128, 16 }, { 0x1B, "SAML21E16B", 64, 8 }, { 0x1C, "SAML21E15B", 32, 4 }, + + /* SAMR30 parts have integrated SAML21 with a radio */ + { 0x1E, "SAMR30G18A", 256, 32 }, + { 0x1F, "SAMR30E18A", 256, 32 }, }; /* Known SAML22 parts. */ @@ -256,30 +262,38 @@ struct samd_family { uint8_t series; const struct samd_part *parts; size_t num_parts; + uint64_t nvm_userrow_res_mask; /* protect bits which are reserved, 0 -> protect */ }; /* Known SAMD families */ static const struct samd_family samd_families[] = { { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_20, - samd20_parts, ARRAY_SIZE(samd20_parts) }, + samd20_parts, ARRAY_SIZE(samd20_parts), + (uint64_t)0xFFFF01FFFE01FF77 }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_21, - samd21_parts, ARRAY_SIZE(samd21_parts) }, - { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_21, - samr21_parts, ARRAY_SIZE(samr21_parts) }, + samd21_parts, ARRAY_SIZE(samd21_parts), + (uint64_t)0xFFFF01FFFE01FF77 }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_09, - samd09_parts, ARRAY_SIZE(samd09_parts) }, + samd09_parts, ARRAY_SIZE(samd09_parts), + (uint64_t)0xFFFF01FFFE01FF77 }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_10, - samd10_parts, ARRAY_SIZE(samd10_parts) }, + samd10_parts, ARRAY_SIZE(samd10_parts), + (uint64_t)0xFFFF01FFFE01FF77 }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_11, - samd11_parts, ARRAY_SIZE(samd11_parts) }, + samd11_parts, ARRAY_SIZE(samd11_parts), + (uint64_t)0xFFFF01FFFE01FF77 }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_L, SAMD_SERIES_21, - saml21_parts, ARRAY_SIZE(saml21_parts) }, + saml21_parts, ARRAY_SIZE(saml21_parts), + (uint64_t)0xFFFF03FFFC01FF77 }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_L, SAMD_SERIES_22, - saml22_parts, ARRAY_SIZE(saml22_parts) }, + saml22_parts, ARRAY_SIZE(saml22_parts), + (uint64_t)0xFFFF03FFFC01FF77 }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_C, SAMD_SERIES_20, - samc20_parts, ARRAY_SIZE(samc20_parts) }, + samc20_parts, ARRAY_SIZE(samc20_parts), + (uint64_t)0xFFFF03FFFC01FF77 }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_C, SAMD_SERIES_21, - samc21_parts, ARRAY_SIZE(samc21_parts) }, + samc21_parts, ARRAY_SIZE(samc21_parts), + (uint64_t)0xFFFF03FFFC01FF77 }, }; struct samd_info { @@ -295,24 +309,42 @@ struct samd_info { static struct samd_info *samd_chips; - - -static const struct samd_part *samd_find_part(uint32_t id) +/** + * Gives the family structure to specific device id. + * @param id The id of the device. + * @return On failure NULL, otherwise a pointer to the structure. + */ +static const struct samd_family *samd_find_family(uint32_t id) { uint8_t processor = SAMD_GET_PROCESSOR(id); uint8_t family = SAMD_GET_FAMILY(id); uint8_t series = SAMD_GET_SERIES(id); - uint8_t devsel = SAMD_GET_DEVSEL(id); for (unsigned i = 0; i < ARRAY_SIZE(samd_families); i++) { if (samd_families[i].processor == processor && samd_families[i].series == series && - samd_families[i].family == family) { - for (unsigned j = 0; j < samd_families[i].num_parts; j++) { - if (samd_families[i].parts[j].id == devsel) - return &samd_families[i].parts[j]; - } - } + samd_families[i].family == family) + return &samd_families[i]; + } + + return NULL; +} + +/** + * Gives the part structure to specific device id. + * @param id The id of the device. + * @return On failure NULL, otherwise a pointer to the structure. + */ +static const struct samd_part *samd_find_part(uint32_t id) +{ + uint8_t devsel = SAMD_GET_DEVSEL(id); + const struct samd_family *family = samd_find_family(id); + if (family == NULL) + return NULL; + + for (unsigned i = 0; i < family->num_parts; i++) { + if (family->parts[i].id == devsel) + return &family->parts[i]; } return NULL; @@ -483,6 +515,12 @@ static int samd_issue_nvmctrl_command(struct target *target, uint16_t cmd) return samd_check_error(target); } +/** + * Erases a flash-row at the given address. + * @param target Pointer to the target structure. + * @param address The address of the row. + * @return On success ERROR_OK, on failure an errorcode. + */ static int samd_erase_row(struct target *target, uint32_t address) { int res; @@ -504,49 +542,62 @@ static int samd_erase_row(struct target *target, uint32_t address) return ERROR_OK; } -static bool is_user_row_reserved_bit(uint8_t bit) +/** + * Returns the bitmask of reserved bits in register. + * @param target Pointer to the target structure. + * @param mask Bitmask, 0 -> value stays untouched. + * @return On success ERROR_OK, on failure an errorcode. + */ +static int samd_get_reservedmask(struct target *target, uint64_t *mask) { - /* See Table 9-3 in the SAMD20 datasheet for more information. */ - switch (bit) { - /* Reserved bits */ - case 3: - case 7: - /* Voltage regulator internal configuration with default value of 0x70, - * may not be changed. */ - case 17 ... 24: - /* 41 is voltage regulator internal configuration and must not be - * changed. 42 through 47 are reserved. */ - case 41 ... 47: - return true; - default: - break; + int res; + /* Get the devicetype */ + uint32_t id; + res = target_read_u32(target, SAMD_DSU + SAMD_DSU_DID, &id); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read Device ID register"); + return res; } - - return false; + const struct samd_family *family; + family = samd_find_family(id); + if (family == NULL) { + LOG_ERROR("Couldn't determine device family"); + return ERROR_FAIL; + } + *mask = family->nvm_userrow_res_mask; + return ERROR_OK; } -/* Modify the contents of the User Row in Flash. These are described in Table - * 9-3 of the SAMD20 datasheet. The User Row itself has a size of one page - * and contains a combination of "fuses" and calibration data in bits 24:17. - * We therefore try not to erase the row's contents unless we absolutely have - * to and we don't permit modifying reserved bits. */ -static int samd_modify_user_row(struct target *target, uint32_t value, - uint8_t startb, uint8_t endb) +static int read_userrow(struct target *target, uint64_t *userrow) +{ + int res; + uint8_t buffer[8]; + + res = target_read_memory(target, SAMD_USER_ROW, 4, 2, buffer); + if (res != ERROR_OK) + return res; + + *userrow = target_buffer_get_u64(target, buffer); + return ERROR_OK; +} + +/** + * Modify the contents of the User Row in Flash. The User Row itself + * has a size of one page and contains a combination of "fuses" and + * calibration data. Bits which have a value of zero in the mask will + * not be changed. Up to now devices only use the first 64 bits. + * @param target Pointer to the target structure. + * @param value_input The value to write. + * @param value_mask Bitmask, 0 -> value stays untouched. + * @return On success ERROR_OK, on failure an errorcode. + */ +static int samd_modify_user_row_masked(struct target *target, + uint64_t value_input, uint64_t value_mask) { int res; uint32_t nvm_ctrlb; bool manual_wp = true; - if (is_user_row_reserved_bit(startb) || is_user_row_reserved_bit(endb)) { - LOG_ERROR("Can't modify bits in the requested range"); - return ERROR_FAIL; - } - - /* Check if we need to do manual page write commands */ - res = target_read_u32(target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLB, &nvm_ctrlb); - if (res == ERROR_OK) - manual_wp = (nvm_ctrlb & SAMD_NVM_CTRLB_MANW) != 0; - /* Retrieve the MCU's page size, in bytes. This is also the size of the * entire User Row. */ uint32_t page_size; @@ -556,44 +607,49 @@ static int samd_modify_user_row(struct target *target, uint32_t value, return res; } - /* Make sure the size is sane before we allocate. */ - assert(page_size > 0 && page_size <= SAMD_PAGE_SIZE_MAX); - - /* Make sure we're within the single page that comprises the User Row. */ - if (startb >= (page_size * 8) || endb >= (page_size * 8)) { - LOG_ERROR("Can't modify bits outside the User Row page range"); - return ERROR_FAIL; - } - - uint8_t *buf = malloc(page_size); - if (!buf) - return ERROR_FAIL; + /* Make sure the size is sane. */ + assert(page_size <= SAMD_PAGE_SIZE_MAX && + page_size >= sizeof(value_input)); + uint8_t buf[SAMD_PAGE_SIZE_MAX]; /* Read the user row (comprising one page) by words. */ res = target_read_memory(target, SAMD_USER_ROW, 4, page_size / 4, buf); if (res != ERROR_OK) - goto out_user_row; + return res; + + uint64_t value_device; + res = read_userrow(target, &value_device); + if (res != ERROR_OK) + return res; + uint64_t value_new = (value_input & value_mask) | (value_device & ~value_mask); /* We will need to erase before writing if the new value needs a '1' in any * position for which the current value had a '0'. Otherwise we can avoid * erasing. */ - uint32_t cur = buf_get_u32(buf, startb, endb - startb + 1); - if ((~cur) & value) { + if ((~value_device) & value_new) { res = samd_erase_row(target, SAMD_USER_ROW); if (res != ERROR_OK) { LOG_ERROR("Couldn't erase user row"); - goto out_user_row; + return res; } } /* Modify */ - buf_set_u32(buf, startb, endb - startb + 1, value); + target_buffer_set_u64(target, buf, value_new); /* Write the page buffer back out to the target. */ res = target_write_memory(target, SAMD_USER_ROW, 4, page_size / 4, buf); if (res != ERROR_OK) - goto out_user_row; + return res; + /* Check if we need to do manual page write commands */ + res = target_read_u32(target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLB, &nvm_ctrlb); + if (res == ERROR_OK) + manual_wp = (nvm_ctrlb & SAMD_NVM_CTRLB_MANW) != 0; + else { + LOG_ERROR("Read of NVM register CTRKB failed."); + return ERROR_FAIL; + } if (manual_wp) { /* Trigger flash write */ res = samd_issue_nvmctrl_command(target, SAMD_NVM_CMD_WAP); @@ -601,12 +657,28 @@ static int samd_modify_user_row(struct target *target, uint32_t value, res = samd_check_error(target); } -out_user_row: - free(buf); - return res; } +/** + * Modifies the user row register to the given value. + * @param target Pointer to the target structure. + * @param value The value to write. + * @param startb The bit-offset by which the given value is shifted. + * @param endb The bit-offset of the last bit in value to write. + * @return On success ERROR_OK, on failure an errorcode. + */ +static int samd_modify_user_row(struct target *target, uint64_t value, + uint8_t startb, uint8_t endb) +{ + uint64_t mask = 0; + int i; + for (i = startb ; i <= endb ; i++) + mask |= ((uint64_t)1) << i; + + return samd_modify_user_row_masked(target, value << startb, mask); +} + static int samd_protect(struct flash_bank *bank, int set, int first_prot_bl, int last_prot_bl) { int res = ERROR_OK; @@ -643,7 +715,8 @@ static int samd_protect(struct flash_bank *bank, int set, int first_prot_bl, int * corresponding to Sector 15. A '1' means unlocked and a '0' means * locked. See Table 9-3 in the SAMD20 datasheet for more details. */ - res = samd_modify_user_row(bank->target, set ? 0x0000 : 0xFFFF, + res = samd_modify_user_row(bank->target, + set ? (uint64_t)0 : (uint64_t)UINT64_MAX, 48 + first_prot_bl, 48 + last_prot_bl); if (res != ERROR_OK) LOG_WARNING("SAMD: protect settings were not made persistent!"); @@ -944,6 +1017,83 @@ COMMAND_HANDLER(samd_handle_eeprom_command) return res; } +static COMMAND_HELPER(get_u64_from_hexarg, unsigned int num, uint64_t *value) +{ + if (num >= CMD_ARGC) { + command_print(CMD_CTX, "Too few Arguments."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (strlen(CMD_ARGV[num]) >= 3 && + CMD_ARGV[num][0] == '0' && + CMD_ARGV[num][1] == 'x') { + char *check = NULL; + *value = strtoull(&(CMD_ARGV[num][2]), &check, 16); + if ((value == 0 && errno == ERANGE) || + check == NULL || *check != 0) { + command_print(CMD_CTX, "Invalid 64-bit hex value in argument %d.", + num + 1); + return ERROR_COMMAND_SYNTAX_ERROR; + } + } else { + command_print(CMD_CTX, "Argument %d needs to be a hex value.", num + 1); + return ERROR_COMMAND_SYNTAX_ERROR; + } + return ERROR_OK; +} + +COMMAND_HANDLER(samd_handle_nvmuserrow_command) +{ + int res = ERROR_OK; + struct target *target = get_current_target(CMD_CTX); + + if (target) { + if (CMD_ARGC > 2) { + command_print(CMD_CTX, "Too much Arguments given."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (CMD_ARGC > 0) { + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted."); + return ERROR_TARGET_NOT_HALTED; + } + + uint64_t mask; + res = samd_get_reservedmask(target, &mask); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't determine the mask for reserved bits."); + return ERROR_FAIL; + } + mask &= NVMUSERROW_LOCKBIT_MASK; + + uint64_t value; + res = CALL_COMMAND_HANDLER(get_u64_from_hexarg, 0, &value); + if (res != ERROR_OK) + return res; + if (CMD_ARGC == 2) { + uint64_t mask_temp; + res = CALL_COMMAND_HANDLER(get_u64_from_hexarg, 1, &mask_temp); + if (res != ERROR_OK) + return res; + mask &= mask_temp; + } + res = samd_modify_user_row_masked(target, value, mask); + if (res != ERROR_OK) + return res; + } + + /* read register */ + uint64_t value; + res = read_userrow(target, &value); + if (res == ERROR_OK) + command_print(CMD_CTX, "NVMUSERROW: 0x%016"PRIX64, value); + else + LOG_ERROR("NVMUSERROW could not be read."); + } + return res; +} + COMMAND_HANDLER(samd_handle_bootloader_command) { int res = ERROR_OK; @@ -1049,29 +1199,29 @@ static const struct command_registration at91samd_exec_command_handlers[] = { .name = "dsu_reset_deassert", .handler = samd_handle_reset_deassert, .mode = COMMAND_EXEC, - .help = "deasert internal reset held by DSU" + .help = "Deasert internal reset held by DSU." }, { .name = "info", .handler = samd_handle_info_command, .mode = COMMAND_EXEC, - .help = "Print information about the current at91samd chip" + .help = "Print information about the current at91samd chip " "and its flash configuration.", }, { .name = "chip-erase", .handler = samd_handle_chip_erase_command, .mode = COMMAND_EXEC, - .help = "Erase the entire Flash by using the Chip" + .help = "Erase the entire Flash by using the Chip-" "Erase feature in the Device Service Unit (DSU).", }, { .name = "set-security", .handler = samd_handle_set_security_command, .mode = COMMAND_EXEC, - .help = "Secure the chip's Flash by setting the Security Bit." - "This makes it impossible to read the Flash contents." - "The only way to undo this is to issue the chip-erase" + .help = "Secure the chip's Flash by setting the Security Bit. " + "This makes it impossible to read the Flash contents. " + "The only way to undo this is to issue the chip-erase " "command.", }, { @@ -1079,9 +1229,9 @@ static const struct command_registration at91samd_exec_command_handlers[] = { .usage = "[size_in_bytes]", .handler = samd_handle_eeprom_command, .mode = COMMAND_EXEC, - .help = "Show or set the EEPROM size setting, stored in the User Row." - "Please see Table 20-3 of the SAMD20 datasheet for allowed values." - "Changes are stored immediately but take affect after the MCU is" + .help = "Show or set the EEPROM size setting, stored in the User Row. " + "Please see Table 20-3 of the SAMD20 datasheet for allowed values. " + "Changes are stored immediately but take affect after the MCU is " "reset.", }, { @@ -1089,11 +1239,22 @@ static const struct command_registration at91samd_exec_command_handlers[] = { .usage = "[size_in_bytes]", .handler = samd_handle_bootloader_command, .mode = COMMAND_EXEC, - .help = "Show or set the bootloader size, stored in the User Row." - "Please see Table 20-2 of the SAMD20 datasheet for allowed values." - "Changes are stored immediately but take affect after the MCU is" + .help = "Show or set the bootloader size, stored in the User Row. " + "Please see Table 20-2 of the SAMD20 datasheet for allowed values. " + "Changes are stored immediately but take affect after the MCU is " "reset.", }, + { + .name = "nvmuserrow", + .usage = "[value] [mask]", + .handler = samd_handle_nvmuserrow_command, + .mode = COMMAND_EXEC, + .help = "Show or set the nvmuserrow register. It is 64 bit wide " + "and located at address 0x804000. Use the optional mask argument " + "to prevent changes at positions where the bitvalue is zero. " + "For security reasons the lock- and reserved-bits are masked out " + "in background and therefore cannot be changed.", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/flash/nor/ath79.c b/src/flash/nor/ath79.c index 451e84365..c5f9eed52 100644 --- a/src/flash/nor/ath79.c +++ b/src/flash/nor/ath79.c @@ -898,4 +898,5 @@ struct flash_driver ath79_flash = { .erase_check = ath79_flash_blank_check, .protect_check = ath79_protect_check, .info = get_ath79_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/atsamv.c b/src/flash/nor/atsamv.c index 73f023896..9c07bdf15 100644 --- a/src/flash/nor/atsamv.c +++ b/src/flash/nor/atsamv.c @@ -739,4 +739,5 @@ struct flash_driver atsamv_flash = { .erase_check = default_flash_blank_check, .protect_check = samv_protect_check, .info = samv_get_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/avrf.c b/src/flash/nor/avrf.c index 11cc3b2d3..65ac6015f 100644 --- a/src/flash/nor/avrf.c +++ b/src/flash/nor/avrf.c @@ -487,4 +487,5 @@ struct flash_driver avr_flash = { .erase_check = default_flash_blank_check, .protect_check = avrf_protect_check, .info = avrf_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c new file mode 100644 index 000000000..2b568593a --- /dev/null +++ b/src/flash/nor/bluenrg-x.c @@ -0,0 +1,554 @@ +/*************************************************************************** + * Copyright (C) 2017 by Michele Sardo * + * msmttchr@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "imp.h" + +#define FLASH_SIZE_REG (0x40100014) +#define DIE_ID_REG (0x4090001C) +#define JTAG_IDCODE_REG (0x40900028) +#define BLUENRG2_IDCODE (0x0200A041) +#define FLASH_BASE (0x10040000) +#define FLASH_PAGE_SIZE (2048) +#define FLASH_REG_COMMAND (0x40100000) +#define FLASH_REG_IRQRAW (0x40100010) +#define FLASH_REG_ADDRESS (0x40100018) +#define FLASH_REG_DATA (0x40100040) +#define FLASH_CMD_ERASE_PAGE 0x11 +#define FLASH_CMD_MASSERASE 0x22 +#define FLASH_CMD_WRITE 0x33 +#define FLASH_CMD_BURSTWRITE 0xCC +#define FLASH_INT_CMDDONE 0x01 +#define FLASH_WORD_LEN 4 + +struct bluenrgx_flash_bank { + int probed; + uint32_t idcode; + uint32_t die_id; +}; + +static int bluenrgx_protect_check(struct flash_bank *bank) +{ + /* Nothing to do. Protection is only handled in SW. */ + return ERROR_OK; +} + +/* flash_bank bluenrg-x 0 0 0 0 */ +FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command) +{ + struct bluenrgx_flash_bank *bluenrgx_info; + /* Create the bank structure */ + bluenrgx_info = calloc(1, sizeof(*bluenrgx_info)); + + /* Check allocation */ + if (bluenrgx_info == NULL) { + LOG_ERROR("failed to allocate bank structure"); + return ERROR_FAIL; + } + + bank->driver_priv = bluenrgx_info; + + bluenrgx_info->probed = 0; + + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + return ERROR_OK; +} + +static int bluenrgx_erase(struct flash_bank *bank, int first, int last) +{ + int retval = ERROR_OK; + struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; + int num_sectors = (last - first + 1); + int mass_erase = (num_sectors == bank->num_sectors); + struct target *target = bank->target; + uint32_t address, command; + + /* check preconditions */ + if (bluenrgx_info->probed == 0) + return ERROR_FLASH_BANK_NOT_PROBED; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + /* Disable blue module */ + if (target_write_u32(target, 0x200000c0, 0) != ERROR_OK) { + LOG_ERROR("Blue disable failed"); + return ERROR_FAIL; + } + + if (mass_erase) { + command = FLASH_CMD_MASSERASE; + address = bank->base; + if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + + if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + + if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + + for (int i = 0; i < 100; i++) { + uint32_t value; + if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + if (value & FLASH_INT_CMDDONE) + break; + if (i == 99) { + LOG_ERROR("Mass erase command failed (timeout)"); + retval = ERROR_FAIL; + } + } + + } else { + command = FLASH_CMD_ERASE_PAGE; + for (int i = first; i <= last; i++) { + address = bank->base+i*FLASH_PAGE_SIZE; + + if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + + if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + + if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) { + LOG_ERROR("Failed"); + return ERROR_FAIL; + } + + for (int j = 0; j < 100; j++) { + uint32_t value; + if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + if (value & FLASH_INT_CMDDONE) + break; + if (j == 99) { + LOG_ERROR("Erase command failed (timeout)"); + retval = ERROR_FAIL; + } + } + } + } + + return retval; + +} + +static int bluenrgx_protect(struct flash_bank *bank, int set, int first, int last) +{ + /* Protection is only handled in software: no hardware write protection + available in BlueNRG-x devices */ + int sector; + + for (sector = first; sector <= last; sector++) + bank->sectors[sector].is_protected = set; + return ERROR_OK; +} +static int bluenrgx_write_word(struct target *target, uint32_t address_base, uint8_t *values, uint32_t count) +{ + int retval = ERROR_OK; + + retval = target_write_u32(target, FLASH_REG_IRQRAW, 0x3f); + if (retval != ERROR_OK) { + LOG_ERROR("Register write failed, error code: %d", retval); + return retval; + } + + for (uint32_t i = 0; i < count; i++) { + uint32_t address = address_base + i * FLASH_WORD_LEN; + + retval = target_write_u32(target, FLASH_REG_ADDRESS, address >> 2); + if (retval != ERROR_OK) { + LOG_ERROR("Register write failed, error code: %d", retval); + return retval; + } + + retval = target_write_buffer(target, FLASH_REG_DATA, FLASH_WORD_LEN, values + i * FLASH_WORD_LEN); + if (retval != ERROR_OK) { + LOG_ERROR("Register write failed, error code: %d", retval); + return retval; + } + + retval = target_write_u32(target, FLASH_REG_COMMAND, FLASH_CMD_WRITE); + if (retval != ERROR_OK) { + LOG_ERROR("Register write failed, error code: %d", retval); + return retval; + } + + for (int j = 0; j < 100; j++) { + uint32_t reg_value; + retval = target_read_u32(target, FLASH_REG_IRQRAW, ®_value); + + if (retval != ERROR_OK) { + LOG_ERROR("Register read failed, error code: %d", retval); + return retval; + } + + if (reg_value & FLASH_INT_CMDDONE) + break; + + if (j == 99) { + LOG_ERROR("Write command failed (timeout)"); + return ERROR_FAIL; + } + } + } + return retval; +} + +static int bluenrgx_write_bytes(struct target *target, uint32_t address_base, uint8_t *buffer, uint32_t count) +{ + int retval = ERROR_OK; + uint8_t *new_buffer = NULL; + uint32_t pre_bytes = 0, post_bytes = 0, pre_word, post_word, pre_address, post_address; + + if (count == 0) { + /* Just return if there are no bytes to write */ + return retval; + } + + if (address_base & 3) { + pre_bytes = address_base & 3; + pre_address = address_base - pre_bytes; + } + + if ((count + pre_bytes) & 3) { + post_bytes = ((count + pre_bytes + 3) & ~3) - (count + pre_bytes); + post_address = (address_base + count) & ~3; + } + + if (pre_bytes || post_bytes) { + uint32_t old_count = count; + + count = old_count + pre_bytes + post_bytes; + + new_buffer = malloc(count); + + if (new_buffer == NULL) { + LOG_ERROR("odd number of bytes to write and no memory " + "for padding buffer"); + return ERROR_FAIL; + } + + LOG_INFO("Requested number of bytes to write and/or address not word aligned (%" PRIu32 "), extending to %" + PRIu32 " ", old_count, count); + + if (pre_bytes) { + if (target_read_u32(target, pre_address, &pre_word)) { + LOG_ERROR("Memory read failed"); + free(new_buffer); + return ERROR_FAIL; + } + + } + + if (post_bytes) { + if (target_read_u32(target, post_address, &post_word)) { + LOG_ERROR("Memory read failed"); + free(new_buffer); + return ERROR_FAIL; + } + + } + + memcpy(new_buffer, &pre_word, pre_bytes); + memcpy((new_buffer+((pre_bytes+old_count) & ~3)), &post_word, 4); + memcpy(new_buffer+pre_bytes, buffer, old_count); + buffer = new_buffer; + } + + retval = bluenrgx_write_word(target, address_base - pre_bytes, buffer, count/4); + + if (new_buffer) + free(new_buffer); + + return retval; +} + +static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + uint32_t buffer_size = 16384 + 8; + struct working_area *write_algorithm; + struct working_area *write_algorithm_sp; + struct working_area *source; + uint32_t address = bank->base + offset; + struct reg_param reg_params[5]; + struct armv7m_algorithm armv7m_info; + int retval = ERROR_OK; + uint32_t pre_size = 0, fast_size = 0, post_size = 0; + uint32_t pre_offset = 0, fast_offset = 0, post_offset = 0; + + /* See contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c for source and + * hints how to generate the data! + */ + static const uint8_t bluenrgx_flash_write_code[] = { +#include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc" + }; + + if ((offset + count) > bank->size) { + LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %d, size=%d", + (offset + count), + bank->size); + return ERROR_FLASH_DST_OUT_OF_BANK; + } + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* We are good here and we need to compute pre_size, fast_size, post_size */ + pre_size = MIN(count, ((offset+0xF) & ~0xF) - offset); + pre_offset = offset; + fast_size = 16*((count - pre_size) / 16); + fast_offset = offset + pre_size; + post_size = (count-pre_size-fast_size) % 16; + post_offset = fast_offset + fast_size; + + LOG_DEBUG("pre_size = %08x, pre_offset=%08x", pre_size, pre_offset); + LOG_DEBUG("fast_size = %08x, fast_offset=%08x", fast_size, fast_offset); + LOG_DEBUG("post_size = %08x, post_offset=%08x", post_size, post_offset); + + /* Program initial chunk not 16 bytes aligned */ + retval = bluenrgx_write_bytes(target, bank->base+pre_offset, (uint8_t *) buffer, pre_size); + if (retval) { + LOG_ERROR("bluenrgx_write_bytes failed %d", retval); + return ERROR_FAIL; + } + + /* Program chunk 16 bytes aligned in fast mode */ + if (fast_size) { + + if (target_alloc_working_area(target, sizeof(bluenrgx_flash_write_code), + &write_algorithm) != ERROR_OK) { + LOG_WARNING("no working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + retval = target_write_buffer(target, write_algorithm->address, + sizeof(bluenrgx_flash_write_code), + bluenrgx_flash_write_code); + if (retval != ERROR_OK) + return retval; + + /* memory buffer */ + if (target_alloc_working_area(target, buffer_size, &source)) { + LOG_WARNING("no large enough working area available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* Stack pointer area */ + if (target_alloc_working_area(target, 64, + &write_algorithm_sp) != ERROR_OK) { + LOG_DEBUG("no working area for write code stack pointer"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); + init_reg_param(®_params[4], "sp", 32, PARAM_OUT); + + /* FIFO start address (first two words used for write and read pointers) */ + buf_set_u32(reg_params[0].value, 0, 32, source->address); + /* FIFO end address (first two words used for write and read pointers) */ + buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); + /* Flash memory address */ + buf_set_u32(reg_params[2].value, 0, 32, address+pre_size); + /* Number of bytes */ + buf_set_u32(reg_params[3].value, 0, 32, fast_size); + /* Stack pointer for program working area */ + buf_set_u32(reg_params[4].value, 0, 32, write_algorithm_sp->address); + + LOG_DEBUG("source->address = %08" TARGET_PRIxADDR, source->address); + LOG_DEBUG("source->address+ source->size = %08" TARGET_PRIxADDR, source->address+source->size); + LOG_DEBUG("write_algorithm_sp->address = %08" TARGET_PRIxADDR, write_algorithm_sp->address); + LOG_DEBUG("address = %08x", address+pre_size); + LOG_DEBUG("count = %08x", count); + + retval = target_run_flash_async_algorithm(target, + buffer+pre_size, + fast_size/16, + 16, /* Block size: we write in block of 16 bytes to enjoy burstwrite speed */ + 0, + NULL, + 5, + reg_params, + source->address, + source->size, + write_algorithm->address, + 0, + &armv7m_info); + + if (retval == ERROR_FLASH_OPERATION_FAILED) { + LOG_ERROR("error executing bluenrg-x flash write algorithm"); + + uint32_t error = buf_get_u32(reg_params[0].value, 0, 32); + + if (error != 0) + LOG_ERROR("flash write failed = %08" PRIx32, error); + } + if (retval == ERROR_OK) { + uint32_t rp; + /* Read back rp and check that is valid */ + retval = target_read_u32(target, source->address+4, &rp); + if (retval == ERROR_OK) { + if ((rp < source->address+8) || (rp > (source->address + source->size))) { + LOG_ERROR("flash write failed = %08" PRIx32, rp); + retval = ERROR_FLASH_OPERATION_FAILED; + } + } + } + target_free_working_area(target, source); + target_free_working_area(target, write_algorithm); + target_free_working_area(target, write_algorithm_sp); + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + if (retval != ERROR_OK) + return retval; + + } + + /* Program chunk at end, not addressable by fast burst write algorithm */ + retval = bluenrgx_write_bytes(target, bank->base+post_offset, (uint8_t *) (buffer+pre_size+fast_size), post_size); + if (retval) { + LOG_ERROR("bluenrgx_write_bytes failed %d", retval); + return ERROR_FAIL; + } + return retval; +} + +static int bluenrgx_probe(struct flash_bank *bank) +{ + struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; + uint32_t idcode, size_info, die_id; + int i; + int retval = target_read_u32(bank->target, JTAG_IDCODE_REG, &idcode); + if (retval != ERROR_OK) + return retval; + retval = target_read_u32(bank->target, FLASH_SIZE_REG, &size_info); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(bank->target, DIE_ID_REG, &die_id); + if (retval != ERROR_OK) + return retval; + + bank->size = (size_info + 1) * 4; + bank->base = FLASH_BASE; + bank->num_sectors = bank->size/FLASH_PAGE_SIZE; + bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors); + + for (i = 0; i < bank->num_sectors; i++) { + bank->sectors[i].offset = i * FLASH_PAGE_SIZE; + bank->sectors[i].size = FLASH_PAGE_SIZE; + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = 0; + } + + bluenrgx_info->probed = 1; + bluenrgx_info->die_id = die_id; + bluenrgx_info->idcode = idcode; + return ERROR_OK; +} + +static int bluenrgx_auto_probe(struct flash_bank *bank) +{ + struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; + + if (bluenrgx_info->probed) + return ERROR_OK; + + return bluenrgx_probe(bank); +} + +/* This method must return a string displaying information about the bank */ +static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; + int mask_number, cut_number; + char *part_name; + + if (!bluenrgx_info->probed) { + int retval = bluenrgx_probe(bank); + if (retval != ERROR_OK) { + snprintf(buf, buf_size, + "Unable to find bank information."); + return retval; + } + } + + if (bluenrgx_info->idcode == BLUENRG2_IDCODE) + part_name = "BLUENRG-2"; + else + part_name = "BLUENRG-1"; + + mask_number = (bluenrgx_info->die_id >> 4) & 0xF; + cut_number = bluenrgx_info->die_id & 0xF; + + snprintf(buf, buf_size, + "%s - Rev: %d.%d", part_name, mask_number, cut_number); + return ERROR_OK; +} + +struct flash_driver bluenrgx_flash = { + .name = "bluenrg-x", + .flash_bank_command = bluenrgx_flash_bank_command, + .erase = bluenrgx_erase, + .protect = bluenrgx_protect, + .write = bluenrgx_write, + .read = default_flash_read, + .probe = bluenrgx_probe, + .erase_check = default_flash_blank_check, + .protect_check = bluenrgx_protect_check, + .auto_probe = bluenrgx_auto_probe, + .info = bluenrgx_get_info, +}; diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c index ac0db8271..0ae72d4a2 100644 --- a/src/flash/nor/cfi.c +++ b/src/flash/nor/cfi.c @@ -3128,4 +3128,5 @@ struct flash_driver cfi_flash = { .erase_check = default_flash_blank_check, .protect_check = cfi_protect_check, .info = get_cfi_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c index ab69a328b..636d50c51 100644 --- a/src/flash/nor/core.c +++ b/src/flash/nor/core.c @@ -171,6 +171,31 @@ int flash_get_bank_count(void) return i; } +void default_flash_free_driver_priv(struct flash_bank *bank) +{ + free(bank->driver_priv); + bank->driver_priv = NULL; +} + +void flash_free_all_banks(void) +{ + struct flash_bank *bank = flash_banks; + while (bank) { + struct flash_bank *next = bank->next; + if (bank->driver->free_driver_priv) + bank->driver->free_driver_priv(bank); + else + LOG_WARNING("Flash driver of %s does not support free_driver_priv()", bank->name); + + free(bank->name); + free(bank->sectors); + free(bank->prot_blocks); + free(bank); + bank = next; + } + flash_banks = NULL; +} + struct flash_bank *get_flash_bank_by_name_noprobe(const char *name) { unsigned requested = get_flash_name_index(name); @@ -399,18 +424,21 @@ static int flash_iterate_address_range_inner(struct target *target, return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } - addr -= c->base; - last_addr -= c->base; + if (c->prot_blocks == NULL || c->num_prot_blocks == 0) { + /* flash driver does not define protect blocks, use sectors instead */ + iterate_protect_blocks = false; + } - if (iterate_protect_blocks && c->prot_blocks && c->num_prot_blocks) { + if (iterate_protect_blocks) { block_array = c->prot_blocks; num_blocks = c->num_prot_blocks; } else { block_array = c->sectors; num_blocks = c->num_sectors; - iterate_protect_blocks = false; } + addr -= c->base; + last_addr -= c->base; for (i = 0; i < num_blocks; i++) { struct flash_sector *f = &block_array[i]; @@ -601,7 +629,7 @@ int flash_write_unlock(struct target *target, struct image *image, uint32_t buffer_size; uint8_t *buffer; int section_last; - uint32_t run_address = sections[section]->base_address + section_offset; + target_addr_t run_address = sections[section]->base_address + section_offset; uint32_t run_size = sections[section]->size - section_offset; int pad_bytes = 0; @@ -617,7 +645,7 @@ int flash_write_unlock(struct target *target, struct image *image, if (retval != ERROR_OK) goto done; if (c == NULL) { - LOG_WARNING("no flash bank found for address %" PRIx32, run_address); + LOG_WARNING("no flash bank found for address " TARGET_ADDR_FMT, run_address); section++; /* and skip it */ section_offset = 0; continue; @@ -652,7 +680,18 @@ int flash_write_unlock(struct target *target, struct image *image, /* if we have multiple sections within our image, * flash programming could fail due to alignment issues * attempt to rebuild a consecutive buffer for the flash loader */ - pad_bytes = (sections[section_last + 1]->base_address) - (run_address + run_size); + target_addr_t run_next_addr = run_address + run_size; + if (sections[section_last + 1]->base_address < run_next_addr) { + LOG_ERROR("Section at " TARGET_ADDR_FMT + " overlaps section ending at " TARGET_ADDR_FMT, + sections[section_last + 1]->base_address, + run_next_addr); + LOG_ERROR("Flash write aborted."); + retval = ERROR_FAIL; + goto done; + } + + pad_bytes = sections[section_last + 1]->base_address - run_next_addr; padding[section_last] = pad_bytes; run_size += sections[++section_last]->size; run_size += pad_bytes; diff --git a/src/flash/nor/core.h b/src/flash/nor/core.h index 338363e2a..1bfe1ab97 100644 --- a/src/flash/nor/core.h +++ b/src/flash/nor/core.h @@ -76,7 +76,7 @@ struct flash_sector { * per-bank basis, if required. */ struct flash_bank { - const char *name; + char *name; struct target *target; /**< Target to which this bank belongs. */ @@ -153,8 +153,15 @@ int flash_write(struct target *target, * This routine must be called when the system may modify the status. */ void flash_set_dirty(void); + /** @returns The number of flash banks currently defined. */ int flash_get_bank_count(void); + +/** Deallocates bank->driver_priv */ +void default_flash_free_driver_priv(struct flash_bank *bank); + +/** Deallocates all flash banks */ +void flash_free_all_banks(void); /** * Provides default read implementation for flash memory. * @param bank The bank to read. diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h index 0ae4d8e20..e7b323443 100644 --- a/src/flash/nor/driver.h +++ b/src/flash/nor/driver.h @@ -209,6 +209,14 @@ struct flash_driver { * @returns ERROR_OK if successful; otherwise, an error code. */ int (*auto_probe)(struct flash_bank *bank); + + /** + * Deallocates private driver structures. + * Use default_flash_free_driver_priv() to simply free(bank->driver_priv) + * + * @param bank - the bank being destroyed + */ + void (*free_driver_priv)(struct flash_bank *bank); }; #define FLASH_BANK_COMMAND_HANDLER(name) \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 81680113d..3d6dab297 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -31,6 +31,7 @@ extern struct flash_driver at91samd_flash; extern struct flash_driver ath79_flash; extern struct flash_driver atsamv_flash; extern struct flash_driver avr_flash; +extern struct flash_driver bluenrgx_flash; extern struct flash_driver cfi_flash; extern struct flash_driver dsp5680xx_flash; extern struct flash_driver efm32_flash; @@ -55,6 +56,7 @@ extern struct flash_driver numicro_flash; extern struct flash_driver ocl_flash; extern struct flash_driver pic32mx_flash; extern struct flash_driver psoc4_flash; +extern struct flash_driver psoc6_flash; extern struct flash_driver sim3x_flash; extern struct flash_driver stellaris_flash; extern struct flash_driver stm32f1x_flash; @@ -88,6 +90,7 @@ static struct flash_driver *flash_drivers[] = { &ath79_flash, &atsamv_flash, &avr_flash, + &bluenrgx_flash, &cfi_flash, &dsp5680xx_flash, &efm32_flash, @@ -112,6 +115,7 @@ static struct flash_driver *flash_drivers[] = { &ocl_flash, &pic32mx_flash, &psoc4_flash, + &psoc6_flash, &sim3x_flash, &stellaris_flash, &stm32f1x_flash, diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c index b8453e1dd..1d70bd501 100644 --- a/src/flash/nor/efm32.c +++ b/src/flash/nor/efm32.c @@ -38,19 +38,8 @@ #include #include -/* keep family IDs in decimal */ -#define EFM_FAMILY_ID_GECKO 71 #define EFM_FAMILY_ID_GIANT_GECKO 72 -#define EFM_FAMILY_ID_TINY_GECKO 73 #define EFM_FAMILY_ID_LEOPARD_GECKO 74 -#define EFM_FAMILY_ID_WONDER_GECKO 75 -#define EFM_FAMILY_ID_ZERO_GECKO 76 -#define EFM_FAMILY_ID_HAPPY_GECKO 77 -#define EZR_FAMILY_ID_WONDER_GECKO 120 -#define EZR_FAMILY_ID_LEOPARD_GECKO 121 -#define EZR_FAMILY_ID_HAPPY_GECKO 122 -#define EFR_FAMILY_ID_MIGHTY_GECKO 16 -#define EFR_FAMILY_ID_BLUE_GECKO 20 #define EFM32_FLASH_ERASE_TMO 100 #define EFM32_FLASH_WDATAREADY_TMO 100 @@ -65,7 +54,7 @@ #define EFM32_MSC_LOCK_BITS (EFM32_MSC_INFO_BASE+0x4000) #define EFM32_MSC_DEV_INFO (EFM32_MSC_INFO_BASE+0x8000) -/* PAGE_SIZE is only present in Leopard, Giant and Wonder Gecko MCUs */ +/* PAGE_SIZE is not present in Zero, Happy and the original Gecko MCU */ #define EFM32_MSC_DI_PAGE_SIZE (EFM32_MSC_DEV_INFO+0x1e7) #define EFM32_MSC_DI_FLASH_SZ (EFM32_MSC_DEV_INFO+0x1f8) #define EFM32_MSC_DI_RAM_SZ (EFM32_MSC_DEV_INFO+0x1fa) @@ -74,7 +63,7 @@ #define EFM32_MSC_DI_PROD_REV (EFM32_MSC_DEV_INFO+0x1ff) #define EFM32_MSC_REGBASE 0x400c0000 -#define EFR32_MSC_REGBASE 0x400e0000 +#define EFM32_MSC_REGBASE_SERIES1 0x400e0000 #define EFM32_MSC_REG_WRITECTRL 0x008 #define EFM32_MSC_WRITECTRL_WREN_MASK 0x1 #define EFM32_MSC_REG_WRITECMD 0x00c @@ -91,9 +80,24 @@ #define EFM32_MSC_STATUS_WORDTIMEOUT_MASK 0x10 #define EFM32_MSC_STATUS_ERASEABORTED_MASK 0x20 #define EFM32_MSC_REG_LOCK 0x03c -#define EFR32_MSC_REG_LOCK 0x040 +#define EFM32_MSC_REG_LOCK_SERIES1 0x040 #define EFM32_MSC_LOCK_LOCKKEY 0x1b71 +struct efm32_family_data { + int family_id; + const char *name; + + /* EFM32 series (EFM32LG995F is the "old" series 0, while EFR32MG12P132 + is the "new" series 1). Determines location of MSC registers. */ + int series; + + /* Page size in bytes, or 0 to read from EFM32_MSC_DI_PAGE_SIZE */ + int page_size; + + /* MSC register base address, or 0 to use default */ + uint32_t msc_regbase; +}; + struct efm32x_flash_bank { int probed; uint32_t lb_page[LOCKBITS_PAGE_SZ/4]; @@ -102,6 +106,7 @@ struct efm32x_flash_bank { }; struct efm32_info { + const struct efm32_family_data *family_data; uint16_t flash_sz_kib; uint16_t ram_sz_kib; uint16_t part_num; @@ -110,6 +115,64 @@ struct efm32_info { uint16_t page_size; }; +static const struct efm32_family_data efm32_families[] = { + { 16, "EFR32MG1P Mighty", .series = 1 }, + { 17, "EFR32MG1B Mighty", .series = 1 }, + { 18, "EFR32MG1V Mighty", .series = 1 }, + { 19, "EFR32MG1P Blue", .series = 1 }, + { 20, "EFR32MG1B Blue", .series = 1 }, + { 21, "EFR32MG1V Blue", .series = 1 }, + { 25, "EFR32FG1P Flex", .series = 1 }, + { 26, "EFR32FG1B Flex", .series = 1 }, + { 27, "EFR32FG1V Flex", .series = 1 }, + { 28, "EFR32MG2P Mighty", .series = 1 }, + { 29, "EFR32MG2B Mighty", .series = 1 }, + { 30, "EFR32MG2V Mighty", .series = 1 }, + { 31, "EFR32BG12P Blue", .series = 1 }, + { 32, "EFR32BG12B Blue", .series = 1 }, + { 33, "EFR32BG12V Blue", .series = 1 }, + { 37, "EFR32FG12P Flex", .series = 1 }, + { 38, "EFR32FG12B Flex", .series = 1 }, + { 39, "EFR32FG12V Flex", .series = 1 }, + { 40, "EFR32MG13P Mighty", .series = 1 }, + { 41, "EFR32MG13B Mighty", .series = 1 }, + { 42, "EFR32MG13V Mighty", .series = 1 }, + { 43, "EFR32BG13P Blue", .series = 1 }, + { 44, "EFR32BG13B Blue", .series = 1 }, + { 45, "EFR32BG13V Blue", .series = 1 }, + { 49, "EFR32FG13P Flex", .series = 1 }, + { 50, "EFR32FG13B Flex", .series = 1 }, + { 51, "EFR32FG13V Flex", .series = 1 }, + { 52, "EFR32MG14P Mighty", .series = 1 }, + { 53, "EFR32MG14B Mighty", .series = 1 }, + { 54, "EFR32MG14V Mighty", .series = 1 }, + { 55, "EFR32BG14P Blue", .series = 1 }, + { 56, "EFR32BG14B Blue", .series = 1 }, + { 57, "EFR32BG14V Blue", .series = 1 }, + { 61, "EFR32FG14P Flex", .series = 1 }, + { 62, "EFR32FG14B Flex", .series = 1 }, + { 63, "EFR32FG14V Flex", .series = 1 }, + { 71, "EFM32G", .series = 0, .page_size = 512 }, + { 72, "EFM32GG Giant", .series = 0 }, + { 73, "EFM32TG Tiny", .series = 0, .page_size = 512 }, + { 74, "EFM32LG Leopard", .series = 0 }, + { 75, "EFM32WG Wonder", .series = 0 }, + { 76, "EFM32ZG Zero", .series = 0, .page_size = 1024 }, + { 77, "EFM32HG Happy", .series = 0, .page_size = 1024 }, + { 81, "EFM32PG1B Pearl", .series = 1 }, + { 83, "EFM32JG1B Jade", .series = 1 }, + { 85, "EFM32PG12B Pearl", .series = 1 }, + { 87, "EFM32JG12B Jade", .series = 1 }, + { 89, "EFM32PG13B Pearl", .series = 1 }, + { 91, "EFM32JG13B Jade", .series = 1 }, + { 100, "EFM32GG11B Giant", .series = 1, .msc_regbase = 0x40000000 }, + { 103, "EFM32TG11B Tiny", .series = 1 }, + { 120, "EZR32WG Wonder", .series = 0 }, + { 121, "EZR32LG Leopard", .series = 0 }, + { 122, "EZR32HG Happy", .series = 0, .page_size = 1024 }, +}; + + static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count); @@ -200,51 +263,33 @@ static int efm32x_read_info(struct flash_bank *bank, if (ERROR_OK != ret) return ret; - if (EFR_FAMILY_ID_BLUE_GECKO == efm32_info->part_family || - EFR_FAMILY_ID_MIGHTY_GECKO == efm32_info->part_family) { - efm32x_info->reg_base = EFR32_MSC_REGBASE; - efm32x_info->reg_lock = EFR32_MSC_REG_LOCK; - } else { - efm32x_info->reg_base = EFM32_MSC_REGBASE; - efm32x_info->reg_lock = EFM32_MSC_REG_LOCK; + for (size_t i = 0; i < ARRAY_SIZE(efm32_families); i++) { + if (efm32_families[i].family_id == efm32_info->part_family) + efm32_info->family_data = &efm32_families[i]; } - if (EFM_FAMILY_ID_GECKO == efm32_info->part_family || - EFM_FAMILY_ID_TINY_GECKO == efm32_info->part_family) - efm32_info->page_size = 512; - else if (EFM_FAMILY_ID_ZERO_GECKO == efm32_info->part_family || - EFM_FAMILY_ID_HAPPY_GECKO == efm32_info->part_family || - EZR_FAMILY_ID_HAPPY_GECKO == efm32_info->part_family) - efm32_info->page_size = 1024; - else if (EFM_FAMILY_ID_GIANT_GECKO == efm32_info->part_family || - EFM_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family) { - if (efm32_info->prod_rev >= 18) { - uint8_t pg_size = 0; - ret = target_read_u8(bank->target, EFM32_MSC_DI_PAGE_SIZE, - &pg_size); - if (ERROR_OK != ret) - return ret; + if (efm32_info->family_data == NULL) { + LOG_ERROR("Unknown MCU family %d", efm32_info->part_family); + return ERROR_FAIL; + } - efm32_info->page_size = (1 << ((pg_size+10) & 0xff)); - } else { - /* EFM32 GG/LG errata: MEM_INFO_PAGE_SIZE is invalid - for MCUs with PROD_REV < 18 */ - if (efm32_info->flash_sz_kib < 512) - efm32_info->page_size = 2048; - else - efm32_info->page_size = 4096; - } + switch (efm32_info->family_data->series) { + case 0: + efm32x_info->reg_base = EFM32_MSC_REGBASE; + efm32x_info->reg_lock = EFM32_MSC_REG_LOCK; + break; + case 1: + efm32x_info->reg_base = EFM32_MSC_REGBASE_SERIES1; + efm32x_info->reg_lock = EFM32_MSC_REG_LOCK_SERIES1; + break; + } - if ((2048 != efm32_info->page_size) && - (4096 != efm32_info->page_size)) { - LOG_ERROR("Invalid page size %u", efm32_info->page_size); - return ERROR_FAIL; - } - } else if (EFM_FAMILY_ID_WONDER_GECKO == efm32_info->part_family || - EZR_FAMILY_ID_WONDER_GECKO == efm32_info->part_family || - EZR_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family || - EFR_FAMILY_ID_BLUE_GECKO == efm32_info->part_family || - EFR_FAMILY_ID_MIGHTY_GECKO == efm32_info->part_family) { + if (efm32_info->family_data->msc_regbase != 0) + efm32x_info->reg_base = efm32_info->family_data->msc_regbase; + + if (efm32_info->family_data->page_size != 0) { + efm32_info->page_size = efm32_info->family_data->page_size; + } else { uint8_t pg_size = 0; ret = target_read_u8(bank->target, EFM32_MSC_DI_PAGE_SIZE, &pg_size); @@ -252,13 +297,25 @@ static int efm32x_read_info(struct flash_bank *bank, return ret; efm32_info->page_size = (1 << ((pg_size+10) & 0xff)); - if (2048 != efm32_info->page_size) { + + if (efm32_info->part_family == EFM_FAMILY_ID_GIANT_GECKO || + efm32_info->part_family == EFM_FAMILY_ID_LEOPARD_GECKO) { + /* Giant or Leopard Gecko */ + if (efm32_info->prod_rev < 18) { + /* EFM32 GG/LG errata: MEM_INFO_PAGE_SIZE is invalid + for MCUs with PROD_REV < 18 */ + if (efm32_info->flash_sz_kib < 512) + efm32_info->page_size = 2048; + else + efm32_info->page_size = 4096; + } + } + + if ((efm32_info->page_size != 2048) && + (efm32_info->page_size != 4096)) { LOG_ERROR("Invalid page size %u", efm32_info->page_size); return ERROR_FAIL; } - } else { - LOG_ERROR("Unknown MCU family %d", efm32_info->part_family); - return ERROR_FAIL; } return ERROR_OK; @@ -270,71 +327,10 @@ static int efm32x_read_info(struct flash_bank *bank, static int efm32x_decode_info(struct efm32_info *info, char *buf, int buf_size) { int printed = 0; + printed = snprintf(buf, buf_size, "%s Gecko, rev %d", + info->family_data->name, info->prod_rev); - switch (info->part_family) { - case EZR_FAMILY_ID_WONDER_GECKO: - case EZR_FAMILY_ID_LEOPARD_GECKO: - case EZR_FAMILY_ID_HAPPY_GECKO: - printed = snprintf(buf, buf_size, "EZR32 "); - break; - case EFR_FAMILY_ID_MIGHTY_GECKO: - case EFR_FAMILY_ID_BLUE_GECKO: - printed = snprintf(buf, buf_size, "EFR32 "); - break; - default: - printed = snprintf(buf, buf_size, "EFM32 "); - } - - buf += printed; - buf_size -= printed; - - if (0 >= buf_size) - return ERROR_BUF_TOO_SMALL; - - switch (info->part_family) { - case EFM_FAMILY_ID_GECKO: - printed = snprintf(buf, buf_size, "Gecko"); - break; - case EFM_FAMILY_ID_GIANT_GECKO: - printed = snprintf(buf, buf_size, "Giant Gecko"); - break; - case EFM_FAMILY_ID_TINY_GECKO: - printed = snprintf(buf, buf_size, "Tiny Gecko"); - break; - case EFM_FAMILY_ID_LEOPARD_GECKO: - case EZR_FAMILY_ID_LEOPARD_GECKO: - printed = snprintf(buf, buf_size, "Leopard Gecko"); - break; - case EFM_FAMILY_ID_WONDER_GECKO: - case EZR_FAMILY_ID_WONDER_GECKO: - printed = snprintf(buf, buf_size, "Wonder Gecko"); - break; - case EFM_FAMILY_ID_ZERO_GECKO: - printed = snprintf(buf, buf_size, "Zero Gecko"); - break; - case EFM_FAMILY_ID_HAPPY_GECKO: - case EZR_FAMILY_ID_HAPPY_GECKO: - printed = snprintf(buf, buf_size, "Happy Gecko"); - break; - case EFR_FAMILY_ID_BLUE_GECKO: - printed = snprintf(buf, buf_size, "Blue Gecko"); - break; - case EFR_FAMILY_ID_MIGHTY_GECKO: - printed = snprintf(buf, buf_size, "Mighty Gecko"); - break; - } - - buf += printed; - buf_size -= printed; - - if (0 >= buf_size) - return ERROR_BUF_TOO_SMALL; - - printed = snprintf(buf, buf_size, " - Rev: %d", info->prod_rev); - buf += printed; - buf_size -= printed; - - if (0 >= buf_size) + if (printed >= buf_size) return ERROR_BUF_TOO_SMALL; return ERROR_OK; @@ -522,7 +518,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank) } } - /* also, read ULW, DLW and MLW */ + /* also, read ULW, DLW, MLW, ALW and CLW words */ /* ULW, word 126 */ ptr = efm32x_info->lb_page + 126; @@ -540,7 +536,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank) return ret; } - /* MLW, word 125, present in GG and LG */ + /* MLW, word 125, present in GG, LG, PG, JG, EFR32 */ ptr = efm32x_info->lb_page + 125; ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+125*4, ptr); if (ERROR_OK != ret) { @@ -548,6 +544,30 @@ static int efm32x_read_lock_data(struct flash_bank *bank) return ret; } + /* ALW, word 124, present in GG, LG, PG, JG, EFR32 */ + ptr = efm32x_info->lb_page + 124; + ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+124*4, ptr); + if (ERROR_OK != ret) { + LOG_ERROR("Failed to read ALW"); + return ret; + } + + /* CLW1, word 123, present in EFR32 */ + ptr = efm32x_info->lb_page + 123; + ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+123*4, ptr); + if (ERROR_OK != ret) { + LOG_ERROR("Failed to read CLW1"); + return ret; + } + + /* CLW0, word 122, present in GG, LG, PG, JG, EFR32 */ + ptr = efm32x_info->lb_page + 122; + ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+122*4, ptr); + if (ERROR_OK != ret) { + LOG_ERROR("Failed to read CLW0"); + return ret; + } + return ERROR_OK; } @@ -1113,4 +1133,5 @@ struct flash_driver efm32_flash = { .erase_check = default_flash_blank_check, .protect_check = efm32x_protect_check, .info = get_efm32x_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/em357.c b/src/flash/nor/em357.c index a11743b55..b14e0323c 100644 --- a/src/flash/nor/em357.c +++ b/src/flash/nor/em357.c @@ -941,4 +941,5 @@ struct flash_driver em357_flash = { .auto_probe = em357_auto_probe, .erase_check = default_flash_blank_check, .protect_check = em357_protect_check, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/faux.c b/src/flash/nor/faux.c index 203eb6fff..46eda7223 100644 --- a/src/flash/nor/faux.c +++ b/src/flash/nor/faux.c @@ -136,5 +136,6 @@ struct flash_driver faux_flash = { .auto_probe = faux_probe, .erase_check = default_flash_blank_check, .protect_check = faux_protect_check, - .info = faux_info + .info = faux_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/fm3.c b/src/flash/nor/fm3.c index 6269a6536..6c619775a 100644 --- a/src/flash/nor/fm3.c +++ b/src/flash/nor/fm3.c @@ -997,4 +997,5 @@ struct flash_driver fm3_flash = { .probe = fm3_probe, .auto_probe = fm3_auto_probe, .erase_check = default_flash_blank_check, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/fm4.c b/src/flash/nor/fm4.c index c8fe8b66f..f5eab9c5b 100644 --- a/src/flash/nor/fm4.c +++ b/src/flash/nor/fm4.c @@ -719,4 +719,5 @@ struct flash_driver fm4_flash = { .erase = fm4_flash_erase, .erase_check = default_flash_blank_check, .write = fm4_flash_write, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/jtagspi.c b/src/flash/nor/jtagspi.c index a73812d88..c28ad22f7 100644 --- a/src/flash/nor/jtagspi.c +++ b/src/flash/nor/jtagspi.c @@ -432,5 +432,6 @@ struct flash_driver jtagspi_flash = { .auto_probe = jtagspi_probe, .erase_check = default_flash_blank_check, .protect_check = jtagspi_protect_check, - .info = jtagspi_info + .info = jtagspi_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/kinetis_ke.c b/src/flash/nor/kinetis_ke.c index 636fcc2e9..8103b6394 100644 --- a/src/flash/nor/kinetis_ke.c +++ b/src/flash/nor/kinetis_ke.c @@ -478,14 +478,13 @@ int kinetis_ke_stop_watchdog(struct target *target) watchdog_algorithm->address, 0, 100000, &armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("Error executing Kinetis KE watchdog algorithm"); - retval = ERROR_FAIL; } else { LOG_INFO("Watchdog stopped"); } target_free_working_area(target, watchdog_algorithm); - return ERROR_OK; + return retval; } COMMAND_HANDLER(kinetis_ke_disable_wdog_handler) @@ -1311,4 +1310,5 @@ struct flash_driver kinetis_ke_flash = { .erase_check = kinetis_ke_blank_check, .protect_check = kinetis_ke_protect_check, .info = kinetis_ke_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/lpc2000.c b/src/flash/nor/lpc2000.c index 9da5da2ca..8e15c3122 100644 --- a/src/flash/nor/lpc2000.c +++ b/src/flash/nor/lpc2000.c @@ -1579,4 +1579,5 @@ struct flash_driver lpc2000_flash = { .erase_check = lpc2000_erase_check, .protect_check = lpc2000_protect_check, .info = get_lpc2000_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/lpc288x.c b/src/flash/nor/lpc288x.c index a4d88de78..24729138a 100644 --- a/src/flash/nor/lpc288x.c +++ b/src/flash/nor/lpc288x.c @@ -433,4 +433,5 @@ struct flash_driver lpc288x_flash = { .auto_probe = lpc288x_probe, .erase_check = lpc288x_erase_check, .protect_check = lpc288x_protect_check, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/lpc2900.c b/src/flash/nor/lpc2900.c index 515a3f7b2..1c65933e2 100644 --- a/src/flash/nor/lpc2900.c +++ b/src/flash/nor/lpc2900.c @@ -1598,4 +1598,5 @@ struct flash_driver lpc2900_flash = { .auto_probe = lpc2900_probe, .erase_check = lpc2900_erase_check, .protect_check = lpc2900_protect_check, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/lpcspifi.c b/src/flash/nor/lpcspifi.c index 943c151e2..828c60ca6 100644 --- a/src/flash/nor/lpcspifi.c +++ b/src/flash/nor/lpcspifi.c @@ -942,4 +942,5 @@ struct flash_driver lpcspifi_flash = { .erase_check = default_flash_blank_check, .protect_check = lpcspifi_protect_check, .info = get_lpcspifi_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/mdr.c b/src/flash/nor/mdr.c index 8ceb1bf46..f3916ded9 100644 --- a/src/flash/nor/mdr.c +++ b/src/flash/nor/mdr.c @@ -633,4 +633,5 @@ struct flash_driver mdr_flash = { .erase_check = default_flash_blank_check, .protect_check = mdr_protect_check, .info = get_mdr_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/mrvlqspi.c b/src/flash/nor/mrvlqspi.c index d79917058..eda6cc1ad 100644 --- a/src/flash/nor/mrvlqspi.c +++ b/src/flash/nor/mrvlqspi.c @@ -955,4 +955,5 @@ struct flash_driver mrvlqspi_flash = { .erase_check = mrvlqspi_flash_erase_check, .protect_check = mrvlqspi_protect_check, .info = mrvlqspi_get_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/niietcm4.c b/src/flash/nor/niietcm4.c index 4a849fd26..fd7d519a8 100644 --- a/src/flash/nor/niietcm4.c +++ b/src/flash/nor/niietcm4.c @@ -1741,4 +1741,5 @@ struct flash_driver niietcm4_flash = { .erase_check = default_flash_blank_check, .protect_check = niietcm4_protect_check, .info = get_niietcm4_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index 4fa62e30a..31dd5aae5 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -155,6 +155,11 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = { NRF5_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256), NRF5_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256), + /* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards + with built-in jlink seem to use engineering samples not listed + in the nRF51 Series Compatibility Matrix V1.0. */ + NRF5_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256), + /* nRF51822 Devices (IC rev 2). */ NRF5_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256), NRF5_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256), @@ -175,6 +180,7 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = { NRF5_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128), NRF5_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256), NRF5_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256), + NRF5_DEVICE_DEF(0x008F, "51822", "QFAA", "H1", 256), /* nRF51422 Devices (IC rev 1). */ NRF5_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256), @@ -198,11 +204,6 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = { /* nRF52832 Devices */ NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512), - - /* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards - with built-in jlink seem to use engineering samples not listed - in the nRF51 Series Compatibility Matrix V1.0. */ - NRF5_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256), }; static int nrf5_bank_is_probed(struct flash_bank *bank) diff --git a/src/flash/nor/numicro.c b/src/flash/nor/numicro.c index 992baa515..4d951f0ee 100644 --- a/src/flash/nor/numicro.c +++ b/src/flash/nor/numicro.c @@ -1880,4 +1880,5 @@ struct flash_driver numicro_flash = { .auto_probe = numicro_auto_probe, .erase_check = default_flash_blank_check, .protect_check = numicro_protect_check, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/ocl.c b/src/flash/nor/ocl.c index 4ae565219..895c4af21 100644 --- a/src/flash/nor/ocl.c +++ b/src/flash/nor/ocl.c @@ -340,4 +340,5 @@ struct flash_driver ocl_flash = { .erase_check = ocl_erase_check, .protect_check = ocl_protect_check, .auto_probe = ocl_auto_probe, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/pic32mx.c b/src/flash/nor/pic32mx.c index 1f148fd73..e3b802870 100644 --- a/src/flash/nor/pic32mx.c +++ b/src/flash/nor/pic32mx.c @@ -980,4 +980,5 @@ struct flash_driver pic32mx_flash = { .erase_check = default_flash_blank_check, .protect_check = pic32mx_protect_check, .info = pic32mx_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/psoc4.c b/src/flash/nor/psoc4.c index c7c85737c..47d60dee4 100644 --- a/src/flash/nor/psoc4.c +++ b/src/flash/nor/psoc4.c @@ -41,24 +41,67 @@ Document Number: 001-87197 Rev. *B Revised August 29, 2013 PSoC 4100/4200 Family PSoC(R) 4 Architecture TRM - Document No. 001-85634 Rev. *C March 25, 2014 + Document No. 001-85634 Rev. *E June 28, 2016 PSoC(R) 4 Registers TRM Spec. Document No. 001-85847 Rev. *A June 25, 2013 + PSoC 4000 Family PSoC(R) 4 Technical Reference Manual + Document No. 001-89309 Rev. *B May 9, 2016 + + PSoC 41XX_BLE/42XX_BLE Family PSoC 4 BLE Architecture TRM + Document No. 001-92738 Rev. *C February 12, 2016 + + PSoC 4200L Family PSoC 4 Architecture TRM + Document No. 001-97952 Rev. *A December 15, 2015 + + PSoC 4200L Family PSoC 4 Registers TRM + Document No. 001-98126 Rev. *A December 16, 2015 + + PSoC 4100M/4200M Family PSoC 4 Architecture TRM + Document No. 001-95223 Rev. *B July 29, 2015 + + PSoC 4100S Family PSoC 4 Architecture TRM + Document No. 002-10621 Rev. *A July 29, 2016 + + PSoC 4100S Family PSoC 4 Registers TRM + Document No. 002-10523 Rev. *A July 20, 2016 + + PSoC Analog Coprocessor Architecture TRM + Document No. 002-10404 Rev. ** December 18, 2015 + + CY8C4Axx PSoC Analog Coprocessor Registers TRM + Document No. 002-10405 Rev. ** December 18, 2015 + CY8C41xx, CY8C42xx Programming Specifications Document No. 001-81799 Rev. *C March 4, 2014 + + CYBL10x6x, CY8C4127_BL, CY8C4247_BL Programming Specifications + Document No. 001-91508 Rev. *B September 22, 2014 + + http://dmitry.gr/index.php?r=05.Projects&proj=24.%20PSoC4%20confidential */ /* register locations */ -#define PSOC4_CPUSS_SYSREQ 0x40000004 -#define PSOC4_CPUSS_SYSARG 0x40000008 -#define PSOC4_TEST_MODE 0x40030014 -#define PSOC4_SPCIF_GEOMETRY 0x400E0000 +#define PSOC4_SFLASH_MACRO0 0x0FFFF000 + +#define PSOC4_CPUSS_SYSREQ_LEGACY 0x40000004 +#define PSOC4_CPUSS_SYSARG_LEGACY 0x40000008 +#define PSOC4_SPCIF_GEOMETRY_LEGACY 0x400E0000 + +#define PSOC4_CPUSS_SYSREQ_NEW 0x40100004 +#define PSOC4_CPUSS_SYSARG_NEW 0x40100008 +#define PSOC4_SPCIF_GEOMETRY_NEW 0x40110000 + +#define PSOC4_TEST_MODE 0x40030014 + +#define PSOC4_ROMTABLE_PID0 0xF0000FE0 -#define PSOC4_SFLASH_MACRO 0x0ffff000 /* constants */ +#define PSOC4_SFLASH_MACRO_SIZE 0x800 +#define PSOC4_ROWS_PER_MACRO 512 + #define PSOC4_SROM_KEY1 0xb6 #define PSOC4_SROM_KEY2 0xd3 #define PSOC4_SROM_SYSREQ_BIT (1<<31) @@ -66,6 +109,10 @@ #define PSOC4_SROM_PRIVILEGED_BIT (1<<28) #define PSOC4_SROM_STATUS_SUCCEEDED 0xa0000000 #define PSOC4_SROM_STATUS_FAILED 0xf0000000 +#define PSOC4_SROM_STATUS_MASK 0xf0000000 + +/* not documented in any TRM */ +#define PSOC4_SROM_ERR_IMO_NOT_IMPLEM 0xf0000013 #define PSOC4_CMD_GET_SILICON_ID 0 #define PSOC4_CMD_LOAD_LATCH 4 @@ -74,76 +121,60 @@ #define PSOC4_CMD_ERASE_ALL 0xa #define PSOC4_CMD_CHECKSUM 0xb #define PSOC4_CMD_WRITE_PROTECTION 0xd +#define PSOC4_CMD_SET_IMO48 0x15 +#define PSOC4_CMD_WRITE_SFLASH_ROW 0x18 #define PSOC4_CHIP_PROT_VIRGIN 0x0 #define PSOC4_CHIP_PROT_OPEN 0x1 #define PSOC4_CHIP_PROT_PROTECTED 0x2 #define PSOC4_CHIP_PROT_KILL 0x4 +#define PSOC4_ROMTABLE_DESIGNER_CHECK 0xb4 -struct psoc4_chip_details { +#define PSOC4_FAMILY_FLAG_LEGACY 1 + +struct psoc4_chip_family { uint16_t id; - const char *type; - const char *package; - uint32_t flash_size_in_kb; + const char *name; + uint32_t flags; }; -/* list of PSoC 4 chips - * flash_size_in_kb is not necessary as it can be decoded from SPCIF_GEOMETRY - */ -const struct psoc4_chip_details psoc4_devices[] = { - /* 4200 series */ - { 0x04A6, "CY8C4245PVI-482", "SSOP-28", .flash_size_in_kb = 32 }, - { 0x04B6, "CY8C4245LQI-483", "QFN-40", .flash_size_in_kb = 32 }, - { 0x04C8, "CY8C4245AXI-483", "TQFP-44", .flash_size_in_kb = 32 }, - { 0x04FB, "CY8C4245AXI-473", "TQFP-44", .flash_size_in_kb = 32 }, - { 0x04F0, "CY8C4244PVI-432", "SSOP-28", .flash_size_in_kb = 16 }, - { 0x04F1, "CY8C4244PVI-442", "SSOP-28", .flash_size_in_kb = 16 }, - { 0x04F6, "CY8C4244LQI-443", "QFN-40", .flash_size_in_kb = 16 }, - { 0x04FA, "CY8C4244AXI-443", "TQFP-44", .flash_size_in_kb = 16 }, - - /* 4100 series */ - { 0x0410, "CY8C4124PVI-432", "SSOP-28", .flash_size_in_kb = 16 }, - { 0x0411, "CY8C4124PVI-442", "SSOP-28", .flash_size_in_kb = 16 }, - { 0x041C, "CY8C4124LQI-443", "QFN-40", .flash_size_in_kb = 16 }, - { 0x041A, "CY8C4124AXI-443", "TQFP-44", .flash_size_in_kb = 16 }, - { 0x041B, "CY8C4125AXI-473", "TQFP-44", .flash_size_in_kb = 32 }, - { 0x0412, "CY8C4125PVI-482", "SSOP-28", .flash_size_in_kb = 32 }, - { 0x0417, "CY8C4125LQI-483", "QFN-40", .flash_size_in_kb = 32 }, - { 0x0416, "CY8C4125AXI-483", "TQFP-44", .flash_size_in_kb = 32 }, - - /* CCG1 series */ - { 0x0490, "CYPD1103-35FNXI", "CSP-35", .flash_size_in_kb = 32 }, - { 0x0489, "CYPD1121-40LQXI", "QFN-40", .flash_size_in_kb = 32 }, - { 0x048A, "CYPD1122-40LQXI", "QFN-40", .flash_size_in_kb = 32 }, - { 0x0491, "CYPD1131-35FNXI", "CSP-35", .flash_size_in_kb = 32 }, - { 0x0498, "CYPD1132-16SXI", "SOIC-16", .flash_size_in_kb = 32 }, - { 0x0481, "CYPD1134-28PVXI", "SSOP-28", .flash_size_in_kb = 32 }, - { 0x048B, "CYPD1134-40LQXI", "QFN-40", .flash_size_in_kb = 32 }, +const struct psoc4_chip_family psoc4_families[] = { + { 0x93, "PSoC4100/4200", .flags = PSOC4_FAMILY_FLAG_LEGACY }, + { 0x9A, "PSoC4000", .flags = 0 }, + { 0x9E, "PSoC/PRoC BLE (119E)", .flags = 0 }, + { 0xA0, "PSoC4200L", .flags = 0 }, + { 0xA1, "PSoC4100M/4200M", .flags = 0 }, + { 0xA3, "PSoC/PRoC BLE (11A3)", .flags = 0 }, + { 0xA9, "PSoC4000S", .flags = 0 }, + { 0xAA, "PSoC/PRoC BLE (11AA)", .flags = 0 }, + { 0xAB, "PSoC4100S", .flags = 0 }, + { 0xAC, "PSoC Analog Coprocessor", .flags = 0 }, + { 0, "Unknown", .flags = 0 } }; struct psoc4_flash_bank { uint32_t row_size; uint32_t user_bank_size; - int probed; - uint32_t silicon_id; - uint8_t chip_protection; + int num_macros; + bool probed; uint8_t cmd_program_row; + uint16_t family_id; + bool legacy_family; + uint32_t cpuss_sysreq_addr; + uint32_t cpuss_sysarg_addr; + uint32_t spcif_geometry_addr; }; -static const struct psoc4_chip_details *psoc4_details_by_id(uint32_t silicon_id) +static const struct psoc4_chip_family *psoc4_family_by_id(uint16_t family_id) { - const struct psoc4_chip_details *p = psoc4_devices; - unsigned int i; - uint16_t id = silicon_id >> 16; /* ignore die revision */ - for (i = 0; i < sizeof(psoc4_devices)/sizeof(psoc4_devices[0]); i++, p++) { - if (p->id == id) - return p; - } - LOG_DEBUG("Unknown PSoC 4 device silicon id 0x%08" PRIx32 ".", silicon_id); - return NULL; + const struct psoc4_chip_family *p = psoc4_families; + while (p->id && p->id != family_id) + p++; + + return p; } static const char *psoc4_decode_chip_protection(uint8_t protection) @@ -176,7 +207,9 @@ FLASH_BANK_COMMAND_HANDLER(psoc4_flash_bank_command) psoc4_info = calloc(1, sizeof(struct psoc4_flash_bank)); bank->driver_priv = psoc4_info; + bank->default_padded_value = bank->erased_value = 0x00; psoc4_info->user_bank_size = bank->size; + psoc4_info->cmd_program_row = PSOC4_CMD_WRITE_ROW; return ERROR_OK; } @@ -189,9 +222,14 @@ FLASH_BANK_COMMAND_HANDLER(psoc4_flash_bank_command) * Otherwise address of memory parameter block is set in CPUSS_SYSARG * and the first parameter is written to the first word of parameter block */ -static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param, - uint32_t *sysreq_params, uint32_t sysreq_params_size) +static int psoc4_sysreq(struct flash_bank *bank, uint8_t cmd, + uint16_t cmd_param, + uint32_t *sysreq_params, uint32_t sysreq_params_size, + uint32_t *sysarg_out) { + struct target *target = bank->target; + struct psoc4_flash_bank *psoc4_info = bank->driver_priv; + struct working_area *sysreq_wait_algorithm; struct working_area *sysreq_mem; @@ -212,8 +250,8 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param, const int code_words = (sizeof(psoc4_sysreq_wait_code) + 3) / 4; /* stack must be aligned */ - const int stack_size = 196; - /* tested stack sizes on PSoC 4: + const int stack_size = 256; + /* tested stack sizes on PSoC4200: ERASE_ALL 144 PROGRAM_ROW 112 other sysreq 68 @@ -238,6 +276,8 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param, } if (sysreq_params_size) { + LOG_DEBUG("SYSREQ %02" PRIx8 " %04" PRIx16 " %08" PRIx32 " size %" PRIu32, + cmd, cmd_param, param1, sysreq_params_size); /* Allocate memory for sysreq_params */ retval = target_alloc_working_area(target, sysreq_params_size, &sysreq_mem); if (retval != ERROR_OK) { @@ -250,21 +290,23 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param, } /* Write sysreq_params */ - sysreq_params[0] = param1; + target_buffer_set_u32(target, (uint8_t *)sysreq_params, param1); retval = target_write_buffer(target, sysreq_mem->address, sysreq_params_size, (uint8_t *)sysreq_params); if (retval != ERROR_OK) goto cleanup_mem; /* Set address of sysreq parameters block */ - retval = target_write_u32(target, PSOC4_CPUSS_SYSARG, sysreq_mem->address); + retval = target_write_u32(target, psoc4_info->cpuss_sysarg_addr, sysreq_mem->address); if (retval != ERROR_OK) goto cleanup_mem; } else { /* Sysreq without memory block of parameters */ + LOG_DEBUG("SYSREQ %02" PRIx8 " %04" PRIx16 " %08" PRIx32, + cmd, cmd_param, param1); /* Set register parameter */ - retval = target_write_u32(target, PSOC4_CPUSS_SYSARG, param1); + retval = target_write_u32(target, psoc4_info->cpuss_sysarg_addr, param1); if (retval != ERROR_OK) goto cleanup_mem; } @@ -279,14 +321,14 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param, struct armv7m_common *armv7m = target_to_armv7m(target); if (armv7m == NULL) { - /* something is very wrong if armv7m is NULL */ LOG_ERROR("unable to get armv7m target"); + retval = ERROR_FAIL; goto cleanup; } /* Set SROM request */ - retval = target_write_u32(target, PSOC4_CPUSS_SYSREQ, + retval = target_write_u32(target, psoc4_info->cpuss_sysreq_addr, PSOC4_SROM_SYSREQ_BIT | PSOC4_SROM_HMASTER_BIT | cmd); if (retval != ERROR_OK) goto cleanup; @@ -295,9 +337,23 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param, retval = target_run_algorithm(target, 0, NULL, sizeof(reg_params) / sizeof(*reg_params), reg_params, sysreq_wait_algorithm->address, 0, 1000, &armv7m_info); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { LOG_ERROR("sysreq wait code execution failed"); + goto cleanup; + } + uint32_t sysarg_out_tmp; + retval = target_read_u32(target, psoc4_info->cpuss_sysarg_addr, &sysarg_out_tmp); + if (retval != ERROR_OK) + goto cleanup; + + if (sysarg_out) { + *sysarg_out = sysarg_out_tmp; + /* If result is an error, do not show now, let caller to decide */ + } else if ((sysarg_out_tmp & PSOC4_SROM_STATUS_MASK) != PSOC4_SROM_STATUS_SUCCEEDED) { + LOG_ERROR("sysreq error 0x%" PRIx32, sysarg_out_tmp); + retval = ERROR_FAIL; + } cleanup: destroy_reg_param(®_params[0]); @@ -313,42 +369,123 @@ cleanup_algo: /* helper routine to get silicon ID from a PSoC 4 chip */ -static int psoc4_get_silicon_id(struct target *target, uint32_t *silicon_id, uint8_t *protection) +static int psoc4_get_silicon_id(struct flash_bank *bank, uint32_t *silicon_id, uint16_t *family_id, uint8_t *protection) { - uint32_t params = PSOC4_SROM_KEY1 - | ((PSOC4_SROM_KEY2 + PSOC4_CMD_GET_SILICON_ID) << 8); + struct target *target = bank->target; + struct psoc4_flash_bank *psoc4_info = bank->driver_priv; + uint32_t part0, part1; - int retval = psoc4_sysreq(target, PSOC4_CMD_GET_SILICON_ID, 0, NULL, 0); + int retval = psoc4_sysreq(bank, PSOC4_CMD_GET_SILICON_ID, 0, NULL, 0, &part0); if (retval != ERROR_OK) return retval; - retval = target_read_u32(target, PSOC4_CPUSS_SYSARG, &part0); - if (retval != ERROR_OK) - return retval; - - if (part0 == params) { - LOG_ERROR("sysreq silicon id request not served"); + if ((part0 & PSOC4_SROM_STATUS_MASK) != PSOC4_SROM_STATUS_SUCCEEDED) { + LOG_ERROR("sysreq error 0x%" PRIx32, part0); return ERROR_FAIL; } - retval = target_read_u32(target, PSOC4_CPUSS_SYSREQ, &part1); + retval = target_read_u32(target, psoc4_info->cpuss_sysreq_addr, &part1); if (retval != ERROR_OK) return retval; - uint32_t silicon = ((part0 & 0xffff) << 16) - | (((part0 >> 16) & 0xff) << 8) - | (part1 & 0xff); - uint8_t prot = (part1 >> 12) & 0xff; - + /* build ID as Cypress sw does: + * bit 31..16 silicon ID + * bit 15..8 revision ID (so far 0x11 for all devices) + * bit 7..0 family ID (lowes 8 bits) + */ if (silicon_id) - *silicon_id = silicon; - if (protection) - *protection = prot; + *silicon_id = ((part0 & 0x0000ffff) << 16) + | ((part0 & 0x00ff0000) >> 8) + | (part1 & 0x000000ff); - LOG_DEBUG("silicon id: 0x%08" PRIx32 "", silicon); - LOG_DEBUG("protection: 0x%02" PRIx8 "", prot); - return retval; + if (family_id) + *family_id = part1 & 0x0fff; + + if (protection) + *protection = (part1 >> 12) & 0x0f; + + return ERROR_OK; +} + + +static int psoc4_get_family(struct target *target, uint16_t *family_id) +{ + int retval, i; + uint32_t pidbf[3]; + uint8_t pid[3]; + + retval = target_read_memory(target, PSOC4_ROMTABLE_PID0, 4, 3, (uint8_t *)pidbf); + if (retval != ERROR_OK) + return retval; + + for (i = 0; i < 3; i++) { + uint32_t tmp = target_buffer_get_u32(target, (uint8_t *)(pidbf + i)); + if (tmp & 0xffffff00) { + LOG_ERROR("Unexpected data in ROMTABLE"); + return ERROR_FAIL; + } + pid[i] = tmp & 0xff; + } + + uint16_t family = pid[0] | ((pid[1] & 0xf) << 8); + uint32_t designer = ((pid[1] & 0xf0) >> 4) | ((pid[2] & 0xf) << 4); + + if (designer != PSOC4_ROMTABLE_DESIGNER_CHECK) { + LOG_ERROR("ROMTABLE designer is not Cypress"); + return ERROR_FAIL; + } + + *family_id = family; + return ERROR_OK; +} + + +static int psoc4_flash_prepare(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct psoc4_flash_bank *psoc4_info = bank->driver_priv; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + uint16_t family_id; + int retval; + + /* get family ID from SROM call */ + retval = psoc4_get_silicon_id(bank, NULL, &family_id, NULL); + if (retval != ERROR_OK) + return retval; + + /* and check with family ID from ROMTABLE */ + if (family_id != psoc4_info->family_id) { + LOG_ERROR("Family mismatch"); + return ERROR_FAIL; + } + + if (!psoc4_info->legacy_family) { + uint32_t sysreq_status; + retval = psoc4_sysreq(bank, PSOC4_CMD_SET_IMO48, 0, NULL, 0, &sysreq_status); + if (retval != ERROR_OK) + return retval; + + if ((sysreq_status & PSOC4_SROM_STATUS_MASK) != PSOC4_SROM_STATUS_SUCCEEDED) { + /* This undocumented error code is returned probably when + * PSOC4_CMD_SET_IMO48 command is not implemented. + * Can be safely ignored, programming works. + */ + if (sysreq_status == PSOC4_SROM_ERR_IMO_NOT_IMPLEM) + LOG_INFO("PSOC4_CMD_SET_IMO48 is not implemented on this device."); + else { + LOG_ERROR("sysreq error 0x%" PRIx32, sysreq_status); + return ERROR_FAIL; + } + } + } + + return ERROR_OK; } @@ -357,48 +494,37 @@ static int psoc4_protect_check(struct flash_bank *bank) struct target *target = bank->target; struct psoc4_flash_bank *psoc4_info = bank->driver_priv; - uint32_t prot_addr = PSOC4_SFLASH_MACRO; - uint32_t protection; - int i, s; - int num_bits; - int retval = ERROR_OK; + uint32_t prot_addr = PSOC4_SFLASH_MACRO0; + int retval; + int s = 0; + int m, i; + uint8_t bf[PSOC4_ROWS_PER_MACRO/8]; - num_bits = bank->num_sectors; - - for (i = 0; i < num_bits; i += 32) { - retval = target_read_u32(target, prot_addr, &protection); + for (m = 0; m < psoc4_info->num_macros; m++, prot_addr += PSOC4_SFLASH_MACRO_SIZE) { + retval = target_read_memory(target, prot_addr, 4, PSOC4_ROWS_PER_MACRO/32, bf); if (retval != ERROR_OK) return retval; - prot_addr += 4; - - for (s = 0; s < 32; s++) { - if (i + s >= num_bits) - break; - bank->sectors[i + s].is_protected = (protection & (1 << s)) ? 1 : 0; - } + for (i = 0; i < PSOC4_ROWS_PER_MACRO && s < bank->num_sectors; i++, s++) + bank->sectors[s].is_protected = bf[i/8] & (1 << (i%8)) ? 1 : 0; } - retval = psoc4_get_silicon_id(target, NULL, &(psoc4_info->chip_protection)); - return retval; + return ERROR_OK; } static int psoc4_mass_erase(struct flash_bank *bank) { - struct target *target = bank->target; int i; - - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } + int retval = psoc4_flash_prepare(bank); + if (retval != ERROR_OK) + return retval; /* Call "Erase All" system ROM API */ - uint32_t param; - int retval = psoc4_sysreq(target, PSOC4_CMD_ERASE_ALL, + uint32_t param = 0; + retval = psoc4_sysreq(bank, PSOC4_CMD_ERASE_ALL, 0, - ¶m, sizeof(param)); + ¶m, sizeof(param), NULL); if (retval == ERROR_OK) /* set all sectors as erased */ @@ -420,7 +546,7 @@ static int psoc4_erase(struct flash_bank *bank, int first, int last) if ((first == 0) && (last == (bank->num_sectors - 1))) return psoc4_mass_erase(bank); - LOG_ERROR("Only mass erase available"); + LOG_ERROR("Only mass erase available! Consider using 'psoc4 flash_autoerase 0 on'"); return ERROR_FAIL; } @@ -431,56 +557,63 @@ static int psoc4_protect(struct flash_bank *bank, int set, int first, int last) struct target *target = bank->target; struct psoc4_flash_bank *psoc4_info = bank->driver_priv; - if (psoc4_info->probed == 0) + if (!psoc4_info->probed) return ERROR_FAIL; - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } + int retval = psoc4_flash_prepare(bank); + if (retval != ERROR_OK) + return retval; uint32_t *sysrq_buffer = NULL; - int retval; - int num_bits = bank->num_sectors; const int param_sz = 8; - int prot_sz = num_bits / 8; int chip_prot = PSOC4_CHIP_PROT_OPEN; - int flash_macro = 0; /* PSoC 42xx has only macro 0 */ - int i; + int i, m, sect; + int num_bits = bank->num_sectors; - sysrq_buffer = calloc(1, param_sz + prot_sz); + if (num_bits > PSOC4_ROWS_PER_MACRO) + num_bits = PSOC4_ROWS_PER_MACRO; + + int prot_sz = num_bits / 8; + + sysrq_buffer = malloc(param_sz + prot_sz); if (sysrq_buffer == NULL) { LOG_ERROR("no memory for row buffer"); return ERROR_FAIL; } - for (i = first; i < num_bits && i <= last; i++) + for (i = first; i <= last && i < bank->num_sectors; i++) bank->sectors[i].is_protected = set; - uint32_t *p = sysrq_buffer + 2; - for (i = 0; i < num_bits; i++) { - if (bank->sectors[i].is_protected) - p[i / 32] |= 1 << (i % 32); + for (m = 0, sect = 0; m < psoc4_info->num_macros; m++) { + uint8_t *p = (uint8_t *)(sysrq_buffer + 2); + memset(p, 0, prot_sz); + for (i = 0; i < num_bits && sect < bank->num_sectors; i++, sect++) { + if (bank->sectors[sect].is_protected) + p[i/8] |= 1 << (i%8); + } + + /* Call "Load Latch" system ROM API */ + target_buffer_set_u32(target, (uint8_t *)(sysrq_buffer + 1), + prot_sz - 1); + retval = psoc4_sysreq(bank, PSOC4_CMD_LOAD_LATCH, + 0 /* Byte number in latch from what to write */ + | (m << 8), /* flash macro index */ + sysrq_buffer, param_sz + prot_sz, + NULL); + if (retval != ERROR_OK) + break; + + /* Call "Write Protection" system ROM API */ + retval = psoc4_sysreq(bank, PSOC4_CMD_WRITE_PROTECTION, + chip_prot | (m << 8), NULL, 0, NULL); + if (retval != ERROR_OK) + break; } - /* Call "Load Latch" system ROM API */ - sysrq_buffer[1] = prot_sz - 1; - retval = psoc4_sysreq(target, PSOC4_CMD_LOAD_LATCH, - 0, /* Byte number in latch from what to write */ - sysrq_buffer, param_sz + psoc4_info->row_size); - if (retval != ERROR_OK) - goto cleanup; - - /* Call "Write Protection" system ROM API */ - retval = psoc4_sysreq(target, PSOC4_CMD_WRITE_PROTECTION, - chip_prot | (flash_macro << 8), NULL, 0); -cleanup: - if (retval != ERROR_OK) - psoc4_protect_check(bank); - if (sysrq_buffer) free(sysrq_buffer); + psoc4_protect_check(bank); return retval; } @@ -516,21 +649,14 @@ COMMAND_HANDLER(psoc4_handle_flash_autoerase_command) static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { - struct psoc4_flash_bank *psoc4_info = bank->driver_priv; struct target *target = bank->target; + struct psoc4_flash_bank *psoc4_info = bank->driver_priv; uint32_t *sysrq_buffer = NULL; - int retval = ERROR_OK; const int param_sz = 8; - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (offset & 0x1) { - LOG_ERROR("offset 0x%08" PRIx32 " breaks required 2-byte alignment", offset); - return ERROR_FLASH_DST_BREAKS_ALIGNMENT; - } + int retval = psoc4_flash_prepare(bank); + if (retval != ERROR_OK) + return retval; sysrq_buffer = malloc(param_sz + psoc4_info->row_size); if (sysrq_buffer == NULL) { @@ -542,7 +668,7 @@ static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t row_num = offset / psoc4_info->row_size; uint32_t row_offset = offset - row_num * psoc4_info->row_size; if (row_offset) - memset(row_buffer, 0, row_offset); + memset(row_buffer, bank->default_padded_value, row_offset); bool save_poll = jtag_poll_get_enabled(); jtag_poll_set_enabled(false); @@ -551,25 +677,31 @@ static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t chunk_size = psoc4_info->row_size - row_offset; if (chunk_size > count) { chunk_size = count; - memset(row_buffer + chunk_size, 0, psoc4_info->row_size - chunk_size); + memset(row_buffer + chunk_size, bank->default_padded_value, psoc4_info->row_size - chunk_size); } memcpy(row_buffer + row_offset, buffer, chunk_size); LOG_DEBUG("offset / row: 0x%08" PRIx32 " / %" PRIu32 ", size %" PRIu32 "", offset, row_offset, chunk_size); + uint32_t macro_idx = row_num / PSOC4_ROWS_PER_MACRO; + /* Call "Load Latch" system ROM API */ - sysrq_buffer[1] = psoc4_info->row_size - 1; - retval = psoc4_sysreq(target, PSOC4_CMD_LOAD_LATCH, - 0, /* Byte number in latch from what to write */ - sysrq_buffer, param_sz + psoc4_info->row_size); + target_buffer_set_u32(target, (uint8_t *)(sysrq_buffer + 1), + psoc4_info->row_size - 1); + retval = psoc4_sysreq(bank, PSOC4_CMD_LOAD_LATCH, + 0 /* Byte number in latch from what to write */ + | (macro_idx << 8), + sysrq_buffer, param_sz + psoc4_info->row_size, + NULL); if (retval != ERROR_OK) goto cleanup; /* Call "Program Row" or "Write Row" system ROM API */ uint32_t sysrq_param; - retval = psoc4_sysreq(target, psoc4_info->cmd_program_row, + retval = psoc4_sysreq(bank, psoc4_info->cmd_program_row, row_num & 0xffff, - &sysrq_param, sizeof(sysrq_param)); + &sysrq_param, sizeof(sysrq_param), + NULL); if (retval != ERROR_OK) goto cleanup; @@ -589,84 +721,82 @@ cleanup: } +/* Due to Cypress's method of market segmentation some devices + * have accessible only 1/2, 1/4 or 1/8 of SPCIF described flash */ +static int psoc4_test_flash_wounding(struct target *target, uint32_t flash_size) +{ + int retval, i; + for (i = 3; i >= 1; i--) { + uint32_t addr = flash_size >> i; + uint32_t dummy; + retval = target_read_u32(target, addr, &dummy); + if (retval != ERROR_OK) + return i; + } + return 0; +} + + static int psoc4_probe(struct flash_bank *bank) { struct psoc4_flash_bank *psoc4_info = bank->driver_priv; struct target *target = bank->target; - uint32_t flash_size_in_kb = 0; - uint32_t max_flash_size_in_kb; - uint32_t cpu_id; - uint32_t silicon_id; - uint32_t row_size; - uint32_t base_address = 0x00000000; - uint8_t protection; - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } + int retval; + uint16_t family_id; - psoc4_info->probed = 0; - psoc4_info->cmd_program_row = PSOC4_CMD_PROGRAM_ROW; + psoc4_info->probed = false; - /* Get the CPUID from the ARM Core - * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0432c/DDI0432C_cortex_m0_r0p0_trm.pdf 4.2.1 */ - int retval = target_read_u32(target, 0xE000ED00, &cpu_id); + retval = psoc4_get_family(target, &family_id); if (retval != ERROR_OK) return retval; - LOG_DEBUG("cpu id = 0x%08" PRIx32 "", cpu_id); + const struct psoc4_chip_family *family = psoc4_family_by_id(family_id); - /* set page size, protection granularity and max flash size depending on family */ - switch ((cpu_id >> 4) & 0xFFF) { - case 0xc20: /* M0 -> PSoC4 */ - row_size = 128; - max_flash_size_in_kb = 32; - break; - default: - LOG_WARNING("Cannot identify target as a PSoC 4 family."); + if (family->id == 0) { + LOG_ERROR("Cannot identify PSoC 4 family."); return ERROR_FAIL; } - uint32_t spcif_geometry; - retval = target_read_u32(target, PSOC4_SPCIF_GEOMETRY, &spcif_geometry); - if (retval == ERROR_OK) { - row_size = 128 * ((spcif_geometry >> 22) & 3); - flash_size_in_kb = (spcif_geometry & 0xffff) * 256 / 1024; - LOG_INFO("SPCIF geometry: %" PRIu32 " kb flash, row %" PRIu32 " bytes.", - flash_size_in_kb, row_size); + if (family->flags & PSOC4_FAMILY_FLAG_LEGACY) { + LOG_INFO("%s legacy family detected.", family->name); + psoc4_info->legacy_family = true; + psoc4_info->cpuss_sysreq_addr = PSOC4_CPUSS_SYSREQ_LEGACY; + psoc4_info->cpuss_sysarg_addr = PSOC4_CPUSS_SYSARG_LEGACY; + psoc4_info->spcif_geometry_addr = PSOC4_SPCIF_GEOMETRY_LEGACY; + } else { + LOG_INFO("%s family detected.", family->name); + psoc4_info->legacy_family = false; + psoc4_info->cpuss_sysreq_addr = PSOC4_CPUSS_SYSREQ_NEW; + psoc4_info->cpuss_sysarg_addr = PSOC4_CPUSS_SYSARG_NEW; + psoc4_info->spcif_geometry_addr = PSOC4_SPCIF_GEOMETRY_NEW; } - /* Early revisions of ST-Link v2 have some problem reading PSOC4_SPCIF_GEOMETRY - and an error is reported late. Dummy read gets this error. */ - uint32_t dummy; - target_read_u32(target, PSOC4_CPUSS_SYSREQ, &dummy); - - /* get silicon ID from target. */ - retval = psoc4_get_silicon_id(target, &silicon_id, &protection); + uint32_t spcif_geometry; + retval = target_read_u32(target, psoc4_info->spcif_geometry_addr, &spcif_geometry); if (retval != ERROR_OK) return retval; - const struct psoc4_chip_details *details = psoc4_details_by_id(silicon_id); - if (details) { - LOG_INFO("%s device detected.", details->type); - if (flash_size_in_kb == 0) - flash_size_in_kb = details->flash_size_in_kb; - else if (flash_size_in_kb != details->flash_size_in_kb) - LOG_ERROR("Flash size mismatch"); + uint32_t flash_size_in_kb = spcif_geometry & 0x3fff; + /* TRM of legacy, M and L version describes FLASH field as 16-bit. + * S-series and PSoC Analog Coprocessor changes spec to 14-bit only. + * Impose PSoC Analog Coprocessor limit to all devices as it + * does not make any harm: flash size is safely below 4 MByte limit + */ + uint32_t row_size = (spcif_geometry >> 22) & 3; + uint32_t num_macros = (spcif_geometry >> 20) & 3; + + if (psoc4_info->legacy_family) { + flash_size_in_kb = flash_size_in_kb * 256 / 1024; + row_size *= 128; + } else { + flash_size_in_kb = (flash_size_in_kb + 1) * 256 / 1024; + row_size = 64 * (row_size + 1); + num_macros++; } - psoc4_info->row_size = row_size; - psoc4_info->silicon_id = silicon_id; - psoc4_info->chip_protection = protection; - - /* failed reading flash size or flash size invalid (early silicon), - * default to max target family */ - if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) { - LOG_WARNING("PSoC 4 flash size failed, probe inaccurate - assuming %" PRIu32 " k flash", - max_flash_size_in_kb); - flash_size_in_kb = max_flash_size_in_kb; - } + LOG_DEBUG("SPCIF geometry: %" PRIu32 " kb flash, row %" PRIu32 " bytes.", + flash_size_in_kb, row_size); /* if the user sets the size manually then ignore the probed value * this allows us to work around devices that have a invalid flash size register value */ @@ -675,37 +805,44 @@ static int psoc4_probe(struct flash_bank *bank) flash_size_in_kb = psoc4_info->user_bank_size / 1024; } - LOG_INFO("flash size = %" PRIu32 " kbytes", flash_size_in_kb); + char macros_txt[20] = ""; + if (num_macros > 1) + snprintf(macros_txt, sizeof(macros_txt), " in %" PRIu32 " macros", num_macros); - /* did we assign flash size? */ - assert(flash_size_in_kb != 0xffff); + LOG_INFO("flash size = %" PRIu32 " kbytes%s", flash_size_in_kb, macros_txt); - /* calculate numbers of pages */ + /* calculate number of pages */ uint32_t num_rows = flash_size_in_kb * 1024 / row_size; - /* check that calculation result makes sense */ - assert(num_rows > 0); + /* check number of flash macros */ + if (num_macros != (num_rows + PSOC4_ROWS_PER_MACRO - 1) / PSOC4_ROWS_PER_MACRO) + LOG_WARNING("Number of macros does not correspond with flash size!"); + + if (!psoc4_info->legacy_family) { + int wounding = psoc4_test_flash_wounding(target, num_rows * row_size); + if (wounding > 0) { + flash_size_in_kb = flash_size_in_kb >> wounding; + num_rows = num_rows >> wounding; + LOG_INFO("WOUNDING detected: accessible flash size %" PRIu32 " kbytes", flash_size_in_kb); + } + } if (bank->sectors) { free(bank->sectors); - bank->sectors = NULL; } - bank->base = base_address; + psoc4_info->family_id = family_id; + psoc4_info->num_macros = num_macros; + psoc4_info->row_size = row_size; + bank->base = 0x00000000; bank->size = num_rows * row_size; bank->num_sectors = num_rows; - bank->sectors = malloc(sizeof(struct flash_sector) * num_rows); + bank->sectors = alloc_block_array(0, row_size, num_rows); + if (bank->sectors == NULL) + return ERROR_FAIL; - uint32_t i; - for (i = 0; i < num_rows; i++) { - bank->sectors[i].offset = i * row_size; - bank->sectors[i].size = row_size; - bank->sectors[i].is_erased = -1; - bank->sectors[i].is_protected = 1; - } - - LOG_INFO("flash bank set %" PRIu32 " rows", num_rows); - psoc4_info->probed = 1; + LOG_DEBUG("flash bank set %" PRIu32 " rows", num_rows); + psoc4_info->probed = true; return ERROR_OK; } @@ -721,28 +858,45 @@ static int psoc4_auto_probe(struct flash_bank *bank) static int get_psoc4_info(struct flash_bank *bank, char *buf, int buf_size) { + struct target *target = bank->target; struct psoc4_flash_bank *psoc4_info = bank->driver_priv; - int printed = 0; - if (psoc4_info->probed == 0) + if (!psoc4_info->probed) return ERROR_FAIL; - const struct psoc4_chip_details *details = psoc4_details_by_id(psoc4_info->silicon_id); + const struct psoc4_chip_family *family = psoc4_family_by_id(psoc4_info->family_id); + uint32_t size_in_kb = bank->size / 1024; - if (details) { - uint32_t chip_revision = psoc4_info->silicon_id & 0xffff; - printed = snprintf(buf, buf_size, "PSoC 4 %s rev 0x%04" PRIx32 " package %s", - details->type, chip_revision, details->package); - } else - printed = snprintf(buf, buf_size, "PSoC 4 silicon id 0x%08" PRIx32 "", - psoc4_info->silicon_id); + if (target->state != TARGET_HALTED) { + snprintf(buf, buf_size, "%s, flash %" PRIu32 " kb" + " (halt target to see details)", family->name, size_in_kb); + return ERROR_OK; + } + + int retval; + int printed = 0; + uint32_t silicon_id; + uint16_t family_id; + uint8_t protection; + + retval = psoc4_get_silicon_id(bank, &silicon_id, &family_id, &protection); + if (retval != ERROR_OK) + return retval; + + if (family_id != psoc4_info->family_id) + printed = snprintf(buf, buf_size, "Family id mismatch 0x%02" PRIx16 + "/0x%02" PRIx16 ", silicon id 0x%08" PRIx32, + psoc4_info->family_id, family_id, silicon_id); + else { + printed = snprintf(buf, buf_size, "%s silicon id 0x%08" PRIx32 "", + family->name, silicon_id); + } buf += printed; buf_size -= printed; - const char *prot_txt = psoc4_decode_chip_protection(psoc4_info->chip_protection); - uint32_t size_in_kb = bank->size / 1024; - snprintf(buf, buf_size, " flash %" PRIu32 " kb %s", size_in_kb, prot_txt); + const char *prot_txt = psoc4_decode_chip_protection(protection); + snprintf(buf, buf_size, ", flash %" PRIu32 " kb %s", size_in_kb, prot_txt); return ERROR_OK; } @@ -809,4 +963,5 @@ struct flash_driver psoc4_flash = { .erase_check = default_flash_blank_check, .protect_check = psoc4_protect_check, .info = get_psoc4_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c new file mode 100644 index 000000000..e5c419764 --- /dev/null +++ b/src/flash/nor/psoc6.c @@ -0,0 +1,986 @@ +/*************************************************************************** + * * + * Copyright (C) 2017 by Bohdan Tymkiv * + * bohdan.tymkiv@cypress.com bohdan200@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "imp.h" +#include "target/target.h" +#include "target/cortex_m.h" +#include "target/breakpoints.h" +#include "target/target_type.h" +#include "time_support.h" +#include "target/algorithm.h" + +/************************************************************************************************** + * PSoC6 device definitions + *************************************************************************************************/ +#define MFLASH_SECTOR_SIZE (256u * 1024u) +#define WFLASH_SECTOR_SIZE (32u * 1024u) + +#define MEM_BASE_MFLASH 0x10000000u +#define MEM_BASE_WFLASH 0x14000000u +#define MEM_WFLASH_SIZE 32768u +#define MEM_BASE_SFLASH 0x16000000u +#define RAM_STACK_WA_SIZE 2048u +#define PSOC6_SPCIF_GEOMETRY 0x4025F00Cu + +#define PROTECTION_UNKNOWN 0x00u +#define PROTECTION_VIRGIN 0x01u +#define PROTECTION_NORMAL 0x02u +#define PROTECTION_SECURE 0x03u +#define PROTECTION_DEAD 0x04u + +#define MEM_BASE_IPC 0x40230000u +#define IPC_STRUCT_SIZE 0x20u +#define MEM_IPC(n) (MEM_BASE_IPC + (n) * IPC_STRUCT_SIZE) +#define MEM_IPC_ACQUIRE(n) (MEM_IPC(n) + 0x00u) +#define MEM_IPC_NOTIFY(n) (MEM_IPC(n) + 0x08u) +#define MEM_IPC_DATA(n) (MEM_IPC(n) + 0x0Cu) +#define MEM_IPC_LOCK_STATUS(n) (MEM_IPC(n) + 0x10u) + +#define MEM_BASE_IPC_INTR 0x40231000u +#define IPC_INTR_STRUCT_SIZE 0x20u +#define MEM_IPC_INTR(n) (MEM_BASE_IPC_INTR + (n) * IPC_INTR_STRUCT_SIZE) +#define MEM_IPC_INTR_MASK(n) (MEM_IPC_INTR(n) + 0x08u) +#define IPC_ACQUIRE_SUCCESS_MSK 0x80000000u +#define IPC_LOCK_ACQUIRED_MSK 0x80000000u + +#define IPC_ID 2u +#define IPC_INTR_ID 0u +#define IPC_TIMEOUT_MS 1000 + +#define SROMAPI_SIID_REQ 0x00000001u +#define SROMAPI_SIID_REQ_FAMILY_REVISION (SROMAPI_SIID_REQ | 0x000u) +#define SROMAPI_SIID_REQ_SIID_PROTECTION (SROMAPI_SIID_REQ | 0x100u) +#define SROMAPI_WRITEROW_REQ 0x05000100u +#define SROMAPI_PROGRAMROW_REQ 0x06000100u +#define SROMAPI_ERASESECTOR_REQ 0x14000100u +#define SROMAPI_ERASEALL_REQ 0x0A000100u +#define SROMAPI_ERASEROW_REQ 0x1C000100u + +#define SROMAPI_STATUS_MSK 0xF0000000u +#define SROMAPI_STAT_SUCCESS 0xA0000000u +#define SROMAPI_DATA_LOCATION_MSK 0x00000001u +#define SROMAPI_CALL_TIMEOUT_MS 1500 + +struct psoc6_target_info { + uint32_t silicon_id; + uint8_t protection; + uint32_t main_flash_sz; + uint32_t row_sz; + bool is_probed; +}; + +struct timeout { + int64_t start_time; + long timeout_ms; +}; + +struct row_region { + uint32_t addr; + size_t size; +}; + +static struct row_region safe_sflash_regions[] = { + {0x16000800, 0x800}, /* SFLASH: User Data */ + {0x16001A00, 0x200}, /* SFLASH: NAR */ + {0x16005A00, 0xC00}, /* SFLASH: Public Key */ + {0x16007C00, 0x400}, /* SFLASH: TOC2 */ +}; + +#define SFLASH_NUM_REGIONS (sizeof(safe_sflash_regions) / sizeof(safe_sflash_regions[0])) + +static struct working_area *g_stack_area; +/************************************************************************************************** + * Initializes timeout_s structure with given timeout in milliseconds + *************************************************************************************************/ +static void timeout_init(struct timeout *to, long timeout_ms) +{ + to->start_time = timeval_ms(); + to->timeout_ms = timeout_ms; +} + +/************************************************************************************************** + * Returns true if given timeout_s object has expired + *************************************************************************************************/ +static bool timeout_expired(struct timeout *to) +{ + return (timeval_ms() - to->start_time) > to->timeout_ms; +} + +/************************************************************************************************** + * Prepares PSoC6 for running pseudo flash algorithm. This function allocates Working Area for + * the algorithm and for CPU Stack. + *************************************************************************************************/ +static int sromalgo_prepare(struct target *target) +{ + int hr; + + /* Initialize Vector Table Offset register (in case FW modified it) */ + hr = target_write_u32(target, 0xE000ED08, 0x00000000); + if (hr != ERROR_OK) + return hr; + + /* Allocate Working Area for Stack and Flash algorithm */ + hr = target_alloc_working_area(target, RAM_STACK_WA_SIZE, &g_stack_area); + if (hr != ERROR_OK) + return hr; + + /* Restore THUMB bit in xPSR register */ + const struct armv7m_common *cm = target_to_armv7m(target); + hr = cm->store_core_reg_u32(target, ARMV7M_xPSR, 0x01000000); + if (hr != ERROR_OK) + goto exit_free_wa; + + return ERROR_OK; + +exit_free_wa: + /* Something went wrong, free allocated area */ + if (g_stack_area) { + target_free_working_area(target, g_stack_area); + g_stack_area = NULL; + } + + return hr; +} + +/************************************************************************************************** + * Releases working area + *************************************************************************************************/ +static int sromalgo_release(struct target *target) +{ + int hr = ERROR_OK; + + /* Free Stack/Flash algorithm working area */ + if (g_stack_area) { + hr = target_free_working_area(target, g_stack_area); + g_stack_area = NULL; + } + + return hr; +} + +/************************************************************************************************** + * Runs pseudo flash algorithm. Algorithm itself consist of couple of NOPs followed by BKPT + * instruction. The trick here is that NMI has already been posted to CM0 via IPC structure + * prior to calling this function. CM0 will immediately jump to NMI handler and execute + * SROM API code. + * This approach is borrowed from PSoC4 Flash Driver. + *************************************************************************************************/ +static int sromalgo_run(struct target *target) +{ + int hr; + + struct armv7m_algorithm armv7m_info; + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + struct reg_param reg_params; + init_reg_param(®_params, "sp", 32, PARAM_OUT); + buf_set_u32(reg_params.value, 0, 32, g_stack_area->address + g_stack_area->size); + + /* mov r8, r8; mov r8, r8 */ + hr = target_write_u32(target, g_stack_area->address + 0, 0x46C046C0); + if (hr != ERROR_OK) + return hr; + + /* mov r8, r8; bkpt #0 */ + hr = target_write_u32(target, g_stack_area->address + 4, 0xBE0046C0); + if (hr != ERROR_OK) + return hr; + + hr = target_run_algorithm(target, 0, NULL, 1, ®_params, g_stack_area->address, + 0, SROMAPI_CALL_TIMEOUT_MS, &armv7m_info); + + destroy_reg_param(®_params); + + return hr; +} + +/************************************************************************************************** + * Waits for expected IPC lock status. + * PSoC6 uses IPC structures for inter-core communication. Same IPCs are used to invoke SROM API. + * IPC structure must be locked prior to invoking any SROM API. This ensures nothing else in the + * system will use same IPC thus corrupting our data. Locking is performed by ipc_acquire(), this + * function ensures that IPC is actually in expected state + *************************************************************************************************/ +static int ipc_poll_lock_stat(struct target *target, uint32_t ipc_id, bool lock_expected) +{ + int hr; + uint32_t reg_val; + + struct timeout to; + timeout_init(&to, IPC_TIMEOUT_MS); + + while (!timeout_expired(&to)) { + /* Process any server requests */ + keep_alive(); + + /* Read IPC Lock status */ + hr = target_read_u32(target, MEM_IPC_LOCK_STATUS(ipc_id), ®_val); + if (hr != ERROR_OK) { + LOG_ERROR("Unable to read IPC Lock Status register"); + return hr; + } + + bool is_locked = (reg_val & IPC_LOCK_ACQUIRED_MSK) != 0; + + if (lock_expected == is_locked) + return ERROR_OK; + } + + if (target->coreid) { + LOG_WARNING("SROM API calls via CM4 target are supported on single-core PSoC6 devices only. " + "Please perform all Flash-related operations via CM0+ target on dual-core devices."); + } + + LOG_ERROR("Timeout polling IPC Lock Status"); + return ERROR_TARGET_TIMEOUT; +} + +/************************************************************************************************** + * Acquires IPC structure + * PSoC6 uses IPC structures for inter-core communication. Same IPCs are used to invoke SROM API. + * IPC structure must be locked prior to invoking any SROM API. This ensures nothing else in the + * system will use same IPC thus corrupting our data. This function locks the IPC. + *************************************************************************************************/ +static int ipc_acquire(struct target *target, char ipc_id) +{ + int hr = ERROR_OK; + bool is_acquired = false; + uint32_t reg_val; + + struct timeout to; + timeout_init(&to, IPC_TIMEOUT_MS); + + while (!timeout_expired(&to)) { + keep_alive(); + + hr = target_write_u32(target, MEM_IPC_ACQUIRE(ipc_id), IPC_ACQUIRE_SUCCESS_MSK); + if (hr != ERROR_OK) { + LOG_ERROR("Unable to write to IPC Acquire register"); + return hr; + } + + /* Check if data is written on first step */ + hr = target_read_u32(target, MEM_IPC_ACQUIRE(ipc_id), ®_val); + if (hr != ERROR_OK) { + LOG_ERROR("Unable to read IPC Acquire register"); + return hr; + } + + is_acquired = (reg_val & IPC_ACQUIRE_SUCCESS_MSK) != 0; + if (is_acquired) { + /* If IPC structure is acquired, the lock status should be set */ + hr = ipc_poll_lock_stat(target, ipc_id, true); + break; + } + } + + if (!is_acquired) + LOG_ERROR("Timeout acquiring IPC structure"); + + return hr; +} + +/************************************************************************************************** + * Invokes SROM API functions which are responsible for Flash operations + *************************************************************************************************/ +static int call_sromapi(struct target *target, + uint32_t req_and_params, + uint32_t working_area, + uint32_t *data_out) +{ + int hr; + + bool is_data_in_ram = (req_and_params & SROMAPI_DATA_LOCATION_MSK) == 0; + + hr = ipc_acquire(target, IPC_ID); + if (hr != ERROR_OK) + return hr; + + if (is_data_in_ram) + hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), working_area); + else + hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), req_and_params); + + if (hr != ERROR_OK) + return hr; + + /* Enable notification interrupt of IPC_INTR_STRUCT0(CM0+) for IPC_STRUCT2 */ + hr = target_write_u32(target, MEM_IPC_INTR_MASK(IPC_INTR_ID), 1u << (16 + IPC_ID)); + if (hr != ERROR_OK) + return hr; + + hr = target_write_u32(target, MEM_IPC_NOTIFY(IPC_ID), 1); + if (hr != ERROR_OK) + return hr; + + hr = sromalgo_run(target); + if (hr != ERROR_OK) + return hr; + + /* Poll lock status */ + hr = ipc_poll_lock_stat(target, IPC_ID, false); + if (hr != ERROR_OK) + return hr; + + /* Poll Data byte */ + if (is_data_in_ram) + hr = target_read_u32(target, working_area, data_out); + else + hr = target_read_u32(target, MEM_IPC_DATA(IPC_ID), data_out); + + if (hr != ERROR_OK) { + LOG_ERROR("Error reading SROM API Status location"); + return hr; + } + + bool is_success = (*data_out & SROMAPI_STATUS_MSK) == SROMAPI_STAT_SUCCESS; + if (!is_success) { + LOG_ERROR("SROM API execution failed. Status: 0x%08X", (uint32_t)*data_out); + return ERROR_TARGET_FAILURE; + } + + return ERROR_OK; +} + +/************************************************************************************************** + * Retrieves SiliconID and Protection status of the target device + *************************************************************************************************/ +static int get_silicon_id(struct target *target, uint32_t *si_id, uint8_t *protection) +{ + int hr; + uint32_t family_rev, siid_prot; + + hr = sromalgo_prepare(target); + if (hr != ERROR_OK) + return hr; + + /* Read FamilyID and Revision */ + hr = call_sromapi(target, SROMAPI_SIID_REQ_FAMILY_REVISION, 0, &family_rev); + if (hr != ERROR_OK) + return hr; + + /* Read SiliconID and Protection */ + hr = call_sromapi(target, SROMAPI_SIID_REQ_SIID_PROTECTION, 0, &siid_prot); + if (hr != ERROR_OK) + return hr; + + *si_id = (siid_prot & 0x0000FFFF) << 16; + *si_id |= (family_rev & 0x00FF0000) >> 8; + *si_id |= (family_rev & 0x000000FF) >> 0; + + *protection = (siid_prot & 0x000F0000) >> 0x10; + + hr = sromalgo_release(target); + return hr; +} + +/************************************************************************************************** + * Translates Protection status to openocd-friendly boolean value + *************************************************************************************************/ +static int psoc6_protect_check(struct flash_bank *bank) +{ + int is_protected; + + struct psoc6_target_info *psoc6_info = bank->driver_priv; + int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection); + if (hr != ERROR_OK) + return hr; + + switch (psoc6_info->protection) { + case PROTECTION_VIRGIN: + case PROTECTION_NORMAL: + is_protected = 0; + break; + + case PROTECTION_UNKNOWN: + case PROTECTION_SECURE: + case PROTECTION_DEAD: + default: + is_protected = 1; + break; + } + + for (int i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_protected = is_protected; + + return ERROR_OK; +} + +/************************************************************************************************** + * Life Cycle transition is not currently supported + *************************************************************************************************/ +static int psoc6_protect(struct flash_bank *bank, int set, int first, int last) +{ + (void)bank; + (void)set; + (void)first; + (void)last; + + LOG_WARNING("Life Cycle transition for PSoC6 is not supported"); + return ERROR_OK; +} + +/************************************************************************************************** + * Translates Protection status to string + *************************************************************************************************/ +static const char *protection_to_str(uint8_t protection) +{ + switch (protection) { + case PROTECTION_VIRGIN: + return "VIRGIN"; + break; + case PROTECTION_NORMAL: + return "NORMAL"; + break; + case PROTECTION_SECURE: + return "SECURE"; + break; + case PROTECTION_DEAD: + return "DEAD"; + break; + case PROTECTION_UNKNOWN: + default: + return "UNKNOWN"; + break; + } +} + +/************************************************************************************************** + * Displays human-readable information about acquired device + *************************************************************************************************/ +static int psoc6_get_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct psoc6_target_info *psoc6_info = bank->driver_priv; + + if (psoc6_info->is_probed == false) + return ERROR_FAIL; + + int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection); + if (hr != ERROR_OK) + return hr; + + snprintf(buf, buf_size, + "PSoC6 Silicon ID: 0x%08X\n" + "Protection: %s\n" + "Main Flash size: %d kB\n" + "Work Flash size: 32 kB\n", + psoc6_info->silicon_id, + protection_to_str(psoc6_info->protection), + psoc6_info->main_flash_sz / 1024); + + return ERROR_OK; +} + +/************************************************************************************************** + * Returns true if flash bank name represents Supervisory Flash + *************************************************************************************************/ +static bool is_sflash_bank(struct flash_bank *bank) +{ + for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) { + if (bank->base == safe_sflash_regions[i].addr) + return true; + } + + return false; +} + +/************************************************************************************************** + * Returns true if flash bank name represents Work Flash + *************************************************************************************************/ +static inline bool is_wflash_bank(struct flash_bank *bank) +{ + return (bank->base == MEM_BASE_WFLASH); +} + +/************************************************************************************************** + * Returns true if flash bank name represents Main Flash + *************************************************************************************************/ +static inline bool is_mflash_bank(struct flash_bank *bank) +{ + return (bank->base == MEM_BASE_MFLASH); +} + +/************************************************************************************************** + * Probes the device and populates related data structures with target flash geometry data. + * This is done in non-intrusive way, no SROM API calls are involved so GDB can safely attach to a + * running target. + * Function assumes that size of Work Flash is 32kB (true for all current part numbers) + *************************************************************************************************/ +static int psoc6_probe(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct psoc6_target_info *psoc6_info = bank->driver_priv; + + int hr = ERROR_OK; + + /* Retrieve data from SPCIF_GEOMATRY */ + uint32_t geom; + target_read_u32(target, PSOC6_SPCIF_GEOMETRY, &geom); + uint32_t row_sz_lg2 = (geom & 0xF0) >> 4; + uint32_t row_sz = (0x01 << row_sz_lg2); + uint32_t row_cnt = 1 + ((geom & 0x00FFFF00) >> 8); + uint32_t bank_cnt = 1 + ((geom & 0xFF000000) >> 24); + + /* Calculate size of Main Flash*/ + uint32_t flash_sz_bytes = bank_cnt * row_cnt * row_sz; + + if (bank->sectors) { + free(bank->sectors); + bank->sectors = NULL; + } + + size_t bank_size = 0; + + if (is_mflash_bank(bank)) + bank_size = flash_sz_bytes; + else if (is_wflash_bank(bank)) + bank_size = MEM_WFLASH_SIZE; + else if (is_sflash_bank(bank)) { + for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) { + if (safe_sflash_regions[i].addr == bank->base) { + bank_size = safe_sflash_regions[i].size; + break; + } + } + } + + if (bank_size == 0) { + LOG_ERROR("Invalid Flash Bank base address in config file"); + return ERROR_FLASH_BANK_INVALID; + } + + size_t num_sectors = bank_size / row_sz; + bank->size = bank_size; + bank->chip_width = 4; + bank->bus_width = 4; + bank->erased_value = 0; + bank->default_padded_value = 0; + + bank->num_sectors = num_sectors; + bank->sectors = calloc(num_sectors, sizeof(struct flash_sector)); + for (size_t i = 0; i < num_sectors; i++) { + bank->sectors[i].size = row_sz; + bank->sectors[i].offset = i * row_sz; + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = -1; + } + + psoc6_info->is_probed = true; + psoc6_info->main_flash_sz = flash_sz_bytes; + psoc6_info->row_sz = row_sz; + + return hr; +} + +/************************************************************************************************** + * Probes target device only if it hasn't been probed yet + *************************************************************************************************/ +static int psoc6_auto_probe(struct flash_bank *bank) +{ + struct psoc6_target_info *psoc6_info = bank->driver_priv; + int hr; + + if (psoc6_info->is_probed) + hr = ERROR_OK; + else + hr = psoc6_probe(bank); + + return hr; +} + +/************************************************************************************************** + * Erases single sector (256k) on target device + *************************************************************************************************/ +static int psoc6_erase_sector(struct flash_bank *bank, struct working_area *wa, uint32_t addr) +{ + struct target *target = bank->target; + + LOG_DEBUG("Erasing SECTOR @%08X", addr); + + int hr = target_write_u32(target, wa->address, SROMAPI_ERASESECTOR_REQ); + if (hr != ERROR_OK) + return hr; + + hr = target_write_u32(target, wa->address + 0x04, addr); + if (hr != ERROR_OK) + return hr; + + uint32_t data_out; + hr = call_sromapi(target, SROMAPI_ERASESECTOR_REQ, wa->address, &data_out); + if (hr != ERROR_OK) + LOG_ERROR("SECTOR @%08X not erased!", addr); + + return hr; +} + +/************************************************************************************************** + * Erases single row (512b) on target device + *************************************************************************************************/ +static int psoc6_erase_row(struct flash_bank *bank, struct working_area *wa, uint32_t addr) +{ + struct target *target = bank->target; + + LOG_DEBUG("Erasing ROW @%08X", addr); + + int hr = target_write_u32(target, wa->address, SROMAPI_ERASEROW_REQ); + if (hr != ERROR_OK) + return hr; + + hr = target_write_u32(target, wa->address + 0x04, addr); + if (hr != ERROR_OK) + return hr; + + uint32_t data_out; + hr = call_sromapi(target, SROMAPI_ERASEROW_REQ, wa->address, &data_out); + if (hr != ERROR_OK) + LOG_ERROR("ROW @%08X not erased!", addr); + + return hr; +} + +/************************************************************************************************** + * Performs Erase operation. + * Function will try to use biggest erase block possible to speedup the operation + *************************************************************************************************/ +static int psoc6_erase(struct flash_bank *bank, int first, int last) +{ + struct target *target = bank->target; + struct psoc6_target_info *psoc6_info = bank->driver_priv; + const uint32_t sector_size = is_wflash_bank(bank) ? WFLASH_SECTOR_SIZE : MFLASH_SECTOR_SIZE; + + int hr; + struct working_area *wa; + + if (is_sflash_bank(bank)) { + LOG_INFO("Erase operation on Supervisory Flash is not required, skipping"); + return ERROR_OK; + } + + hr = sromalgo_prepare(target); + if (hr != ERROR_OK) + return hr; + + hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa); + if (hr != ERROR_OK) + goto exit; + + /* Number of rows in single sector */ + const int rows_in_sector = sector_size / psoc6_info->row_sz; + + while (last >= first) { + /* Erase Sector if we are on sector boundary and erase size covers whole sector */ + if ((first % rows_in_sector) == 0 && + (last - first + 1) >= rows_in_sector) { + hr = psoc6_erase_sector(bank, wa, bank->base + first * psoc6_info->row_sz); + if (hr != ERROR_OK) + goto exit_free_wa; + + for (int i = first; i < first + rows_in_sector; i++) + bank->sectors[i].is_erased = 1; + + first += rows_in_sector; + } else { + /* Perform Row Erase otherwise */ + hr = psoc6_erase_row(bank, wa, bank->base + first * psoc6_info->row_sz); + if (hr != ERROR_OK) + goto exit_free_wa; + + bank->sectors[first].is_erased = 1; + first += 1; + } + } + +exit_free_wa: + target_free_working_area(target, wa); +exit: + sromalgo_release(target); + return hr; +} + + +/************************************************************************************************** + * Programs single Flash Row + *************************************************************************************************/ +static int psoc6_program_row(struct flash_bank *bank, + uint32_t addr, + const uint8_t *buffer, + bool is_sflash) +{ + struct target *target = bank->target; + struct psoc6_target_info *psoc6_info = bank->driver_priv; + struct working_area *wa; + const uint32_t sromapi_req = is_sflash ? SROMAPI_WRITEROW_REQ : SROMAPI_PROGRAMROW_REQ; + uint32_t data_out; + int hr = ERROR_OK; + + LOG_DEBUG("Programming ROW @%08X", addr); + + hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa); + if (hr != ERROR_OK) + goto exit; + + hr = target_write_u32(target, wa->address, sromapi_req); + if (hr != ERROR_OK) + goto exit_free_wa; + + hr = target_write_u32(target, + wa->address + 0x04, + 0x106); + if (hr != ERROR_OK) + goto exit_free_wa; + + hr = target_write_u32(target, wa->address + 0x08, addr); + if (hr != ERROR_OK) + goto exit_free_wa; + + hr = target_write_u32(target, wa->address + 0x0C, wa->address + 0x10); + if (hr != ERROR_OK) + goto exit_free_wa; + + hr = target_write_buffer(target, wa->address + 0x10, psoc6_info->row_sz, buffer); + if (hr != ERROR_OK) + goto exit_free_wa; + + hr = call_sromapi(target, sromapi_req, wa->address, &data_out); + +exit_free_wa: + target_free_working_area(target, wa); + +exit: + return hr; +} + + +/************************************************************************************************** + * Programs set of Rows + *************************************************************************************************/ +static int psoc6_program(struct flash_bank *bank, + const uint8_t *buffer, + uint32_t offset, + uint32_t count) +{ + struct target *target = bank->target; + struct psoc6_target_info *psoc6_info = bank->driver_priv; + const bool is_sflash = is_sflash_bank(bank); + int hr; + + hr = sromalgo_prepare(target); + if (hr != ERROR_OK) + return hr; + + uint8_t page_buf[psoc6_info->row_sz]; + + while (count) { + uint32_t row_offset = offset % psoc6_info->row_sz; + uint32_t aligned_addr = bank->base + offset - row_offset; + uint32_t row_bytes = MIN(psoc6_info->row_sz - row_offset, count); + + memset(page_buf, 0, sizeof(page_buf)); + memcpy(&page_buf[row_offset], buffer, row_bytes); + + hr = psoc6_program_row(bank, aligned_addr, page_buf, is_sflash); + if (hr != ERROR_OK) { + LOG_ERROR("Failed to program Flash at address 0x%08X", aligned_addr); + break; + } + + buffer += row_bytes; + offset += row_bytes; + count -= row_bytes; + } + + hr = sromalgo_release(target); + return hr; +} + +/************************************************************************************************** + * Performs Mass Erase of given flash bank + * Syntax: psoc6 mass_erase bank_id + *************************************************************************************************/ +COMMAND_HANDLER(psoc6_handle_mass_erase_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int hr = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (hr != ERROR_OK) + return hr; + + hr = psoc6_erase(bank, 0, bank->num_sectors - 1); + + return hr; +} + +/************************************************************************************************** + * Simulates broken Vector Catch + * Function will try to determine entry point of user application. If it succeeds it will set HW + * breakpoint at that address, issue SW Reset and remove the breakpoint afterwards. + * In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will + * reset CM4 anyway, so using SYSRESETREQ is safe here. + * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core. + *************************************************************************************************/ +int handle_reset_halt(struct target *target) +{ + int hr; + uint32_t reset_addr; + bool is_cm0 = (target->coreid == 0); + + /* Halt target device */ + if (target->state != TARGET_HALTED) { + hr = target_halt(target); + if (hr != ERROR_OK) + return hr; + + target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS); + if (hr != ERROR_OK) + return hr; + } + + /* Read Vector Offset register */ + uint32_t vt_base; + const uint32_t vt_offset_reg = is_cm0 ? 0x402102B0 : 0x402102C0; + hr = target_read_u32(target, vt_offset_reg, &vt_base); + if (hr != ERROR_OK) + return ERROR_OK; + + /* Invalid value means flash is empty */ + vt_base &= 0xFFFFFF00; + if ((vt_base == 0) || (vt_base == 0xFFFFFF00)) + return ERROR_OK; + + /* Read Reset Vector value*/ + hr = target_read_u32(target, vt_base + 4, &reset_addr); + if (hr != ERROR_OK) + return hr; + + /* Invalid value means flash is empty */ + if ((reset_addr == 0) || (reset_addr == 0xFFFFFF00)) + return ERROR_OK; + + + /* Set breakpoint at User Application entry point */ + hr = breakpoint_add(target, reset_addr, 2, BKPT_HARD); + if (hr != ERROR_OK) + return hr; + + const struct armv7m_common *cm = target_to_armv7m(target); + + if (is_cm0) { + /* Reset the CM0 by asserting SYSRESETREQ. This will also reset CM4 */ + LOG_INFO("psoc6.cm0: bkpt @0x%08X, issuing SYSRESETREQ", reset_addr); + hr = mem_ap_write_atomic_u32(cm->debug_ap, + NVIC_AIRCR, + AIRCR_VECTKEY | AIRCR_SYSRESETREQ); + + /* Wait for bootcode and initialize DAP */ + usleep(3000); + dap_dp_init(cm->debug_ap->dap); + } else { + LOG_INFO("psoc6.cm4: bkpt @0x%08X, issuing VECTRESET", reset_addr); + hr = mem_ap_write_atomic_u32(cm->debug_ap, + NVIC_AIRCR, + AIRCR_VECTKEY | AIRCR_VECTRESET); + if (hr != ERROR_OK) + return hr; + } + + target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS); + + /* Remove the break point */ + breakpoint_remove(target, reset_addr); + + return hr; +} + +COMMAND_HANDLER(psoc6_handle_reset_halt) +{ + if (CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + return handle_reset_halt(target); +} + +FLASH_BANK_COMMAND_HANDLER(psoc6_flash_bank_command) +{ + struct psoc6_target_info *psoc6_info; + int hr = ERROR_OK; + + if (CMD_ARGC < 6) + hr = ERROR_COMMAND_SYNTAX_ERROR; + else { + psoc6_info = calloc(1, sizeof(struct psoc6_target_info)); + psoc6_info->is_probed = false; + bank->driver_priv = psoc6_info; + } + return hr; +} + +static const struct command_registration psoc6_exec_command_handlers[] = { + { + .name = "mass_erase", + .handler = psoc6_handle_mass_erase_command, + .mode = COMMAND_EXEC, + .usage = NULL, + .help = "Erases entire Main Flash", + }, + { + .name = "reset_halt", + .handler = psoc6_handle_reset_halt, + .mode = COMMAND_EXEC, + .usage = NULL, + .help = "Tries to simulate broken Vector Catch", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration psoc6_command_handlers[] = { + { + .name = "psoc6", + .mode = COMMAND_ANY, + .help = "PSoC 6 flash command group", + .usage = "", + .chain = psoc6_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct flash_driver psoc6_flash = { + .name = "psoc6", + .commands = psoc6_command_handlers, + .flash_bank_command = psoc6_flash_bank_command, + .erase = psoc6_erase, + .protect = psoc6_protect, + .write = psoc6_program, + .read = default_flash_read, + .probe = psoc6_probe, + .auto_probe = psoc6_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = psoc6_protect_check, + .info = psoc6_get_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/sim3x.c b/src/flash/nor/sim3x.c index ce9a21ed5..f282ba089 100644 --- a/src/flash/nor/sim3x.c +++ b/src/flash/nor/sim3x.c @@ -1122,5 +1122,6 @@ struct flash_driver sim3x_flash = { .auto_probe = sim3x_auto_probe, .erase_check = default_flash_blank_check, .protect_check = sim3x_flash_protect_check, - .info = sim3x_flash_info + .info = sim3x_flash_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c index d28ceee4b..79aaf3ba2 100644 --- a/src/flash/nor/stellaris.c +++ b/src/flash/nor/stellaris.c @@ -1452,4 +1452,5 @@ struct flash_driver stellaris_flash = { .erase_check = default_flash_blank_check, .protect_check = stellaris_protect_check, .info = get_stellaris_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index d44670768..64c91680c 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -1647,4 +1647,5 @@ struct flash_driver stm32f1x_flash = { .erase_check = default_flash_blank_check, .protect_check = stm32x_protect_check, .info = get_stm32x_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index b0992b404..8bca62ea2 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -1634,4 +1634,5 @@ struct flash_driver stm32f2x_flash = { .erase_check = default_flash_blank_check, .protect_check = stm32x_protect_check, .info = get_stm32x_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index 01e6f06dc..a15cd2531 100644 --- a/src/flash/nor/stm32h7x.c +++ b/src/flash/nor/stm32h7x.c @@ -1180,4 +1180,5 @@ struct flash_driver stm32h7x_flash = { .erase_check = default_flash_blank_check, .protect_check = stm32x_protect_check, .info = stm32x_get_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 6a1fa074e..e2710bd81 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -953,4 +953,5 @@ struct flash_driver stm32l4x_flash = { .erase_check = default_flash_blank_check, .protect_check = stm32l4_protect_check, .info = get_stm32l4_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index fdfaad4cf..f4dd686aa 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -965,6 +965,7 @@ struct flash_driver stm32lx_flash = { .erase_check = default_flash_blank_check, .protect_check = stm32lx_protect_check, .info = stm32lx_get_info, + .free_driver_priv = default_flash_free_driver_priv, }; /* Static methods implementation */ diff --git a/src/flash/nor/stmsmi.c b/src/flash/nor/stmsmi.c index 781ea3b5b..c839bf74c 100644 --- a/src/flash/nor/stmsmi.c +++ b/src/flash/nor/stmsmi.c @@ -654,4 +654,5 @@ struct flash_driver stmsmi_flash = { .erase_check = default_flash_blank_check, .protect_check = stmsmi_protect_check, .info = get_stmsmi_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/str7x.c b/src/flash/nor/str7x.c index 11179f520..015202a0e 100644 --- a/src/flash/nor/str7x.c +++ b/src/flash/nor/str7x.c @@ -812,4 +812,5 @@ struct flash_driver str7x_flash = { .erase_check = default_flash_blank_check, .protect_check = str7x_protect_check, .info = get_str7x_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/str9x.c b/src/flash/nor/str9x.c index 3b7ca2aa7..37700ce36 100644 --- a/src/flash/nor/str9x.c +++ b/src/flash/nor/str9x.c @@ -679,4 +679,5 @@ struct flash_driver str9x_flash = { .auto_probe = str9x_probe, .erase_check = default_flash_blank_check, .protect_check = str9x_protect_check, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/str9xpec.c b/src/flash/nor/str9xpec.c index eb391e8fb..29e0977bb 100644 --- a/src/flash/nor/str9xpec.c +++ b/src/flash/nor/str9xpec.c @@ -1207,4 +1207,5 @@ struct flash_driver str9xpec_flash = { .auto_probe = str9xpec_probe, .erase_check = str9xpec_erase_check, .protect_check = str9xpec_protect_check, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/tms470.c b/src/flash/nor/tms470.c index a70891e89..102bf1b15 100644 --- a/src/flash/nor/tms470.c +++ b/src/flash/nor/tms470.c @@ -1186,4 +1186,5 @@ struct flash_driver tms470_flash = { .erase_check = tms470_erase_check, .protect_check = tms470_protect_check, .info = get_tms470_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/virtual.c b/src/flash/nor/virtual.c index 06981f4f4..d5d688b36 100644 --- a/src/flash/nor/virtual.c +++ b/src/flash/nor/virtual.c @@ -231,4 +231,5 @@ struct flash_driver virtual_flash = { .erase_check = virtual_blank_check, .protect_check = virtual_protect_check, .info = virtual_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/xcf.c b/src/flash/nor/xcf.c index 035791eb3..bc4b1be5e 100644 --- a/src/flash/nor/xcf.c +++ b/src/flash/nor/xcf.c @@ -636,6 +636,7 @@ static int xcf_probe(struct flash_bank *bank) fill_sector_table(bank); priv->probed = true; + /* REVISIT: Why is unchanged bank->driver_priv rewritten by same value? */ bank->driver_priv = priv; LOG_INFO("product name: %s", product_name(bank)); @@ -893,5 +894,6 @@ struct flash_driver xcf_flash = { .auto_probe = xcf_auto_probe, .erase_check = xcf_erase_check, .protect_check = xcf_protect_check, - .info = xcf_info + .info = xcf_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/xmc1xxx.c b/src/flash/nor/xmc1xxx.c index 0a76b216d..4b25398bc 100644 --- a/src/flash/nor/xmc1xxx.c +++ b/src/flash/nor/xmc1xxx.c @@ -546,4 +546,5 @@ struct flash_driver xmc1xxx_flash = { .erase = xmc1xxx_erase, .erase_check = xmc1xxx_erase_check, .write = xmc1xxx_write, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/xmc4xxx.c b/src/flash/nor/xmc4xxx.c index 5677ef0f1..0b6d48c1b 100644 --- a/src/flash/nor/xmc4xxx.c +++ b/src/flash/nor/xmc4xxx.c @@ -1356,4 +1356,5 @@ struct flash_driver xmc4xxx_flash = { .info = xmc4xxx_get_info_command, .protect_check = xmc4xxx_protect_check, .protect = xmc4xxx_protect, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/helper/command.c b/src/helper/command.c index cbd52fbf1..f8b731e4a 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -608,7 +608,23 @@ static int run_command(struct command_context *context, .argc = num_words - 1, .argv = words + 1, }; + /* Black magic of overridden current target: + * If the command we are going to handle has a target prefix, + * override the current target temporarily for the time + * of processing the command. + * current_target_override is used also for event handlers + * therefore we prevent touching it if command has no prefix. + * Previous override is saved and restored back to ensure + * correct work when run_command() is re-entered. */ + struct target *saved_target_override = context->current_target_override; + if (c->jim_handler_data) + context->current_target_override = c->jim_handler_data; + int retval = c->handler(&cmd); + + if (c->jim_handler_data) + context->current_target_override = saved_target_override; + if (retval == ERROR_COMMAND_SYNTAX_ERROR) { /* Print help for command */ char *full_name = command_name(c, ' '); @@ -643,6 +659,8 @@ int command_run_line(struct command_context *context, char *line) * happen when the Jim Tcl interpreter is provided by eCos for * instance. */ + context->current_target_override = NULL; + Jim_Interp *interp = context->interp; Jim_DeleteAssocData(interp, "context"); retcode = Jim_SetAssocData(interp, "context", NULL, context); @@ -1269,14 +1287,10 @@ static const struct command_registration command_builtin_handlers[] = { struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp) { - struct command_context *context = malloc(sizeof(struct command_context)); + struct command_context *context = calloc(1, sizeof(struct command_context)); const char *HostOs; context->mode = COMMAND_EXEC; - context->commands = NULL; - context->current_target = 0; - context->output_handler = NULL; - context->output_handler_priv = NULL; /* Create a jim interpreter if we were not handed one */ if (interp == NULL) { diff --git a/src/helper/command.h b/src/helper/command.h index f696ab823..f9c02e573 100644 --- a/src/helper/command.h +++ b/src/helper/command.h @@ -22,8 +22,12 @@ #ifndef OPENOCD_HELPER_COMMAND_H #define OPENOCD_HELPER_COMMAND_H +#include +#include #include +#include + /* To achieve C99 printf compatibility in MinGW, gnu_printf should be * used for __attribute__((format( ... ))), with GCC v4.4 or later */ @@ -49,7 +53,15 @@ struct command_context { Jim_Interp *interp; enum command_mode mode; struct command *commands; - int current_target; + struct target *current_target; + /* The target set by 'targets xx' command or the latest created */ + struct target *current_target_override; + /* If set overrides current_target + * It happens during processing of + * 1) a target prefixed command + * 2) an event handler + * Pay attention to reentrancy when setting override. + */ command_output_handler_t output_handler; void *output_handler_priv; }; @@ -168,6 +180,11 @@ struct command { command_handler_t handler; Jim_CmdProc *jim_handler; void *jim_handler_data; + /* Currently used only for target of target-prefixed cmd. + * Native OpenOCD commands use jim_handler_data exclusively + * as a target override. + * Jim handlers outside of target cmd tree can use + * jim_handler_data for any handler specific data */ enum command_mode mode; struct command *next; }; diff --git a/src/helper/configuration.c b/src/helper/configuration.c index 2a278838d..114ad2c6c 100644 --- a/src/helper/configuration.c +++ b/src/helper/configuration.c @@ -51,6 +51,21 @@ void add_config_command(const char *cfg) config_file_names[num_config_files] = NULL; } +void free_config(void) +{ + while (num_config_files) + free(config_file_names[--num_config_files]); + + free(config_file_names); + config_file_names = NULL; + + while (num_script_dirs) + free(script_search_dirs[--num_script_dirs]); + + free(script_search_dirs); + script_search_dirs = NULL; +} + /* return full path or NULL according to search rules */ char *find_file(const char *file) { diff --git a/src/helper/configuration.h b/src/helper/configuration.h index 3cbcd41f6..cc28efcdb 100644 --- a/src/helper/configuration.h +++ b/src/helper/configuration.h @@ -32,6 +32,8 @@ void add_config_command(const char *cfg); void add_script_search_dir(const char *dir); +void free_config(void); + int configuration_output_handler(struct command_context *cmd_ctx, const char *line); diff --git a/src/helper/fileio.c b/src/helper/fileio.c index 47494dfcd..9dd57e72a 100644 --- a/src/helper/fileio.c +++ b/src/helper/fileio.c @@ -153,6 +153,11 @@ int fileio_close(struct fileio *fileio) return retval; } +int fileio_feof(struct fileio *fileio) +{ + return feof(fileio->file); +} + int fileio_seek(struct fileio *fileio, size_t position) { int retval; diff --git a/src/helper/fileio.h b/src/helper/fileio.h index ae4a3ecfc..02592e28d 100644 --- a/src/helper/fileio.h +++ b/src/helper/fileio.h @@ -46,6 +46,7 @@ struct fileio; int fileio_open(struct fileio **fileio, const char *url, enum fileio_access access_type, enum fileio_type type); int fileio_close(struct fileio *fileio); +int fileio_feof(struct fileio *fileio); int fileio_seek(struct fileio *fileio, size_t position); int fileio_fgets(struct fileio *fileio, size_t size, void *buffer); diff --git a/src/helper/replacements.h b/src/helper/replacements.h index f43b7e0f3..ac5009549 100644 --- a/src/helper/replacements.h +++ b/src/helper/replacements.h @@ -25,6 +25,8 @@ #ifndef OPENOCD_HELPER_REPLACEMENTS_H #define OPENOCD_HELPER_REPLACEMENTS_H +#include + /* MIN,MAX macros */ #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) diff --git a/src/helper/types.h b/src/helper/types.h index 58c9e7245..5e35c13b7 100644 --- a/src/helper/types.h +++ b/src/helper/types.h @@ -22,7 +22,12 @@ #ifndef OPENOCD_HELPER_TYPES_H #define OPENOCD_HELPER_TYPES_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include +#include #ifdef HAVE_SYS_TYPES_H #include #endif @@ -123,17 +128,17 @@ static inline uint64_t le_to_h_u64(const uint8_t *buf) static inline uint32_t le_to_h_u32(const uint8_t* buf) { - return (uint32_t)(buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24); + return (uint32_t)((uint32_t)buf[0] | (uint32_t)buf[1] << 8 | (uint32_t)buf[2] << 16 | (uint32_t)buf[3] << 24); } static inline uint32_t le_to_h_u24(const uint8_t* buf) { - return (uint32_t)(buf[0] | buf[1] << 8 | buf[2] << 16); + return (uint32_t)((uint32_t)buf[0] | (uint32_t)buf[1] << 8 | (uint32_t)buf[2] << 16); } static inline uint16_t le_to_h_u16(const uint8_t* buf) { - return (uint16_t)(buf[0] | buf[1] << 8); + return (uint16_t)((uint16_t)buf[0] | (uint16_t)buf[1] << 8); } static inline uint64_t be_to_h_u64(const uint8_t *buf) @@ -150,17 +155,17 @@ static inline uint64_t be_to_h_u64(const uint8_t *buf) static inline uint32_t be_to_h_u32(const uint8_t* buf) { - return (uint32_t)(buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24); + return (uint32_t)((uint32_t)buf[3] | (uint32_t)buf[2] << 8 | (uint32_t)buf[1] << 16 | (uint32_t)buf[0] << 24); } static inline uint32_t be_to_h_u24(const uint8_t* buf) { - return (uint32_t)(buf[2] | buf[1] << 8 | buf[0] << 16); + return (uint32_t)((uint32_t)buf[2] | (uint32_t)buf[1] << 8 | (uint32_t)buf[0] << 16); } static inline uint16_t be_to_h_u16(const uint8_t* buf) { - return (uint16_t)(buf[1] | buf[0] << 8); + return (uint16_t)((uint16_t)buf[1] | (uint16_t)buf[0] << 8); } static inline void h_u64_to_le(uint8_t *buf, int64_t val) diff --git a/src/jtag/aice/aice_interface.c b/src/jtag/aice/aice_interface.c index 20f1f07f9..c758bb43b 100644 --- a/src/jtag/aice/aice_interface.c +++ b/src/jtag/aice/aice_interface.c @@ -239,6 +239,30 @@ static int aice_khz(int khz, int *jtag_speed) return ERROR_OK; } +int aice_scan_jtag_chain(void) +{ + LOG_DEBUG("=== %s ===", __func__); + uint8_t num_of_idcode = 0; + struct target *target; + + int res = aice_port->api->idcode(aice_target_id_codes, &num_of_idcode); + if (res != ERROR_OK) { + LOG_ERROR("<-- TARGET ERROR! Failed to identify AndesCore " + "JTAG Manufacture ID in the JTAG scan chain. " + "Failed to access EDM registers. -->"); + return res; + } + + for (uint32_t i = 0; i < num_of_idcode; i++) + LOG_DEBUG("id_codes[%d] = 0x%x", i, aice_target_id_codes[i]); + + /* Update tap idcode */ + for (target = all_targets; target; target = target->next) + target->tap->idcode = aice_target_id_codes[target->tap->abs_chain_position]; + + return ERROR_OK; +} + /***************************************************************************/ /* Command handlers */ COMMAND_HANDLER(aice_handle_aice_info_command) diff --git a/src/jtag/aice/aice_interface.h b/src/jtag/aice/aice_interface.h index 0e3f10836..220b0b04d 100644 --- a/src/jtag/aice/aice_interface.h +++ b/src/jtag/aice/aice_interface.h @@ -31,5 +31,6 @@ struct aice_interface_param_s { }; int aice_init_targets(void); +int aice_scan_jtag_chain(void); #endif /* OPENOCD_JTAG_AICE_AICE_INTERFACE_H */ diff --git a/src/jtag/aice/aice_transport.c b/src/jtag/aice/aice_transport.c index 9f079468c..57c93f2a1 100644 --- a/src/jtag/aice/aice_transport.c +++ b/src/jtag/aice/aice_transport.c @@ -158,6 +158,59 @@ COMMAND_HANDLER(handle_aice_init_command) return jtag_init(CMD_CTX); } +COMMAND_HANDLER(handle_scan_chain_command) +{ + struct jtag_tap *tap; + char expected_id[12]; + + aice_scan_jtag_chain(); + tap = jtag_all_taps(); + command_print(CMD_CTX, + " TapName Enabled IdCode Expected IrLen IrCap IrMask"); + command_print(CMD_CTX, + "-- ------------------- -------- ---------- ---------- ----- ----- ------"); + + while (tap) { + uint32_t expected, expected_mask, ii; + + snprintf(expected_id, sizeof expected_id, "0x%08x", + (unsigned)((tap->expected_ids_cnt > 0) + ? tap->expected_ids[0] + : 0)); + if (tap->ignore_version) + expected_id[2] = '*'; + + expected = buf_get_u32(tap->expected, 0, tap->ir_length); + expected_mask = buf_get_u32(tap->expected_mask, 0, tap->ir_length); + + command_print(CMD_CTX, + "%2d %-18s %c 0x%08x %s %5d 0x%02x 0x%02x", + tap->abs_chain_position, + tap->dotted_name, + tap->enabled ? 'Y' : 'n', + (unsigned int)(tap->idcode), + expected_id, + (unsigned int)(tap->ir_length), + (unsigned int)(expected), + (unsigned int)(expected_mask)); + + for (ii = 1; ii < tap->expected_ids_cnt; ii++) { + snprintf(expected_id, sizeof expected_id, "0x%08x", + (unsigned) tap->expected_ids[ii]); + if (tap->ignore_version) + expected_id[2] = '*'; + + command_print(CMD_CTX, + " %s", + expected_id); + } + + tap = tap->next_tap; + } + + return ERROR_OK; +} + static int jim_aice_arp_init(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { LOG_DEBUG("No implement: jim_aice_arp_init"); @@ -307,6 +360,13 @@ aice_transport_jtag_subcommand_handlers[] = { .jim_handler = jim_aice_names, .help = "Returns list of all JTAG tap names.", }, + { + .name = "scan_chain", + .handler = handle_scan_chain_command, + .mode = COMMAND_ANY, + .help = "print current scan chain configuration", + .usage = "" + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/core.c b/src/jtag/core.c index 71a731de1..4522321a7 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -836,68 +836,7 @@ int default_interface_jtag_execute_queue(void) return ERROR_FAIL; } - int result = jtag->execute_queue(); - - struct jtag_command *cmd = jtag_command_queue; - while (debug_level >= LOG_LVL_DEBUG && cmd) { - switch (cmd->type) { - case JTAG_SCAN: - DEBUG_JTAG_IO("JTAG %s SCAN to %s", - cmd->cmd.scan->ir_scan ? "IR" : "DR", - tap_state_name(cmd->cmd.scan->end_state)); - for (int i = 0; i < cmd->cmd.scan->num_fields; i++) { - struct scan_field *field = cmd->cmd.scan->fields + i; - if (field->out_value) { - char *str = buf_to_str(field->out_value, field->num_bits, 16); - DEBUG_JTAG_IO(" %db out: %s", field->num_bits, str); - free(str); - } - if (field->in_value) { - char *str = buf_to_str(field->in_value, field->num_bits, 16); - DEBUG_JTAG_IO(" %db in: %s", field->num_bits, str); - free(str); - } - } - break; - case JTAG_TLR_RESET: - DEBUG_JTAG_IO("JTAG TLR RESET to %s", - tap_state_name(cmd->cmd.statemove->end_state)); - break; - case JTAG_RUNTEST: - DEBUG_JTAG_IO("JTAG RUNTEST %d cycles to %s", - cmd->cmd.runtest->num_cycles, - tap_state_name(cmd->cmd.runtest->end_state)); - break; - case JTAG_RESET: - { - const char *reset_str[3] = { - "leave", "deassert", "assert" - }; - DEBUG_JTAG_IO("JTAG RESET %s TRST, %s SRST", - reset_str[cmd->cmd.reset->trst + 1], - reset_str[cmd->cmd.reset->srst + 1]); - } - break; - case JTAG_PATHMOVE: - DEBUG_JTAG_IO("JTAG PATHMOVE (TODO)"); - break; - case JTAG_SLEEP: - DEBUG_JTAG_IO("JTAG SLEEP (TODO)"); - break; - case JTAG_STABLECLOCKS: - DEBUG_JTAG_IO("JTAG STABLECLOCKS (TODO)"); - break; - case JTAG_TMS: - DEBUG_JTAG_IO("JTAG STABLECLOCKS (TODO)"); - break; - default: - LOG_ERROR("Unknown JTAG command: %d", cmd->type); - break; - } - cmd = cmd->next; - } - - return result; + return jtag->execute_queue(); } void jtag_execute_queue_noclear(void) @@ -1168,8 +1107,7 @@ static int jtag_examine_chain(void) if ((idcode & 1) == 0) { /* Zero for LSB indicates a device in bypass */ - LOG_INFO("TAP %s does not have valid IDCODE (idcode=0x%x)", - tap->dotted_name, idcode); + LOG_INFO("TAP %s does not have IDCODE", tap->dotted_name); tap->hasidcode = false; tap->idcode = 0; @@ -1370,6 +1308,14 @@ void jtag_tap_free(struct jtag_tap *tap) { jtag_unregister_event_callback(&jtag_reset_callback, tap); + struct jtag_tap_event_action *jteap = tap->event_action; + while (jteap) { + struct jtag_tap_event_action *next = jteap->next; + Jim_DecrRefCount(jteap->interp, jteap->body); + free(jteap); + jteap = next; + } + free(tap->expected); free(tap->expected_mask); free(tap->expected_ids); @@ -1534,13 +1480,21 @@ int jtag_init_inner(struct command_context *cmd_ctx) int adapter_quit(void) { - if (!jtag || !jtag->quit) - return ERROR_OK; + if (jtag && jtag->quit) { + /* close the JTAG interface */ + int result = jtag->quit(); + if (ERROR_OK != result) + LOG_ERROR("failed: %d", result); + } - /* close the JTAG interface */ - int result = jtag->quit(); - if (ERROR_OK != result) - LOG_ERROR("failed: %d", result); + struct jtag_tap *t = jtag_all_taps(); + while (t) { + struct jtag_tap *n = t->next_tap; + jtag_tap_free(t); + t = n; + } + + dap_cleanup_all(); return ERROR_OK; } diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index 3e5974da4..b3b4d2198 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -80,6 +80,9 @@ if USB_BLASTER_DRIVER %C%_libocdjtagdrivers_la_LIBADD += %D%/usb_blaster/libocdusbblaster.la include %D%/usb_blaster/Makefile.am endif +if FT232R +DRIVERFILES += %D%/ft232r.c +endif if AMTJTAGACCEL DRIVERFILES += %D%/amt_jtagaccel.c endif diff --git a/src/jtag/drivers/buspirate.c b/src/jtag/drivers/buspirate.c index aa0d8cc3f..35649c280 100644 --- a/src/jtag/drivers/buspirate.c +++ b/src/jtag/drivers/buspirate.c @@ -22,6 +22,7 @@ #endif #include +#include #include #include @@ -48,9 +49,21 @@ static void buspirate_stableclocks(int num_cycles); #define CMD_READ_ADCS 0x03 /*#define CMD_TAP_SHIFT 0x04 // old protocol */ #define CMD_TAP_SHIFT 0x05 +#define CMD_ENTER_RWIRE 0x05 #define CMD_ENTER_OOCD 0x06 #define CMD_UART_SPEED 0x07 #define CMD_JTAG_SPEED 0x08 +#define CMD_RAW_PERIPH 0x40 +#define CMD_RAW_SPEED 0x60 +#define CMD_RAW_MODE 0x80 + +/* raw-wire mode configuration */ +#define CMD_RAW_CONFIG_HIZ 0x00 +#define CMD_RAW_CONFIG_3V3 0x08 +#define CMD_RAW_CONFIG_2W 0x00 +#define CMD_RAW_CONFIG_3W 0x04 +#define CMD_RAW_CONFIG_MSB 0x00 +#define CMD_RAW_CONFIG_LSB 0x02 /* Not all OSes have this speed defined */ #if !defined(B1000000) @@ -81,6 +94,18 @@ enum { SERIAL_FAST = 1 }; +enum { + SPEED_RAW_5_KHZ = 0x0, + SPEED_RAW_50_KHZ = 0x1, + SPEED_RAW_100_KHZ = 0x2, + SPEED_RAW_400_KHZ = 0x3 +}; + +/* SWD mode specific */ +static bool swd_mode; +static int queued_retval; +static char swd_features; + static const cc_t SHORT_TIMEOUT = 1; /* Must be at least 1. */ static const cc_t NORMAL_TIMEOUT = 10; @@ -93,6 +118,12 @@ static char *buspirate_port; static enum tap_state last_tap_state = TAP_RESET; +/* SWD interface */ +static int buspirate_swd_init(void); +static void buspirate_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk); +static void buspirate_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk); +static int buspirate_swd_switch_seq(enum swd_special_seq seq); +static int buspirate_swd_run_queue(void); /* TAP interface */ static void buspirate_tap_init(void); @@ -103,23 +134,31 @@ static void buspirate_tap_append_scan(int length, uint8_t *buffer, static void buspirate_tap_make_space(int scan, int bits); static void buspirate_reset(int trst, int srst); +static void buspirate_set_feature(int, char, char); +static void buspirate_set_mode(int, char); +static void buspirate_set_speed(int, char); /* low level interface */ +static void buspirate_bbio_enable(int); static void buspirate_jtag_reset(int); -static void buspirate_jtag_enable(int); -static unsigned char buspirate_jtag_command(int, char *, int); +static unsigned char buspirate_jtag_command(int, uint8_t *, int); static void buspirate_jtag_set_speed(int, char); static void buspirate_jtag_set_mode(int, char); static void buspirate_jtag_set_feature(int, char, char); static void buspirate_jtag_get_adcs(int); +/* low level two-wire interface */ +static void buspirate_swd_set_speed(int, char); +static void buspirate_swd_set_feature(int, char, char); +static void buspirate_swd_set_mode(int, char); + /* low level HW communication interface */ static int buspirate_serial_open(char *port); static int buspirate_serial_setspeed(int fd, char speed, cc_t timeout); -static int buspirate_serial_write(int fd, char *buf, int size); -static int buspirate_serial_read(int fd, char *buf, int size); +static int buspirate_serial_write(int fd, uint8_t *buf, int size); +static int buspirate_serial_read(int fd, uint8_t *buf, int size); static void buspirate_serial_close(int fd); -static void buspirate_print_buffer(char *buf, int size); +static void buspirate_print_buffer(uint8_t *buf, int size); static int buspirate_execute_queue(void) { @@ -216,7 +255,7 @@ static bool read_and_discard_all_data(const int fd) bool was_msg_already_printed = false; for ( ; ; ) { - char buffer[1024]; /* Any size will do, it's a trade-off between stack size and performance. */ + uint8_t buffer[1024]; /* Any size will do, it's a trade-off between stack size and performance. */ const ssize_t read_count = read(fd, buffer, sizeof(buffer)); @@ -295,18 +334,20 @@ static int buspirate_init(void) return ERROR_JTAG_INIT_FAILED; } - buspirate_jtag_enable(buspirate_fd); + buspirate_bbio_enable(buspirate_fd); - if (buspirate_baudrate != SERIAL_NORMAL) - buspirate_jtag_set_speed(buspirate_fd, SERIAL_FAST); + if (swd_mode || buspirate_baudrate != SERIAL_NORMAL) + buspirate_set_speed(buspirate_fd, SERIAL_FAST); - LOG_INFO("Buspirate Interface ready!"); + LOG_INFO("Buspirate %s Interface ready!", swd_mode ? "SWD" : "JTAG"); - buspirate_tap_init(); - buspirate_jtag_set_mode(buspirate_fd, buspirate_pinmode); - buspirate_jtag_set_feature(buspirate_fd, FEATURE_VREG, + if (!swd_mode) + buspirate_tap_init(); + + buspirate_set_mode(buspirate_fd, buspirate_pinmode); + buspirate_set_feature(buspirate_fd, FEATURE_VREG, (buspirate_vreg == 1) ? ACTION_ENABLE : ACTION_DISABLE); - buspirate_jtag_set_feature(buspirate_fd, FEATURE_PULLUP, + buspirate_set_feature(buspirate_fd, FEATURE_PULLUP, (buspirate_pullup == 1) ? ACTION_ENABLE : ACTION_DISABLE); buspirate_reset(0, 0); @@ -316,9 +357,9 @@ static int buspirate_init(void) static int buspirate_quit(void) { LOG_INFO("Shutting down buspirate."); - buspirate_jtag_set_mode(buspirate_fd, MODE_HIZ); + buspirate_set_mode(buspirate_fd, MODE_HIZ); + buspirate_set_speed(buspirate_fd, SERIAL_NORMAL); - buspirate_jtag_set_speed(buspirate_fd, SERIAL_NORMAL); buspirate_jtag_reset(buspirate_fd); buspirate_serial_close(buspirate_fd); @@ -336,6 +377,10 @@ COMMAND_HANDLER(buspirate_handle_adc_command) if (buspirate_fd == -1) return ERROR_OK; + /* unavailable in SWD mode */ + if (swd_mode) + return ERROR_OK; + /* send the command */ buspirate_jtag_get_adcs(buspirate_fd); @@ -382,11 +427,11 @@ COMMAND_HANDLER(buspirate_handle_led_command) if (atoi(CMD_ARGV[0]) == 1) { /* enable led */ - buspirate_jtag_set_feature(buspirate_fd, FEATURE_LED, + buspirate_set_feature(buspirate_fd, FEATURE_LED, ACTION_ENABLE); } else if (atoi(CMD_ARGV[0]) == 0) { /* disable led */ - buspirate_jtag_set_feature(buspirate_fd, FEATURE_LED, + buspirate_set_feature(buspirate_fd, FEATURE_LED, ACTION_DISABLE); } else { LOG_ERROR("usage: buspirate_led <1|0>"); @@ -492,10 +537,22 @@ static const struct command_registration buspirate_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct swd_driver buspirate_swd = { + .init = buspirate_swd_init, + .switch_seq = buspirate_swd_switch_seq, + .read_reg = buspirate_swd_read_reg, + .write_reg = buspirate_swd_write_reg, + .run = buspirate_swd_run_queue, +}; + +static const char * const buspirate_transports[] = { "jtag", "swd", NULL }; + struct jtag_interface buspirate_interface = { .name = "buspirate", .execute_queue = buspirate_execute_queue, .commands = buspirate_command_handlers, + .transports = buspirate_transports, + .swd = &buspirate_swd, .init = buspirate_init, .quit = buspirate_quit }; @@ -633,8 +690,8 @@ static void buspirate_stableclocks(int num_cycles) make it incompatible with the Bus Pirate firmware. */ #define BUSPIRATE_MAX_PENDING_SCANS 128 -static char tms_chain[BUSPIRATE_BUFFER_SIZE]; /* send */ -static char tdi_chain[BUSPIRATE_BUFFER_SIZE]; /* send */ +static uint8_t tms_chain[BUSPIRATE_BUFFER_SIZE]; /* send */ +static uint8_t tdi_chain[BUSPIRATE_BUFFER_SIZE]; /* send */ static int tap_chain_index; struct pending_scan_result /* this was stolen from arm-jtag-ew */ @@ -659,7 +716,7 @@ static int buspirate_tap_execute(void) { static const int CMD_TAP_SHIFT_HEADER_LEN = 3; - char tmp[4096]; + uint8_t tmp[4096]; uint8_t *in_buf; int i; int fill_index = 0; @@ -675,8 +732,8 @@ static int buspirate_tap_execute(void) bytes_to_send = DIV_ROUND_UP(tap_chain_index, 8); tmp[0] = CMD_TAP_SHIFT; /* this command expects number of bits */ - tmp[1] = (char)(tap_chain_index >> 8); /* high */ - tmp[2] = (char)(tap_chain_index); /* low */ + tmp[1] = tap_chain_index >> 8; /* high */ + tmp[2] = tap_chain_index; /* low */ fill_index = CMD_TAP_SHIFT_HEADER_LEN; for (i = 0; i < bytes_to_send; i++) { @@ -799,7 +856,7 @@ static void buspirate_tap_append_scan(int length, uint8_t *buffer, tap_pending_scans_num++; } -/*************** jtag wrapper functions *********************/ +/*************** wrapper functions *********************/ /* (1) assert or (0) deassert reset lines */ static void buspirate_reset(int trst, int srst) @@ -807,33 +864,148 @@ static void buspirate_reset(int trst, int srst) LOG_DEBUG("trst: %i, srst: %i", trst, srst); if (trst) - buspirate_jtag_set_feature(buspirate_fd, - FEATURE_TRST, ACTION_DISABLE); + buspirate_set_feature(buspirate_fd, FEATURE_TRST, ACTION_DISABLE); else - buspirate_jtag_set_feature(buspirate_fd, - FEATURE_TRST, ACTION_ENABLE); + buspirate_set_feature(buspirate_fd, FEATURE_TRST, ACTION_ENABLE); if (srst) - buspirate_jtag_set_feature(buspirate_fd, - FEATURE_SRST, ACTION_DISABLE); + buspirate_set_feature(buspirate_fd, FEATURE_SRST, ACTION_DISABLE); else - buspirate_jtag_set_feature(buspirate_fd, - FEATURE_SRST, ACTION_ENABLE); + buspirate_set_feature(buspirate_fd, FEATURE_SRST, ACTION_ENABLE); +} + +static void buspirate_set_feature(int fd, char feat, char action) +{ + if (swd_mode) + buspirate_swd_set_feature(fd, feat, action); + else + buspirate_jtag_set_feature(fd, feat, action); +} + +static void buspirate_set_mode(int fd, char mode) +{ + if (swd_mode) + buspirate_swd_set_mode(fd, mode); + else + buspirate_jtag_set_mode(fd, mode); +} + +static void buspirate_set_speed(int fd, char speed) +{ + if (swd_mode) + buspirate_swd_set_speed(fd, speed); + else + buspirate_jtag_set_speed(fd, speed); +} + + +/*************** swd lowlevel functions ********************/ + +static void buspirate_swd_set_speed(int fd, char speed) +{ + int ret; + uint8_t tmp[1]; + + LOG_DEBUG("Buspirate speed setting in SWD mode defaults to 400 kHz"); + + /* speed settings */ + tmp[0] = CMD_RAW_SPEED | SPEED_RAW_400_KHZ; + buspirate_serial_write(fd, tmp, 1); + ret = buspirate_serial_read(fd, tmp, 1); + if (ret != 1) { + LOG_ERROR("Buspirate did not answer correctly"); + exit(-1); + } + if (tmp[0] != 1) { + LOG_ERROR("Buspirate did not reply as expected to the speed change command"); + exit(-1); + } +} + +static void buspirate_swd_set_mode(int fd, char mode) +{ + int ret; + uint8_t tmp[1]; + + /* raw-wire mode configuration */ + if (mode == MODE_HIZ) + tmp[0] = CMD_RAW_MODE | CMD_RAW_CONFIG_LSB; + else + tmp[0] = CMD_RAW_MODE | CMD_RAW_CONFIG_LSB | CMD_RAW_CONFIG_3V3; + + buspirate_serial_write(fd, tmp, 1); + ret = buspirate_serial_read(fd, tmp, 1); + if (ret != 1) { + LOG_ERROR("Buspirate did not answer correctly"); + exit(-1); + } + if (tmp[0] != 1) { + LOG_ERROR("Buspirate did not reply as expected to the configure command"); + exit(-1); + } +} + +static void buspirate_swd_set_feature(int fd, char feat, char action) +{ + int ret; + uint8_t tmp[1]; + + switch (feat) { + case FEATURE_TRST: + LOG_DEBUG("Buspirate TRST feature not available in SWD mode"); + return; + case FEATURE_LED: + LOG_ERROR("Buspirate LED feature not available in SWD mode"); + return; + case FEATURE_SRST: + swd_features = (action == ACTION_ENABLE) ? swd_features | 0x02 : swd_features & 0x0D; + break; + case FEATURE_PULLUP: + swd_features = (action == ACTION_ENABLE) ? swd_features | 0x04 : swd_features & 0x0B; + break; + case FEATURE_VREG: + swd_features = (action == ACTION_ENABLE) ? swd_features | 0x08 : swd_features & 0x07; + break; + default: + LOG_DEBUG("Buspirate unknown feature %d", feat); + return; + } + + tmp[0] = CMD_RAW_PERIPH | swd_features; + buspirate_serial_write(fd, tmp, 1); + ret = buspirate_serial_read(fd, tmp, 1); + if (ret != 1) { + LOG_DEBUG("Buspirate feature %d not supported in SWD mode", feat); + } else if (tmp[0] != 1) { + LOG_ERROR("Buspirate did not reply as expected to the configure command"); + exit(-1); + } } /*************** jtag lowlevel functions ********************/ -static void buspirate_jtag_enable(int fd) +static void buspirate_bbio_enable(int fd) { int ret; - char tmp[21] = { [0 ... 20] = 0x00 }; + char command; + const char *mode_answers[2] = { "OCD1", "RAW1" }; + const char *correct_ans = NULL; + uint8_t tmp[21] = { [0 ... 20] = 0x00 }; int done = 0; int cmd_sent = 0; - LOG_DEBUG("Entering binary mode"); + if (swd_mode) { + command = CMD_ENTER_RWIRE; + correct_ans = mode_answers[1]; + } else { + command = CMD_ENTER_OOCD; + correct_ans = mode_answers[0]; + } + + LOG_DEBUG("Entering binary mode, that is %s", correct_ans); buspirate_serial_write(fd, tmp, 20); usleep(10000); - /* reads 1 to n "BBIO1"s and one "OCD1" */ + /* reads 1 to n "BBIO1"s and one "OCD1" or "RAW1" */ while (!done) { ret = buspirate_serial_read(fd, tmp, 4); if (ret != 4) { @@ -841,7 +1013,7 @@ static void buspirate_jtag_enable(int fd) "/OpenOCD support enabled?"); exit(-1); } - if (strncmp(tmp, "BBIO", 4) == 0) { + if (strncmp((char *)tmp, "BBIO", 4) == 0) { ret = buspirate_serial_read(fd, tmp, 1); if (ret != 1) { LOG_ERROR("Buspirate did not answer correctly! " @@ -854,14 +1026,14 @@ static void buspirate_jtag_enable(int fd) } if (cmd_sent == 0) { cmd_sent = 1; - tmp[0] = CMD_ENTER_OOCD; + tmp[0] = command; ret = buspirate_serial_write(fd, tmp, 1); if (ret != 1) { LOG_ERROR("error reading"); exit(-1); } } - } else if (strncmp(tmp, "OCD1", 4) == 0) + } else if (strncmp((char *)tmp, correct_ans, 4) == 0) done = 1; else { LOG_ERROR("Buspirate did not answer correctly! " @@ -874,14 +1046,14 @@ static void buspirate_jtag_enable(int fd) static void buspirate_jtag_reset(int fd) { - char tmp[5]; + uint8_t tmp[5]; tmp[0] = 0x00; /* exit OCD1 mode */ buspirate_serial_write(fd, tmp, 1); usleep(10000); /* We ignore the return value here purposly, nothing we can do */ buspirate_serial_read(fd, tmp, 5); - if (strncmp(tmp, "BBIO1", 5) == 0) { + if (strncmp((char *)tmp, "BBIO1", 5) == 0) { tmp[0] = 0x0F; /* reset BP */ buspirate_serial_write(fd, tmp, 1); } else @@ -891,8 +1063,8 @@ static void buspirate_jtag_reset(int fd) static void buspirate_jtag_set_speed(int fd, char speed) { int ret; - char tmp[2]; - char ack[2]; + uint8_t tmp[2]; + uint8_t ack[2]; ack[0] = 0xAA; ack[1] = 0x55; @@ -924,7 +1096,7 @@ static void buspirate_jtag_set_speed(int fd, char speed) static void buspirate_jtag_set_mode(int fd, char mode) { - char tmp[2]; + uint8_t tmp[2]; tmp[0] = CMD_PORT_MODE; tmp[1] = mode; buspirate_jtag_command(fd, tmp, 2); @@ -932,7 +1104,7 @@ static void buspirate_jtag_set_mode(int fd, char mode) static void buspirate_jtag_set_feature(int fd, char feat, char action) { - char tmp[3]; + uint8_t tmp[3]; tmp[0] = CMD_FEATURE; tmp[1] = feat; /* what */ tmp[2] = action; /* action */ @@ -944,7 +1116,7 @@ static void buspirate_jtag_get_adcs(int fd) uint8_t tmp[10]; uint16_t a, b, c, d; tmp[0] = CMD_READ_ADCS; - buspirate_jtag_command(fd, (char *)tmp, 1); + buspirate_jtag_command(fd, tmp, 1); a = tmp[2] << 8 | tmp[3]; b = tmp[4] << 8 | tmp[5]; c = tmp[6] << 8 | tmp[7]; @@ -957,7 +1129,7 @@ static void buspirate_jtag_get_adcs(int fd) } static unsigned char buspirate_jtag_command(int fd, - char *cmd, int cmdlen) + uint8_t *cmd, int cmdlen) { int res; int len = 0; @@ -1048,7 +1220,7 @@ static int buspirate_serial_setspeed(int fd, char speed, cc_t timeout) return 0; } -static int buspirate_serial_write(int fd, char *buf, int size) +static int buspirate_serial_write(int fd, uint8_t *buf, int size) { int ret = 0; @@ -1063,7 +1235,7 @@ static int buspirate_serial_write(int fd, char *buf, int size) return ret; } -static int buspirate_serial_read(int fd, char *buf, int size) +static int buspirate_serial_read(int fd, uint8_t *buf, int size) { int len = 0; int ret = 0; @@ -1102,7 +1274,7 @@ static void buspirate_serial_close(int fd) #define LINE_SIZE 81 #define BYTES_PER_LINE 16 -static void buspirate_print_buffer(char *buf, int size) +static void buspirate_print_buffer(uint8_t *buf, int size) { char line[LINE_SIZE]; char tmp[10]; @@ -1124,3 +1296,240 @@ static void buspirate_print_buffer(char *buf, int size) if (line[0] != 0) LOG_DEBUG("%s", line); } + +/************************* SWD related stuff **********/ + +static int buspirate_swd_init(void) +{ + LOG_INFO("Buspirate SWD mode enabled"); + swd_mode = true; + + return ERROR_OK; +} + +static int buspirate_swd_switch_seq(enum swd_special_seq seq) +{ + const uint8_t *sequence; + int sequence_len; + uint8_t tmp[64]; + + switch (seq) { + case LINE_RESET: + LOG_DEBUG("SWD line reset"); + sequence = swd_seq_line_reset; + sequence_len = DIV_ROUND_UP(swd_seq_line_reset_len, 8); + break; + case JTAG_TO_SWD: + LOG_DEBUG("JTAG-to-SWD"); + sequence = swd_seq_jtag_to_swd; + sequence_len = DIV_ROUND_UP(swd_seq_jtag_to_swd_len, 8); + break; + case SWD_TO_JTAG: + LOG_DEBUG("SWD-to-JTAG"); + sequence = swd_seq_swd_to_jtag; + sequence_len = DIV_ROUND_UP(swd_seq_swd_to_jtag_len, 8); + break; + default: + LOG_ERROR("Sequence %d not supported", seq); + return ERROR_FAIL; + } + + /* FIXME: all above sequences fit into one pirate command for now + * but it may cause trouble later + */ + + tmp[0] = 0x10 + ((sequence_len - 1) & 0x0F); + memcpy(tmp + 1, sequence, sequence_len); + + buspirate_serial_write(buspirate_fd, tmp, sequence_len + 1); + buspirate_serial_read(buspirate_fd, tmp, sequence_len + 1); + + return ERROR_OK; +} + +static uint8_t buspirate_swd_write_header(uint8_t cmd) +{ + uint8_t tmp[8]; + int to_send; + + tmp[0] = 0x10; /* bus pirate: send 1 byte */ + tmp[1] = cmd; /* swd cmd */ + tmp[2] = 0x07; /* ack __x */ + tmp[3] = 0x07; /* ack _x_ */ + tmp[4] = 0x07; /* ack x__ */ + tmp[5] = 0x07; /* write mode trn_1 */ + tmp[6] = 0x07; /* write mode trn_2 */ + + to_send = ((cmd & SWD_CMD_RnW) == 0) ? 7 : 5; + buspirate_serial_write(buspirate_fd, tmp, to_send); + + /* read ack */ + buspirate_serial_read(buspirate_fd, tmp, 2); /* drop pirate command ret vals */ + buspirate_serial_read(buspirate_fd, tmp, to_send - 2); /* ack bits */ + + return tmp[2] << 2 | tmp[1] << 1 | tmp[0]; +} + +static void buspirate_swd_idle_clocks(uint32_t no_bits) +{ + uint32_t no_bytes; + uint8_t tmp[20]; + + no_bytes = (no_bits + 7) / 8; + memset(tmp + 1, 0x00, sizeof(tmp) - 1); + + /* unfortunately bus pirate misbehaves when clocks are sent in parts + * so we need to limit at 128 clock cycles + */ + if (no_bytes > 16) + no_bytes = 16; + + while (no_bytes) { + uint8_t to_send = no_bytes > 16 ? 16 : no_bytes; + tmp[0] = 0x10 + ((to_send - 1) & 0x0F); + + buspirate_serial_write(buspirate_fd, tmp, to_send + 1); + buspirate_serial_read(buspirate_fd, tmp, to_send + 1); + + no_bytes -= to_send; + } +} + +static void buspirate_swd_clear_sticky_errors(void) +{ + buspirate_swd_write_reg(swd_cmd(false, false, DP_ABORT), + STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0); +} + +static void buspirate_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) +{ + uint8_t tmp[16]; + + LOG_DEBUG("buspirate_swd_read_reg"); + assert(cmd & SWD_CMD_RnW); + + if (queued_retval != ERROR_OK) { + LOG_DEBUG("Skip buspirate_swd_read_reg because queued_retval=%d", queued_retval); + return; + } + + cmd |= SWD_CMD_START | SWD_CMD_PARK; + uint8_t ack = buspirate_swd_write_header(cmd); + + /* do a read transaction */ + tmp[0] = 0x06; /* 4 data bytes */ + tmp[1] = 0x06; + tmp[2] = 0x06; + tmp[3] = 0x06; + tmp[4] = 0x07; /* parity bit */ + tmp[5] = 0x21; /* 2 turnaround clocks */ + + buspirate_serial_write(buspirate_fd, tmp, 6); + buspirate_serial_read(buspirate_fd, tmp, 6); + + /* store the data and parity */ + uint32_t data = (uint8_t) tmp[0]; + data |= (uint8_t) tmp[1] << 8; + data |= (uint8_t) tmp[2] << 16; + data |= (uint8_t) tmp[3] << 24; + int parity = tmp[4] ? 0x01 : 0x00; + + LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, + ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", + cmd & SWD_CMD_APnDP ? "AP" : "DP", + cmd & SWD_CMD_RnW ? "read" : "write", + (cmd & SWD_CMD_A32) >> 1, + data); + + switch (ack) { + case SWD_ACK_OK: + if (parity != parity_u32(data)) { + LOG_DEBUG("Read data parity mismatch %x %x", parity, parity_u32(data)); + queued_retval = ERROR_FAIL; + return; + } + if (value) + *value = data; + if (cmd & SWD_CMD_APnDP) + buspirate_swd_idle_clocks(ap_delay_clk); + return; + case SWD_ACK_WAIT: + LOG_DEBUG("SWD_ACK_WAIT"); + buspirate_swd_clear_sticky_errors(); + return; + case SWD_ACK_FAULT: + LOG_DEBUG("SWD_ACK_FAULT"); + queued_retval = ack; + return; + default: + LOG_DEBUG("No valid acknowledge: ack=%d", ack); + queued_retval = ack; + return; + } +} + +static void buspirate_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) +{ + uint8_t tmp[16]; + + LOG_DEBUG("buspirate_swd_write_reg"); + assert(!(cmd & SWD_CMD_RnW)); + + if (queued_retval != ERROR_OK) { + LOG_DEBUG("Skip buspirate_swd_write_reg because queued_retval=%d", queued_retval); + return; + } + + cmd |= SWD_CMD_START | SWD_CMD_PARK; + uint8_t ack = buspirate_swd_write_header(cmd); + + /* do a write transaction */ + tmp[0] = 0x10 + ((4 + 1 - 1) & 0xF); /* bus pirate: send 4+1 bytes */ + buf_set_u32((uint8_t *) tmp + 1, 0, 32, value); + /* write sequence ends with parity bit and 7 idle ticks */ + tmp[5] = parity_u32(value) ? 0x01 : 0x00; + + buspirate_serial_write(buspirate_fd, tmp, 6); + buspirate_serial_read(buspirate_fd, tmp, 6); + + LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, + ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", + cmd & SWD_CMD_APnDP ? "AP" : "DP", + cmd & SWD_CMD_RnW ? "read" : "write", + (cmd & SWD_CMD_A32) >> 1, + value); + + switch (ack) { + case SWD_ACK_OK: + if (cmd & SWD_CMD_APnDP) + buspirate_swd_idle_clocks(ap_delay_clk); + return; + case SWD_ACK_WAIT: + LOG_DEBUG("SWD_ACK_WAIT"); + buspirate_swd_clear_sticky_errors(); + return; + case SWD_ACK_FAULT: + LOG_DEBUG("SWD_ACK_FAULT"); + queued_retval = ack; + return; + default: + LOG_DEBUG("No valid acknowledge: ack=%d", ack); + queued_retval = ack; + return; + } +} + +static int buspirate_swd_run_queue(void) +{ + LOG_DEBUG("buspirate_swd_run_queue"); + /* A transaction must be followed by another transaction or at least 8 idle cycles to + * ensure that data is clocked through the AP. */ + buspirate_swd_idle_clocks(8); + + int retval = queued_retval; + queued_retval = ERROR_OK; + LOG_DEBUG("SWD queue return value: %02x", retval); + return retval; +} + + diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c new file mode 100644 index 000000000..fc3d75f43 --- /dev/null +++ b/src/jtag/drivers/ft232r.c @@ -0,0 +1,669 @@ +/*************************************************************************** + * Copyright (C) 2010 Serge Vakulenko * + * serge@vak.ru * + * * + * 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 . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if IS_CYGWIN == 1 +#include "windows.h" +#undef LOG_ERROR +#endif + +/* project specific includes */ +#include +#include +#include +#include "libusb1_common.h" + +/* system includes */ +#include +#include +#include +#include +#include + +/* + * Bit 7 (0x80, pin 6, RI ): unused. + * Bit 6 (0x40, pin 10,DCD): /SYSRST output. + * Bit 5 (0x20, pin 9, DSR): unused. + * Bit 4 (0x10, pin 2, DTR): /TRST output. + * Bit 3 (0x08, pin 11,CTS): TMS output. + * Bit 2 (0x04, pin 3, RTS): TDO input. + * Bit 1 (0x02, pin 5, RXD): TDI output. + * Bit 0 (0x01, pin 1, TXD): TCK output. + * + * Sync bit bang mode is implemented as described in FTDI Application + * Note AN232R-01: "Bit Bang Modes for the FT232R and FT245R". + */ +#define TCK (1 << 0) +#define TDI (1 << 1) +#define READ_TDO (1 << 2) +#define TMS (1 << 3) +#define NTRST (1 << 4) +#define NSYSRST (1 << 6) + +/* + * USB endpoints. + */ +#define IN_EP 0x02 +#define OUT_EP 0x81 + +/* Requests */ +#define SIO_RESET 0 /* Reset the port */ +#define SIO_MODEM_CTRL 1 /* Set the modem control register */ +#define SIO_SET_FLOW_CTRL 2 /* Set flow control register */ +#define SIO_SET_BAUD_RATE 3 /* Set baud rate */ +#define SIO_SET_DATA 4 /* Set the data characteristics of the port */ +#define SIO_POLL_MODEM_STATUS 5 +#define SIO_SET_EVENT_CHAR 6 +#define SIO_SET_ERROR_CHAR 7 +#define SIO_SET_LATENCY_TIMER 9 +#define SIO_GET_LATENCY_TIMER 10 +#define SIO_SET_BITMODE 11 +#define SIO_READ_PINS 12 +#define SIO_READ_EEPROM 0x90 +#define SIO_WRITE_EEPROM 0x91 +#define SIO_ERASE_EEPROM 0x92 + +#define FT232R_BUF_SIZE 4000 + +static char *ft232r_serial_desc; +static uint16_t ft232r_vid = 0x0403; /* FTDI */ +static uint16_t ft232r_pid = 0x6001; /* FT232R */ +static jtag_libusb_device_handle *adapter; + +static uint8_t *ft232r_output; +static size_t ft232r_output_len; + +/** + * Perform sync bitbang output/input transaction. + * Before call, an array ft232r_output[] should be filled with data to send. + * Counter ft232r_output_len contains the number of bytes to send. + * On return, received data is put back to array ft232r_output[]. + */ +static int ft232r_send_recv(void) +{ + /* FIFO TX buffer has 128 bytes. + * FIFO RX buffer has 256 bytes. + * First two bytes of received packet contain contain modem + * and line status and are ignored. + * Unfortunately, transfer sizes bigger than 64 bytes + * frequently cause hang ups. */ + assert(ft232r_output_len > 0); + + size_t total_written = 0; + size_t total_read = 0; + int rxfifo_free = 128; + + while (total_read < ft232r_output_len) { + /* Write */ + int bytes_to_write = ft232r_output_len - total_written; + if (bytes_to_write > 64) + bytes_to_write = 64; + if (bytes_to_write > rxfifo_free) + bytes_to_write = rxfifo_free; + + if (bytes_to_write) { + int n = jtag_libusb_bulk_write(adapter, IN_EP, + (char *) ft232r_output + total_written, + bytes_to_write, 1000); + + if (n == 0) { + LOG_ERROR("usb bulk write failed"); + return ERROR_JTAG_DEVICE_ERROR; + } + + total_written += n; + rxfifo_free -= n; + } + + /* Read */ + uint8_t reply[64]; + + int n = jtag_libusb_bulk_read(adapter, OUT_EP, + (char *) reply, + sizeof(reply), 1000); + + if (n == 0) { + LOG_ERROR("usb bulk read failed"); + return ERROR_JTAG_DEVICE_ERROR; + } + if (n > 2) { + /* Copy data, ignoring first 2 bytes. */ + memcpy(ft232r_output + total_read, reply + 2, n - 2); + int bytes_read = n - 2; + total_read += bytes_read; + rxfifo_free += bytes_read; + if (total_read > total_written) { + LOG_ERROR("read more bytes than wrote"); + return ERROR_JTAG_DEVICE_ERROR; + } + } + } + ft232r_output_len = 0; + return ERROR_OK; +} + +/** + * Add one TCK/TMS/TDI sample to send buffer. + */ +static void ft232r_write(int tck, int tms, int tdi) +{ + unsigned out_value = NTRST | NSYSRST; + if (tck) + out_value |= TCK; + if (tms) + out_value |= TMS; + if (tdi) + out_value |= TDI; + + if (ft232r_output_len >= FT232R_BUF_SIZE) { + /* FIXME: should we just execute queue here? */ + LOG_ERROR("ft232r_write: buffer overflow"); + return; + } + ft232r_output[ft232r_output_len++] = out_value; +} + +/** + * Control /TRST and /SYSRST pins. + * Perform immediate bitbang transaction. + */ +static void ft232r_reset(int trst, int srst) +{ + unsigned out_value = NTRST | NSYSRST; + LOG_DEBUG("ft232r_reset(%d,%d)", trst, srst); + + if (trst == 1) + out_value &= ~NTRST; /* switch /TRST low */ + else if (trst == 0) + out_value |= NTRST; /* switch /TRST high */ + + if (srst == 1) + out_value &= ~NSYSRST; /* switch /SYSRST low */ + else if (srst == 0) + out_value |= NSYSRST; /* switch /SYSRST high */ + + if (ft232r_output_len >= FT232R_BUF_SIZE) { + /* FIXME: should we just execute queue here? */ + LOG_ERROR("ft232r_write: buffer overflow"); + return; + } + + ft232r_output[ft232r_output_len++] = out_value; + ft232r_send_recv(); +} + +static int ft232r_speed(int divisor) +{ + int baud = (divisor == 0) ? 3000000 : + (divisor == 1) ? 2000000 : + 3000000 / divisor; + LOG_DEBUG("ft232r_speed(%d) rate %d bits/sec", divisor, baud); + + if (jtag_libusb_control_transfer(adapter, + LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, + SIO_SET_BAUD_RATE, divisor, 0, 0, 0, 1000) != 0) { + LOG_ERROR("cannot set baud rate"); + return ERROR_JTAG_DEVICE_ERROR; + } + return ERROR_OK; +} + +static int ft232r_init(void) +{ + uint16_t avids[] = {ft232r_vid, 0}; + uint16_t apids[] = {ft232r_pid, 0}; + if (jtag_libusb_open(avids, apids, ft232r_serial_desc, &adapter)) { + LOG_ERROR("ft232r not found: vid=%04x, pid=%04x, serial=%s\n", + ft232r_vid, ft232r_pid, (ft232r_serial_desc == NULL) ? "[any]" : ft232r_serial_desc); + return ERROR_JTAG_INIT_FAILED; + } + + libusb_detach_kernel_driver(adapter, 0); + + if (jtag_libusb_claim_interface(adapter, 0)) { + LOG_ERROR("unable to claim interface"); + return ERROR_JTAG_INIT_FAILED; + } + + /* Reset the device. */ + if (jtag_libusb_control_transfer(adapter, + LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, + SIO_RESET, 0, 0, 0, 0, 1000) != 0) { + LOG_ERROR("unable to reset device"); + return ERROR_JTAG_INIT_FAILED; + } + + /* Sync bit bang mode. */ + if (jtag_libusb_control_transfer(adapter, + LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, + SIO_SET_BITMODE, TCK | TDI | TMS | NTRST | NSYSRST | 0x400, + 0, 0, 0, 1000) != 0) { + LOG_ERROR("cannot set sync bitbang mode"); + return ERROR_JTAG_INIT_FAILED; + } + + /* Exactly 500 nsec between updates. */ + unsigned divisor = 1; + unsigned char latency_timer = 1; + + /* Frequency divisor is 14-bit non-zero value. */ + if (jtag_libusb_control_transfer(adapter, + LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, + SIO_SET_BAUD_RATE, divisor, + 0, 0, 0, 1000) != 0) { + LOG_ERROR("cannot set baud rate"); + return ERROR_JTAG_INIT_FAILED; + } + if (jtag_libusb_control_transfer(adapter, + LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, + SIO_SET_LATENCY_TIMER, latency_timer, 0, 0, 0, 1000) != 0) { + LOG_ERROR("unable to set latency timer"); + return ERROR_JTAG_INIT_FAILED; + } + + ft232r_output = malloc(FT232R_BUF_SIZE); + if (ft232r_output == NULL) { + LOG_ERROR("Unable to allocate memory for the buffer"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +static int ft232r_quit(void) +{ + if (jtag_libusb_release_interface(adapter, 0) != 0) + LOG_ERROR("usb release interface failed"); + + jtag_libusb_close(adapter); + free(ft232r_output); + + return ERROR_OK; +} + +static int ft232r_speed_div(int divisor, int *khz) +{ + /* Maximum 3 Mbaud for bit bang mode. */ + if (divisor == 0) + *khz = 3000; + else if (divisor == 1) + *khz = 2000; + else + *khz = 3000 / divisor; + return ERROR_OK; +} + +static int ft232r_khz(int khz, int *divisor) +{ + if (khz == 0) { + LOG_DEBUG("RCLK not supported"); + return ERROR_FAIL; + } + + /* Calculate frequency divisor. */ + if (khz > 2500) + *divisor = 0; /* Special case: 3 MHz */ + else if (khz > 1700) + *divisor = 1; /* Special case: 2 MHz */ + else { + *divisor = (2*3000 / khz + 1) / 2; + if (*divisor > 0x3FFF) + *divisor = 0x3FFF; + } + return ERROR_OK; +} + +COMMAND_HANDLER(ft232r_handle_serial_desc_command) +{ + if (CMD_ARGC == 1) + ft232r_serial_desc = strdup(CMD_ARGV[0]); + else + LOG_ERROR("require exactly one argument to " + "ft232r_serial_desc "); + return ERROR_OK; +} + +COMMAND_HANDLER(ft232r_handle_vid_pid_command) +{ + if (CMD_ARGC > 2) { + LOG_WARNING("ignoring extra IDs in ft232r_vid_pid " + "(maximum is 1 pair)"); + CMD_ARGC = 2; + } + if (CMD_ARGC == 2) { + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], ft232r_vid); + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], ft232r_pid); + } else + LOG_WARNING("incomplete ft232r_vid_pid configuration"); + + return ERROR_OK; +} + +static const struct command_registration ft232r_command_handlers[] = { + { + .name = "ft232r_serial_desc", + .handler = ft232r_handle_serial_desc_command, + .mode = COMMAND_CONFIG, + .help = "USB serial descriptor of the adapter", + .usage = "serial string", + }, + { + .name = "ft232r_vid_pid", + .handler = ft232r_handle_vid_pid_command, + .mode = COMMAND_CONFIG, + .help = "USB VID and PID of the adapter", + .usage = "vid pid", + }, + COMMAND_REGISTRATION_DONE +}; + +/* + * Synchronous bitbang protocol implementation. + */ + +static void syncbb_end_state(tap_state_t state) +{ + if (tap_is_state_stable(state)) + tap_set_end_state(state); + else { + LOG_ERROR("BUG: %i is not a valid end state", state); + exit(-1); + } +} + +static void syncbb_state_move(int skip) +{ + int i = 0, tms = 0; + uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + + for (i = skip; i < tms_count; i++) { + tms = (tms_scan >> i) & 1; + ft232r_write(0, tms, 0); + ft232r_write(1, tms, 0); + } + ft232r_write(0, tms, 0); + + tap_set_state(tap_get_end_state()); +} + +/** + * Clock a bunch of TMS (or SWDIO) transitions, to change the JTAG + * (or SWD) state machine. + */ +static int syncbb_execute_tms(struct jtag_command *cmd) +{ + unsigned num_bits = cmd->cmd.tms->num_bits; + const uint8_t *bits = cmd->cmd.tms->bits; + + DEBUG_JTAG_IO("TMS: %d bits", num_bits); + + int tms = 0; + for (unsigned i = 0; i < num_bits; i++) { + tms = ((bits[i/8] >> (i % 8)) & 1); + ft232r_write(0, tms, 0); + ft232r_write(1, tms, 0); + } + ft232r_write(0, tms, 0); + + return ERROR_OK; +} + +static void syncbb_path_move(struct pathmove_command *cmd) +{ + int num_states = cmd->num_states; + int state_count; + int tms = 0; + + state_count = 0; + while (num_states) { + if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count]) { + tms = 0; + } else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count]) { + tms = 1; + } else { + LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", + tap_state_name(tap_get_state()), + tap_state_name(cmd->path[state_count])); + exit(-1); + } + + ft232r_write(0, tms, 0); + ft232r_write(1, tms, 0); + + tap_set_state(cmd->path[state_count]); + state_count++; + num_states--; + } + + ft232r_write(0, tms, 0); + + tap_set_end_state(tap_get_state()); +} + +static void syncbb_runtest(int num_cycles) +{ + int i; + + tap_state_t saved_end_state = tap_get_end_state(); + + /* only do a state_move when we're not already in IDLE */ + if (tap_get_state() != TAP_IDLE) { + syncbb_end_state(TAP_IDLE); + syncbb_state_move(0); + } + + /* execute num_cycles */ + for (i = 0; i < num_cycles; i++) { + ft232r_write(0, 0, 0); + ft232r_write(1, 0, 0); + } + ft232r_write(0, 0, 0); + + /* finish in end_state */ + syncbb_end_state(saved_end_state); + if (tap_get_state() != tap_get_end_state()) + syncbb_state_move(0); +} + +/** + * Function syncbb_stableclocks + * issues a number of clock cycles while staying in a stable state. + * Because the TMS value required to stay in the RESET state is a 1, whereas + * the TMS value required to stay in any of the other stable states is a 0, + * this function checks the current stable state to decide on the value of TMS + * to use. + */ +static void syncbb_stableclocks(int num_cycles) +{ + int tms = (tap_get_state() == TAP_RESET ? 1 : 0); + int i; + + /* send num_cycles clocks onto the cable */ + for (i = 0; i < num_cycles; i++) { + ft232r_write(1, tms, 0); + ft232r_write(0, tms, 0); + } +} + +static void syncbb_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size) +{ + tap_state_t saved_end_state = tap_get_end_state(); + int bit_cnt, bit0_index; + + if (!((!ir_scan && (tap_get_state() == TAP_DRSHIFT)) || (ir_scan && (tap_get_state() == TAP_IRSHIFT)))) { + if (ir_scan) + syncbb_end_state(TAP_IRSHIFT); + else + syncbb_end_state(TAP_DRSHIFT); + + syncbb_state_move(0); + syncbb_end_state(saved_end_state); + } + + bit0_index = ft232r_output_len; + for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) { + int tms = (bit_cnt == scan_size-1) ? 1 : 0; + int tdi; + int bytec = bit_cnt/8; + int bcval = 1 << (bit_cnt % 8); + + /* if we're just reading the scan, but don't care about the output + * default to outputting 'low', this also makes valgrind traces more readable, + * as it removes the dependency on an uninitialised value + */ + tdi = 0; + if ((type != SCAN_IN) && (buffer[bytec] & bcval)) + tdi = 1; + + ft232r_write(0, tms, tdi); + ft232r_write(1, tms, tdi); + } + + if (tap_get_state() != tap_get_end_state()) { + /* we *KNOW* the above loop transitioned out of + * the shift state, so we skip the first state + * and move directly to the end state. + */ + syncbb_state_move(1); + } + ft232r_send_recv(); + + if (type != SCAN_OUT) + for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) { + int bytec = bit_cnt/8; + int bcval = 1 << (bit_cnt % 8); + int val = ft232r_output[bit0_index + bit_cnt*2 + 1]; + + if (val & READ_TDO) + buffer[bytec] |= bcval; + else + buffer[bytec] &= ~bcval; + } +} + +static int syncbb_execute_queue(void) +{ + struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ + int scan_size; + enum scan_type type; + uint8_t *buffer; + int retval; + + /* return ERROR_OK, unless a jtag_read_buffer returns a failed check + * that wasn't handled by a caller-provided error handler + */ + retval = ERROR_OK; + +/* ft232r_blink(1);*/ + + while (cmd) { + switch (cmd->type) { + case JTAG_RESET: + LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); + + if ((cmd->cmd.reset->trst == 1) || + (cmd->cmd.reset->srst && + (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) { + tap_set_state(TAP_RESET); + } + ft232r_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + + case JTAG_RUNTEST: + LOG_DEBUG_IO("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, + tap_state_name(cmd->cmd.runtest->end_state)); + + syncbb_end_state(cmd->cmd.runtest->end_state); + syncbb_runtest(cmd->cmd.runtest->num_cycles); + break; + + case JTAG_STABLECLOCKS: + /* this is only allowed while in a stable state. A check for a stable + * state was done in jtag_add_clocks() + */ + syncbb_stableclocks(cmd->cmd.stableclocks->num_cycles); + break; + + case JTAG_TLR_RESET: /* renamed from JTAG_STATEMOVE */ + LOG_DEBUG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); + + syncbb_end_state(cmd->cmd.statemove->end_state); + syncbb_state_move(0); + break; + + case JTAG_PATHMOVE: + LOG_DEBUG_IO("pathmove: %i states, end in %s", cmd->cmd.pathmove->num_states, + tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); + + syncbb_path_move(cmd->cmd.pathmove); + break; + + case JTAG_SCAN: + LOG_DEBUG_IO("%s scan end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", + tap_state_name(cmd->cmd.scan->end_state)); + + syncbb_end_state(cmd->cmd.scan->end_state); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + type = jtag_scan_type(cmd->cmd.scan); + syncbb_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); + if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + if (buffer) + free(buffer); + break; + + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIi32, cmd->cmd.sleep->us); + + jtag_sleep(cmd->cmd.sleep->us); + break; + + case JTAG_TMS: + retval = syncbb_execute_tms(cmd); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); + } + if (ft232r_output_len > 0) + ft232r_send_recv(); + cmd = cmd->next; + } +/* ft232r_blink(0);*/ + + return retval; +} + +struct jtag_interface ft232r_interface = { + .name = "ft232r", + .commands = ft232r_command_handlers, + .transports = jtag_only, + .supported = DEBUG_CAP_TMS_SEQ, + + .execute_queue = syncbb_execute_queue, + + .speed = ft232r_speed, + .init = ft232r_init, + .quit = ft232r_quit, + .speed_div = ft232r_speed_div, + .khz = ft232r_khz, +}; diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index e69707e5a..7c6709cd5 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -694,6 +694,18 @@ static int ftdi_quit(void) { mpsse_close(mpsse_ctx); + struct signal *sig = signals; + while (sig) { + struct signal *next = sig->next; + free((void *)sig->name); + free(sig); + sig = next; + } + + free(ftdi_device_desc); + free(ftdi_serial); + free(ftdi_location); + free(swd_cmd_queue); return ERROR_OK; diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c index db5b62e2e..522eb17bb 100644 --- a/src/jtag/drivers/kitprog.c +++ b/src/jtag/drivers/kitprog.c @@ -741,12 +741,22 @@ static int kitprog_swd_run_queue(void) break; } - /* We use the maximum buffer size here because the KitProg sometimes - * doesn't like bulk reads of fewer than 62 bytes. (?!?!) + /* KitProg firmware does not send a zero length packet + * after the bulk-in transmission of a length divisible by bulk packet + * size (64 bytes) as required by the USB specification. + * Therefore libusb would wait for continuation of transmission. + * Workaround: Limit bulk read size to expected number of bytes + * for problematic tranfer sizes. Otherwise use the maximum buffer + * size here because the KitProg sometimes doesn't like bulk reads + * of fewer than 62 bytes. (?!?!) */ + size_t read_count_workaround = SWD_MAX_BUFFER_LENGTH; + if (read_count % 64 == 0) + read_count_workaround = read_count; + ret = jtag_libusb_bulk_read(kitprog_handle->usb_handle, BULK_EP_IN | LIBUSB_ENDPOINT_IN, (char *)buffer, - SWD_MAX_BUFFER_LENGTH, 0); + read_count_workaround, 1000); if (ret > 0) { /* Handle garbage data by offsetting the initial read index */ if ((unsigned int)ret > read_count) diff --git a/src/jtag/drivers/mpsse.c b/src/jtag/drivers/mpsse.c index 924c97450..06d008b47 100644 --- a/src/jtag/drivers/mpsse.c +++ b/src/jtag/drivers/mpsse.c @@ -335,7 +335,13 @@ struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const cha ctx->write_size = 16384; ctx->read_chunk = malloc(ctx->read_chunk_size); ctx->read_buffer = malloc(ctx->read_size); - ctx->write_buffer = malloc(ctx->write_size); + + /* Use calloc to make valgrind happy: buffer_write() sets payload + * on bit basis, so some bits can be left uninitialized in write_buffer. + * Although this is perfectly ok with MPSSE, valgrind reports + * Syscall param ioctl(USBDEVFS_SUBMITURB).buffer points to uninitialised byte(s) */ + ctx->write_buffer = calloc(1, ctx->write_size); + if (!ctx->read_chunk || !ctx->read_buffer || !ctx->write_buffer) goto error; diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 6f720b86b..99f96b9c9 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -457,8 +457,8 @@ static int stlink_usb_error_check(void *handle) LOG_DEBUG("Write error"); return ERROR_FAIL; case STLINK_JTAG_WRITE_VERIF_ERROR: - LOG_DEBUG("Verify error"); - return ERROR_FAIL; + LOG_DEBUG("Write verify error, ignoring"); + return ERROR_OK; case STLINK_SWD_AP_FAULT: /* git://git.ac6.fr/openocd commit 657e3e885b9ee10 * returns ERROR_OK with the comment: diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c index 62a8f5947..cb9ef3969 100644 --- a/src/jtag/hla/hla_interface.c +++ b/src/jtag/hla/hla_interface.c @@ -119,6 +119,11 @@ static int hl_interface_quit(void) if (hl_if.layout->api->close) hl_if.layout->api->close(hl_if.handle); + jtag_command_queue_reset(); + + free((void *)hl_if.param.device_desc); + free((void *)hl_if.param.serial); + return ERROR_OK; } diff --git a/src/jtag/hla/hla_tcl.c b/src/jtag/hla/hla_tcl.c index 9378427b0..73f78fc8a 100644 --- a/src/jtag/hla/hla_tcl.c +++ b/src/jtag/hla/hla_tcl.c @@ -39,20 +39,15 @@ static int jim_newtap_expected_id(Jim_Nvp *n, Jim_GetOptInfo *goi, return e; } - unsigned expected_len = sizeof(uint32_t) * pTap->expected_ids_cnt; - uint32_t *new_expected_ids = malloc(expected_len + sizeof(uint32_t)); - if (new_expected_ids == NULL) { + uint32_t *p = realloc(pTap->expected_ids, + (pTap->expected_ids_cnt + 1) * sizeof(uint32_t)); + if (!p) { Jim_SetResultFormatted(goi->interp, "no memory"); return JIM_ERR; } - memcpy(new_expected_ids, pTap->expected_ids, expected_len); - - new_expected_ids[pTap->expected_ids_cnt] = w; - - free(pTap->expected_ids); - pTap->expected_ids = new_expected_ids; - pTap->expected_ids_cnt++; + pTap->expected_ids = p; + pTap->expected_ids[pTap->expected_ids_cnt++] = w; return JIM_OK; } diff --git a/src/jtag/hla/hla_transport.c b/src/jtag/hla/hla_transport.c index 5a5671db6..ddacea36a 100644 --- a/src/jtag/hla/hla_transport.c +++ b/src/jtag/hla/hla_transport.c @@ -233,3 +233,11 @@ static void hl_constructor(void) transport_register(&hl_jtag_transport); transport_register(&stlink_swim_transport); } + +bool transport_is_hla(void) +{ + struct transport *t; + t = get_current_transport(); + return t == &hl_swd_transport || t == &hl_jtag_transport + || t == &stlink_swim_transport; +} diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index 174c63a3c..ddeadb466 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -60,6 +60,9 @@ extern struct jtag_interface usb_blaster_interface; #if BUILD_JTAG_VPI == 1 extern struct jtag_interface jtag_vpi_interface; #endif +#if BUILD_FT232R == 1 +extern struct jtag_interface ft232r_interface; +#endif #if BUILD_AMTJTAGACCEL == 1 extern struct jtag_interface amt_jtagaccel_interface; #endif @@ -159,6 +162,9 @@ struct jtag_interface *jtag_interfaces[] = { #if BUILD_JTAG_VPI == 1 &jtag_vpi_interface, #endif +#if BUILD_FT232R == 1 + &ft232r_interface, +#endif #if BUILD_AMTJTAGACCEL == 1 &amt_jtagaccel_interface, #endif diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index 7702d6ca8..a6891c03f 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -153,8 +153,6 @@ struct jtag_tap { struct jtag_tap_event_action *event_action; struct jtag_tap *next_tap; - /* dap instance if some null if no instance , initialized to 0 by calloc*/ - struct adiv5_dap *dap; /* private pointer to support none-jtag specific functions */ void *priv; }; @@ -642,8 +640,6 @@ void jtag_poll_set_enabled(bool value); * level APIs that are used in inner loops. */ #include -bool transport_is_jtag(void); - int jim_jtag_newtap(Jim_Interp *interp, int argc, Jim_Obj *const *argv); #endif /* OPENOCD_JTAG_JTAG_H */ diff --git a/src/jtag/swd.h b/src/jtag/swd.h index c888cc07d..52f41d5d9 100644 --- a/src/jtag/swd.h +++ b/src/jtag/swd.h @@ -211,6 +211,4 @@ struct swd_driver { int swd_init_reset(struct command_context *cmd_ctx); void swd_add_reset(int req_srst); -bool transport_is_swd(void); - #endif /* OPENOCD_JTAG_SWD_H */ diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c index bc6bbf204..e32f0ca07 100644 --- a/src/jtag/tcl.c +++ b/src/jtag/tcl.c @@ -42,6 +42,7 @@ #endif #include +#include "transport/transport.h" /** * @file diff --git a/src/openocd.c b/src/openocd.c index 831bd17f2..902528d08 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include #include @@ -85,13 +87,13 @@ static int log_target_callback_event_handler(struct target *target, { switch (event) { case TARGET_EVENT_GDB_START: - target->display = 0; + target->verbose_halt_msg = false; break; case TARGET_EVENT_GDB_END: - target->display = 1; + target->verbose_halt_msg = true; break; case TARGET_EVENT_HALTED: - if (target->display) { + if (target->verbose_halt_msg) { /* do not display information when debugger caused the halt */ target_arch_state(target); } @@ -150,6 +152,10 @@ COMMAND_HANDLER(handle_init_command) if (ERROR_OK != retval) return ERROR_FAIL; + retval = command_run_line(CMD_CTX, "dap init"); + if (ERROR_OK != retval) + return ERROR_FAIL; + LOG_DEBUG("Examining targets..."); if (target_examine() != ERROR_OK) LOG_DEBUG("target examination failed"); @@ -252,6 +258,8 @@ struct command_context *setup_command_handler(Jim_Interp *interp) &nand_register_commands, &pld_register_commands, &mflash_register_commands, + &cti_register_commands, + &dap_register_commands, NULL }; for (unsigned i = 0; NULL != command_registrants[i]; i++) { @@ -286,10 +294,13 @@ static int openocd_thread(int argc, char *argv[], struct command_context *cmd_ct return ERROR_FAIL; ret = parse_config_file(cmd_ctx); - if (ret == ERROR_COMMAND_CLOSE_CONNECTION) + if (ret == ERROR_COMMAND_CLOSE_CONNECTION) { + server_quit(); /* gdb server may be initialized by -c init */ return ERROR_OK; - else if (ret != ERROR_OK) + } else if (ret != ERROR_OK) { + server_quit(); /* gdb server may be initialized by -c init */ return ERROR_FAIL; + } ret = server_init(cmd_ctx); if (ERROR_OK != ret) @@ -342,12 +353,18 @@ int openocd_main(int argc, char *argv[]) /* Start the executable meat that can evolve into thread in future. */ ret = openocd_thread(argc, argv, cmd_ctx); + flash_free_all_banks(); + gdb_service_free(); + server_free(); + unregister_all_commands(cmd_ctx, NULL); + adapter_quit(); + /* Shutdown commandline interface */ command_exit(cmd_ctx); - adapter_quit(); + free_config(); if (ERROR_FAIL == ret) return EXIT_FAILURE; diff --git a/src/rtos/ChibiOS.c b/src/rtos/ChibiOS.c index ef0bb16cf..a46f7a492 100644 --- a/src/rtos/ChibiOS.c +++ b/src/rtos/ChibiOS.c @@ -247,7 +247,7 @@ static int ChibiOS_update_stacking(struct rtos *rtos) /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4 */ struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target); if (is_armv7m(armv7m_target)) { - if (armv7m_target->fp_feature == FPv4_SP) { + if (armv7m_target->fp_feature != FP_NONE) { /* Found ARM v7m target which includes a FPU */ uint32_t cpacr; diff --git a/src/rtos/riscv_debug.c b/src/rtos/riscv_debug.c index b1a714d48..90caf406f 100644 --- a/src/rtos/riscv_debug.c +++ b/src/rtos/riscv_debug.c @@ -248,7 +248,7 @@ static int riscv_gdb_v_packet(struct connection *connection, const char *packet, if (strcmp(packet_stttrr, "vCont;c") == 0) { target_call_event_callbacks(target, TARGET_EVENT_GDB_START); target_call_event_callbacks(target, TARGET_EVENT_RESUME_START); - riscv_resume_all_harts(target); + riscv_openocd_resume(target, 1, 0, 0, 0); target->state = TARGET_RUNNING; gdb_set_frontend_state_running(connection); target_call_event_callbacks(target, TARGET_EVENT_RESUMED); diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index a37f44a1a..4f2304038 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -59,6 +59,15 @@ int rtos_smp_init(struct target *target) return ERROR_TARGET_INIT_FAILED; } +static int rtos_target_for_threadid(struct connection *connection, int64_t threadid, struct target **t) +{ + struct target *curr = get_target_from_connection(connection); + if (t) + *t = curr; + + return ERROR_OK; +} + static int os_alloc(struct target *target, struct rtos_type *ostype) { struct rtos *os = target->rtos = calloc(1, sizeof(struct rtos)); @@ -75,6 +84,7 @@ static int os_alloc(struct target *target, struct rtos_type *ostype) /* RTOS drivers can override the packet handler in _create(). */ os->gdb_thread_packet = rtos_thread_packet; os->gdb_v_packet = NULL; + os->gdb_target_for_threadid = rtos_target_for_threadid; return JIM_OK; } @@ -339,8 +349,10 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa return ERROR_OK; } else if (strncmp(packet, "qSymbol", 7) == 0) { if (rtos_qsymbol(connection, packet, packet_size) == 1) { - target->rtos_auto_detect = false; - target->rtos->type->create(target); + if (target->rtos_auto_detect == true) { + target->rtos_auto_detect = false; + target->rtos->type->create(target); + } target->rtos->type->update_threads(target->rtos); } return ERROR_OK; diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index 9da035adb..c9ac1e555 100644 --- a/src/rtos/rtos.h +++ b/src/rtos/rtos.h @@ -55,6 +55,7 @@ struct rtos { int thread_count; int (*gdb_thread_packet)(struct connection *connection, char const *packet, int packet_size); int (*gdb_v_packet)(struct connection *connection, char const *packet, int packet_size); + int (*gdb_target_for_threadid)(struct connection *connection, int64_t thread_id, struct target **p_target); void *rtos_specific_params; }; diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index b59b9f12f..ca9da1515 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include "server.h" #include #include "gdb_server.h" @@ -126,6 +128,9 @@ static int gdb_flash_program = 1; * Disabled by default. */ static int gdb_report_data_abort; +/* If set, errors when accessing registers are reported to gdb. Disabled by + * default. */ +static int gdb_report_register_access_error; /* set if we are sending target descriptions to gdb * via qXfer:features:read packet */ @@ -728,7 +733,6 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio } else { if (gdb_connection->ctrl_c) { signal_var = 0x2; - gdb_connection->ctrl_c = 0; } else signal_var = gdb_last_signal(target); @@ -760,12 +764,19 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio current_thread[0] = '\0'; if (target->rtos != NULL) { - snprintf(current_thread, sizeof(current_thread), "thread:%016" PRIx64 ";", target->rtos->current_thread); + struct target *ct; + snprintf(current_thread, sizeof(current_thread), "thread:%016" PRIx64 ";", + target->rtos->current_thread); target->rtos->current_threadid = target->rtos->current_thread; + target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &ct); + if (!gdb_connection->ctrl_c) + signal_var = gdb_last_signal(ct); } sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s%s", signal_var, stop_reason, current_thread); + + gdb_connection->ctrl_c = 0; } gdb_put_packet(connection, sig_reply, sig_reply_len); @@ -953,9 +964,14 @@ static int gdb_new_connection(struct connection *connection) breakpoint_clear_target(target); watchpoint_clear_target(target); - /* clean previous rtos session if supported*/ - if ((target->rtos) && (target->rtos->type->clean)) - target->rtos->type->clean(target); + if (target->rtos) { + /* clean previous rtos session if supported*/ + if (target->rtos->type->clean) + target->rtos->type->clean(target); + + /* update threads */ + rtos_update_threads(target); + } /* remove the initial ACK from the incoming buffer */ retval = gdb_get_char(connection, &initial_ack); @@ -1174,7 +1190,7 @@ static int gdb_get_registers_packet(struct connection *connection, for (i = 0; i < reg_list_size; i++) { if (!reg_list[i]->valid) { retval = reg_list[i]->type->get(reg_list[i]); - if (retval != ERROR_OK) { + if (retval != ERROR_OK && gdb_report_register_access_error) { LOG_DEBUG("Couldn't get register %s.", reg_list[i]->name); free(reg_packet); free(reg_list); @@ -1242,7 +1258,7 @@ static int gdb_set_registers_packet(struct connection *connection, gdb_target_to_reg(target, packet_p, chars, bin_buf); retval = reg_list[i]->type->set(reg_list[i], bin_buf); - if (retval != ERROR_OK) { + if (retval != ERROR_OK && gdb_report_register_access_error) { LOG_DEBUG("Couldn't set register %s.", reg_list[i]->name); free(reg_list); free(bin_buf); @@ -1289,7 +1305,7 @@ static int gdb_get_register_packet(struct connection *connection, if (!reg_list[reg_num]->valid) { retval = reg_list[reg_num]->type->get(reg_list[reg_num]); - if (retval != ERROR_OK) { + if (retval != ERROR_OK && gdb_report_register_access_error) { LOG_DEBUG("Couldn't get register %s.", reg_list[reg_num]->name); free(reg_list); return gdb_error(connection, retval); @@ -1349,7 +1365,7 @@ static int gdb_set_register_packet(struct connection *connection, gdb_target_to_reg(target, separator + 1, chars, bin_buf); retval = reg_list[reg_num]->type->set(reg_list[reg_num], bin_buf); - if (retval != ERROR_OK) { + if (retval != ERROR_OK && gdb_report_register_access_error) { LOG_DEBUG("Couldn't set register %s.", reg_list[reg_num]->name); free(bin_buf); free(reg_list); @@ -1919,6 +1935,8 @@ static int gdb_memory_map(struct connection *connection, static const char *gdb_get_reg_type_name(enum reg_type type) { switch (type) { + case REG_TYPE_BOOL: + return "bool"; case REG_TYPE_INT: return "int"; case REG_TYPE_INT8: @@ -1931,6 +1949,8 @@ static const char *gdb_get_reg_type_name(enum reg_type type) return "int64"; case REG_TYPE_INT128: return "int128"; + case REG_TYPE_UINT: + return "uint"; case REG_TYPE_UINT8: return "uint8"; case REG_TYPE_UINT16: @@ -1958,12 +1978,45 @@ static const char *gdb_get_reg_type_name(enum reg_type type) return "int"; /* "int" as default value */ } +static int lookup_add_arch_defined_types(char const **arch_defined_types_list[], const char *type_id, + int *num_arch_defined_types) +{ + int tbl_sz = *num_arch_defined_types; + + if (type_id != NULL && (strcmp(type_id, ""))) { + for (int j = 0; j < (tbl_sz + 1); j++) { + if (!((*arch_defined_types_list)[j])) { + (*arch_defined_types_list)[tbl_sz++] = type_id; + *arch_defined_types_list = realloc(*arch_defined_types_list, + sizeof(char *) * (tbl_sz + 1)); + (*arch_defined_types_list)[tbl_sz] = NULL; + *num_arch_defined_types = tbl_sz; + return 1; + } else { + if (!strcmp((*arch_defined_types_list)[j], type_id)) + return 0; + } + } + } + + return -1; +} + static int gdb_generate_reg_type_description(struct target *target, - char **tdesc, int *pos, int *size, struct reg_data_type *type) + char **tdesc, int *pos, int *size, struct reg_data_type *type, + char const **arch_defined_types_list[], int * num_arch_defined_types) { int retval = ERROR_OK; if (type->type_class == REG_TYPE_CLASS_VECTOR) { + struct reg_data_type *data_type = type->reg_type_vector->type; + if (data_type->type == REG_TYPE_ARCH_DEFINED) { + if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id, + num_arch_defined_types)) + gdb_generate_reg_type_description(target, tdesc, pos, size, data_type, + arch_defined_types_list, + num_arch_defined_types); + } /* */ xml_printf(&retval, tdesc, pos, size, "\n", @@ -1971,6 +2024,20 @@ static int gdb_generate_reg_type_description(struct target *target, type->reg_type_vector->count); } else if (type->type_class == REG_TYPE_CLASS_UNION) { + struct reg_data_type_union_field *field; + field = type->reg_type_union->fields; + while (field != NULL) { + struct reg_data_type *data_type = field->type; + if (data_type->type == REG_TYPE_ARCH_DEFINED) { + if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id, + num_arch_defined_types)) + gdb_generate_reg_type_description(target, tdesc, pos, size, data_type, + arch_defined_types_list, + num_arch_defined_types); + } + + field = field->next; + } /* * ... * */ @@ -1978,7 +2045,6 @@ static int gdb_generate_reg_type_description(struct target *target, "\n", type->id); - struct reg_data_type_union_field *field; field = type->reg_type_union->fields; while (field != NULL) { xml_printf(&retval, tdesc, pos, size, @@ -2004,13 +2070,24 @@ static int gdb_generate_reg_type_description(struct target *target, type->id, type->reg_type_struct->size); while (field != NULL) { xml_printf(&retval, tdesc, pos, size, - "\n", - field->name, field->bitfield->start, - field->bitfield->end); + "\n", + field->name, field->bitfield->start, field->bitfield->end, + gdb_get_reg_type_name(field->bitfield->type)); field = field->next; } } else { + while (field != NULL) { + struct reg_data_type *data_type = field->type; + if (data_type->type == REG_TYPE_ARCH_DEFINED) { + if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id, + num_arch_defined_types)) + gdb_generate_reg_type_description(target, tdesc, pos, size, data_type, + arch_defined_types_list, + num_arch_defined_types); + } + } + /* * ... * */ @@ -2041,8 +2118,9 @@ static int gdb_generate_reg_type_description(struct target *target, field = type->reg_type_flags->fields; while (field != NULL) { xml_printf(&retval, tdesc, pos, size, - "\n", - field->name, field->bitfield->start, field->bitfield->end); + "\n", + field->name, field->bitfield->start, field->bitfield->end, + gdb_get_reg_type_name(field->bitfield->type)); field = field->next; } @@ -2103,11 +2181,15 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o struct reg **reg_list = NULL; int reg_list_size; char const **features = NULL; + char const **arch_defined_types = NULL; int feature_list_size = 0; + int num_arch_defined_types = 0; char *tdesc = NULL; int pos = 0; int size = 0; + arch_defined_types = calloc(1, sizeof(char *)); + retval = target_get_gdb_reg_list(target, ®_list, ®_list_size, REG_CLASS_ALL); @@ -2160,8 +2242,13 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o if (reg_list[i]->reg_data_type != NULL) { if (reg_list[i]->reg_data_type->type == REG_TYPE_ARCH_DEFINED) { /* generate reg_data_type); + if (lookup_add_arch_defined_types(&arch_defined_types, + reg_list[i]->reg_data_type->id, + &num_arch_defined_types)) + gdb_generate_reg_type_description(target, &tdesc, &pos, &size, + reg_list[i]->reg_data_type, + &arch_defined_types, + &num_arch_defined_types); type_str = reg_list[i]->reg_data_type->id; } else { @@ -2211,6 +2298,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o error: free(features); free(reg_list); + free(arch_defined_types); if (retval == ERROR_OK) *tdesc_out = tdesc; @@ -2387,7 +2475,11 @@ static int gdb_get_thread_list_chunk(struct target *target, char **thread_list, else transfer_type = 'l'; - *chunk = malloc(length + 2); + *chunk = malloc(length + 2 + 3); + /* Allocating extra 3 bytes prevents false positive valgrind report + * of strlen(chunk) word access: + * Invalid read of size 4 + * Address 0x4479934 is 44 bytes inside a block of size 45 alloc'd */ if (*chunk == NULL) { LOG_ERROR("Unable to allocate memory"); return ERROR_FAIL; @@ -2495,7 +2587,7 @@ static int gdb_query_packet(struct connection *connection, &buffer, &pos, &size, - "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+", + "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+;vContSupported+", (GDB_BUFFER_SIZE - 1), ((gdb_use_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-', (gdb_target_desc_supported == 1) ? '+' : '-'); @@ -2584,6 +2676,185 @@ static int gdb_query_packet(struct connection *connection, return ERROR_OK; } +static bool gdb_handle_vcont_packet(struct connection *connection, const char *packet, int packet_size) +{ + struct gdb_connection *gdb_connection = connection->priv; + struct target *target = get_target_from_connection(connection); + const char *parse = packet; + int retval; + + /* query for vCont supported */ + if (parse[0] == '?') { + if (target->type->step != NULL) { + /* gdb doesn't accept c without C and s without S */ + gdb_put_packet(connection, "vCont;c;C;s;S", 13); + return true; + } + return false; + } + + if (parse[0] == ';') { + ++parse; + --packet_size; + } + + /* simple case, a continue packet */ + if (parse[0] == 'c') { + LOG_DEBUG("target %s continue", target_name(target)); + log_add_callback(gdb_log_callback, connection); + retval = target_resume(target, 1, 0, 0, 0); + if (retval == ERROR_TARGET_NOT_HALTED) + LOG_INFO("target %s was not halted when resume was requested", target_name(target)); + + /* poll target in an attempt to make its internal state consistent */ + if (retval != ERROR_OK) { + retval = target_poll(target); + if (retval != ERROR_OK) + LOG_DEBUG("error polling target %s after failed resume", target_name(target)); + } + + /* + * We don't report errors to gdb here, move frontend_state to + * TARGET_RUNNING to stay in sync with gdb's expectation of the + * target state + */ + gdb_connection->frontend_state = TARGET_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_GDB_START); + + return true; + } + + /* single-step or step-over-breakpoint */ + if (parse[0] == 's') { + bool fake_step = false; + + if (strncmp(parse, "s:", 2) == 0) { + struct target *ct = target; + int current_pc = 1; + int64_t thread_id; + char *endp; + + parse += 2; + packet_size -= 2; + + thread_id = strtoll(parse, &endp, 16); + if (endp != NULL) { + packet_size -= endp - parse; + parse = endp; + } + + if (target->rtos != NULL) { + /* FIXME: why is this necessary? rtos state should be up-to-date here already! */ + rtos_update_threads(target); + + target->rtos->gdb_target_for_threadid(connection, thread_id, &ct); + + /* + * check if the thread to be stepped is the current rtos thread + * if not, we must fake the step + */ + if (target->rtos->current_thread != thread_id) + fake_step = true; + } + + if (parse[0] == ';') { + ++parse; + --packet_size; + + if (parse[0] == 'c') { + parse += 1; + packet_size -= 1; + + /* check if thread-id follows */ + if (parse[0] == ':') { + int64_t tid; + parse += 1; + packet_size -= 1; + + tid = strtoll(parse, &endp, 16); + if (tid == thread_id) { + /* + * Special case: only step a single thread (core), + * keep the other threads halted. Currently, only + * aarch64 target understands it. Other target types don't + * care (nobody checks the actual value of 'current') + * and it doesn't really matter. This deserves + * a symbolic constant and a formal interface documentation + * at a later time. + */ + LOG_DEBUG("request to step current core only"); + /* uncomment after checking that indeed other targets are safe */ + /*current_pc = 2;*/ + } + } + } + } + + LOG_DEBUG("target %s single-step thread %"PRIx64, target_name(ct), thread_id); + log_add_callback(gdb_log_callback, connection); + target_call_event_callbacks(ct, TARGET_EVENT_GDB_START); + + /* + * work around an annoying gdb behaviour: when the current thread + * is changed in gdb, it assumes that the target can follow and also + * make the thread current. This is an assumption that cannot hold + * for a real target running a multi-threading OS. We just fake + * the step to not trigger an internal error in gdb. See + * https://sourceware.org/bugzilla/show_bug.cgi?id=22925 for details + */ + if (fake_step) { + int sig_reply_len; + char sig_reply[128]; + + LOG_DEBUG("fake step thread %"PRIx64, thread_id); + + sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), + "T05thread:%016"PRIx64";", thread_id); + + gdb_put_packet(connection, sig_reply, sig_reply_len); + log_remove_callback(gdb_log_callback, connection); + + return true; + } + + /* support for gdb_sync command */ + if (gdb_connection->sync) { + gdb_connection->sync = false; + if (ct->state == TARGET_HALTED) { + LOG_WARNING("stepi ignored. GDB will now fetch the register state " \ + "from the target."); + gdb_sig_halted(connection); + log_remove_callback(gdb_log_callback, connection); + } else + gdb_connection->frontend_state = TARGET_RUNNING; + return true; + } + + retval = target_step(ct, current_pc, 0, 0); + if (retval == ERROR_TARGET_NOT_HALTED) + LOG_INFO("target %s was not halted when step was requested", target_name(ct)); + + /* if step was successful send a reply back to gdb */ + if (retval == ERROR_OK) { + retval = target_poll(ct); + if (retval != ERROR_OK) + LOG_DEBUG("error polling target %s after successful step", target_name(ct)); + /* send back signal information */ + gdb_signal_reply(ct, connection); + /* stop forwarding log packets! */ + log_remove_callback(gdb_log_callback, connection); + } else + gdb_connection->frontend_state = TARGET_RUNNING; + } else { + LOG_ERROR("Unknown vCont packet"); + return false; + } + return true; + } + + return false; +} + static int gdb_v_packet(struct connection *connection, char const *packet, int packet_size) { @@ -2597,6 +2868,19 @@ static int gdb_v_packet(struct connection *connection, return out; } + if (strncmp(packet, "vCont", 5) == 0) { + bool handled; + + packet += 5; + packet_size -= 5; + + handled = gdb_handle_vcont_packet(connection, packet, packet_size); + if (!handled) + gdb_put_packet(connection, "", 0); + + return ERROR_OK; + } + /* if flash programming disabled - send a empty reply */ if (gdb_flash_program == 0) { @@ -3036,7 +3320,12 @@ static int gdb_input_inner(struct connection *connection) if (gdb_con->ctrl_c) { if (target->state == TARGET_RUNNING) { - retval = target_halt(target); + struct target *t = target; + if (target->rtos) + target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &t); + retval = target_halt(t); + if (retval == ERROR_OK) + retval = target_poll(t); if (retval != ERROR_OK) target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); gdb_con->ctrl_c = 0; @@ -3209,6 +3498,15 @@ COMMAND_HANDLER(handle_gdb_report_data_abort_command) return ERROR_OK; } +COMMAND_HANDLER(handle_gdb_report_register_access_error) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_report_register_access_error); + return ERROR_OK; +} + /* gdb_breakpoint_override */ COMMAND_HANDLER(handle_gdb_breakpoint_override_command) { @@ -3330,6 +3628,13 @@ static const struct command_registration gdb_command_handlers[] = { .help = "enable or disable reporting data aborts", .usage = "('enable'|'disable')" }, + { + .name = "gdb_report_register_access_error", + .handler = handle_gdb_report_register_access_error, + .mode = COMMAND_CONFIG, + .help = "enable or disable reporting register access errors", + .usage = "('enable'|'disable')" + }, { .name = "gdb_breakpoint_override", .handler = handle_gdb_breakpoint_override_command, @@ -3366,3 +3671,9 @@ void gdb_set_frontend_state_running(struct connection *connection) struct gdb_connection *gdb_con = connection->priv; gdb_con->frontend_state = TARGET_RUNNING; } + +void gdb_service_free(void) +{ + free(gdb_port); + free(gdb_port_next); +} diff --git a/src/server/gdb_server.h b/src/server/gdb_server.h index 1dc30e095..1366c76dc 100644 --- a/src/server/gdb_server.h +++ b/src/server/gdb_server.h @@ -36,6 +36,7 @@ struct reg; int gdb_target_add_all(struct target *target); int gdb_register_commands(struct command_context *command_context); +void gdb_service_free(void); int gdb_put_packet(struct connection *connection, char *buffer, int len); diff --git a/src/server/server.c b/src/server/server.c index b00db6ab8..4e806563c 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -259,7 +259,7 @@ int add_service(char *name, c->sin.sin_family = AF_INET; if (bindto_name == NULL) - c->sin.sin_addr.s_addr = INADDR_ANY; + c->sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); else { hp = gethostbyname(bindto_name); if (hp == NULL) { @@ -273,8 +273,7 @@ int add_service(char *name, c->sin.sin_port = htons(c->portnumber); if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) { - LOG_ERROR("couldn't bind %s to socket on port %d: %s", name, - c->portnumber, strerror(errno)); + LOG_ERROR("couldn't bind %s to socket on port %d: %s", name, c->portnumber, strerror(errno)); close_socket(c->fd); free_service(c); return ERROR_FAIL; @@ -346,6 +345,21 @@ int add_service(char *name, return ERROR_OK; } +static void remove_connections(struct service *service) +{ + struct connection *connection; + + connection = service->connections; + + while (connection) { + struct connection *tmp; + + tmp = connection->next; + remove_connection(service, connection); + connection = tmp; + } +} + static int remove_services(void) { struct service *c = services; @@ -354,6 +368,8 @@ static int remove_services(void) while (c) { struct service *next = c->next; + remove_connections(c); + if (c->name) free(c->name); @@ -625,6 +641,13 @@ int server_quit(void) return last_signal; } +void server_free(void) +{ + tcl_service_free(); + telnet_service_free(); + jsp_service_free(); +} + void exit_on_signal(int sig) { #ifndef _WIN32 diff --git a/src/server/server.h b/src/server/server.h index 68ad16d55..d4eae9424 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -25,6 +25,10 @@ #ifndef OPENOCD_SERVER_SERVER_H #define OPENOCD_SERVER_SERVER_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #ifdef HAVE_NETINET_IN_H @@ -78,6 +82,7 @@ int add_service(char *name, const char *port, int server_preinit(void); int server_init(struct command_context *cmd_ctx); int server_quit(void); +void server_free(void); void exit_on_signal(int); int server_loop(struct command_context *command_context); diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c index 0077339f2..3cb63a275 100644 --- a/src/server/tcl_server.c +++ b/src/server/tcl_server.c @@ -157,7 +157,7 @@ static int tcl_new_connection(struct connection *connection) connection->priv = tclc; - struct target *target = get_target_by_num(connection->cmd_ctx->current_target); + struct target *target = get_current_target(connection->cmd_ctx); if (target != NULL) tclc->tc_laststate = target->state; @@ -359,3 +359,8 @@ int tcl_register_commands(struct command_context *cmd_ctx) tcl_port = strdup("6666"); return register_commands(cmd_ctx, NULL, tcl_command_handlers); } + +void tcl_service_free(void) +{ + free(tcl_port); +} diff --git a/src/server/tcl_server.h b/src/server/tcl_server.h index 422c794ee..6ce3ab95f 100644 --- a/src/server/tcl_server.h +++ b/src/server/tcl_server.h @@ -22,5 +22,6 @@ int tcl_init(void); int tcl_register_commands(struct command_context *cmd_ctx); +void tcl_service_free(void); #endif /* OPENOCD_SERVER_TCL_SERVER_H */ diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index 9077b6c46..a864f5fd2 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -719,3 +719,8 @@ int telnet_register_commands(struct command_context *cmd_ctx) telnet_port = strdup("4444"); return register_commands(cmd_ctx, NULL, telnet_command_handlers); } + +void telnet_service_free(void) +{ + free(telnet_port); +} diff --git a/src/server/telnet_server.h b/src/server/telnet_server.h index 5e238f441..27148d7ce 100644 --- a/src/server/telnet_server.h +++ b/src/server/telnet_server.h @@ -64,5 +64,6 @@ struct telnet_service { int telnet_init(char *banner); int telnet_register_commands(struct command_context *command_context); +void telnet_service_free(void); #endif /* OPENOCD_SERVER_TELNET_SERVER_H */ diff --git a/src/svf/svf.c b/src/svf/svf.c index 1d686ba61..223af7e18 100644 --- a/src/svf/svf.c +++ b/src/svf/svf.c @@ -741,6 +741,9 @@ parse_char: pos++; } + if (num == 0) + return ERROR_FAIL; + *num_of_argu = num; return ERROR_OK; @@ -1313,7 +1316,7 @@ XXR_common: * SEC]] [ENDSTATE end_state] */ /* RUNTEST [run_state] min_time SEC [MAXIMUM max_time SEC] [ENDSTATE * end_state] */ - if ((num_of_argu < 3) && (num_of_argu > 11)) { + if ((num_of_argu < 3) || (num_of_argu > 11)) { LOG_ERROR("invalid parameter of %s", argus[0]); return ERROR_FAIL; } diff --git a/src/target/Makefile.am b/src/target/Makefile.am index 9576b2357..030015adf 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -89,6 +89,7 @@ ARM_DEBUG_SRC = \ %D%/arm_simulator.c \ %D%/arm_semihosting.c \ %D%/arm_adi_v5.c \ + %D%/arm_dap.c \ %D%/armv7a_cache.c \ %D%/armv7a_cache_l2x.c \ %D%/adi_v5_jtag.c \ diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 14a2da6c1..4641a3fd5 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -40,6 +40,11 @@ enum halt_mode { HALT_SYNC, }; +struct aarch64_private_config { + struct adiv5_private_config adiv5_config; + struct arm_cti *cti; +}; + static int aarch64_poll(struct target *target); static int aarch64_debug_entry(struct target *target); static int aarch64_restore_context(struct target *target, bool bpwp); @@ -452,7 +457,7 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug struct target *curr; if (debug_reason == DBG_REASON_NOTHALTED) { - LOG_INFO("Halting remaining targets in SMP group"); + LOG_DEBUG("Halting remaining targets in SMP group"); aarch64_halt_smp(target, true); } @@ -1086,7 +1091,7 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres if (retval != ERROR_OK) return retval; - if (target->smp && !handle_breakpoints) { + if (target->smp && (current == 1)) { /* * isolate current target so that it doesn't get resumed * together with the others @@ -1861,7 +1866,7 @@ static int aarch64_write_cpu_memory(struct target *target, if (dscr & (DSCR_ERR | DSCR_SYS_ERROR_PEND)) { /* Abort occurred - clear it and exit */ LOG_ERROR("abort occurred - dscr = 0x%08" PRIx32, dscr); - armv8_dpm_handle_exception(dpm); + armv8_dpm_handle_exception(dpm, true); return ERROR_FAIL; } @@ -2080,7 +2085,7 @@ static int aarch64_read_cpu_memory(struct target *target, if (dscr & (DSCR_ERR | DSCR_SYS_ERROR_PEND)) { /* Abort occurred - clear it and exit */ LOG_ERROR("abort occurred - dscr = 0x%08" PRIx32, dscr); - armv8_dpm_handle_exception(dpm); + armv8_dpm_handle_exception(dpm, true); return ERROR_FAIL; } @@ -2198,7 +2203,7 @@ static int aarch64_examine_first(struct target *target) struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; struct adiv5_dap *swjdp = armv8->arm.dap; - uint32_t cti_base; + struct aarch64_private_config *pc; int i; int retval = ERROR_OK; uint64_t debug, ttypr; @@ -2206,10 +2211,6 @@ static int aarch64_examine_first(struct target *target) uint32_t tmp0, tmp1, tmp2, tmp3; debug = ttypr = cpuid = 0; - retval = dap_dp_init(swjdp); - if (retval != ERROR_OK) - return retval; - /* Search for the APB-AB - it is needed for access to debug registers */ retval = dap_find_ap(swjdp, AP_TYPE_APB_AP, &armv8->debug_ap); if (retval != ERROR_OK) { @@ -2289,17 +2290,15 @@ static int aarch64_examine_first(struct target *target) LOG_DEBUG("ttypr = 0x%08" PRIx64, ttypr); LOG_DEBUG("debug = 0x%08" PRIx64, debug); - if (target->ctibase == 0) { - /* assume a v8 rom table layout */ - cti_base = armv8->debug_base + 0x10000; - LOG_INFO("Target ctibase is not set, assuming 0x%0" PRIx32, cti_base); - } else - cti_base = target->ctibase; - - armv8->cti = arm_cti_create(armv8->debug_ap, cti_base); - if (armv8->cti == NULL) + if (target->private_config == NULL) return ERROR_FAIL; + pc = (struct aarch64_private_config *)target->private_config; + if (pc->cti == NULL) + return ERROR_FAIL; + + armv8->cti = pc->cti; + retval = aarch64_dpm_setup(aarch64, debug); if (retval != ERROR_OK) return retval; @@ -2356,18 +2355,13 @@ static int aarch64_init_target(struct command_context *cmd_ctx, } static int aarch64_init_arch_info(struct target *target, - struct aarch64_common *aarch64, struct jtag_tap *tap) + struct aarch64_common *aarch64, struct adiv5_dap *dap) { struct armv8_common *armv8 = &aarch64->armv8_common; /* Setup struct aarch64_common */ aarch64->common_magic = AARCH64_COMMON_MAGIC; - /* tap has no dap initialized */ - if (!tap->dap) { - tap->dap = dap_init(); - tap->dap->tap = tap; - } - armv8->arm.dap = tap->dap; + armv8->arm.dap = dap; /* register arch-specific functions */ armv8->examine_debug_reason = NULL; @@ -2383,9 +2377,13 @@ static int aarch64_init_arch_info(struct target *target, static int aarch64_target_create(struct target *target, Jim_Interp *interp) { + struct aarch64_private_config *pc = target->private_config; struct aarch64_common *aarch64 = calloc(1, sizeof(struct aarch64_common)); - return aarch64_init_arch_info(target, aarch64, target->tap); + if (adiv5_verify_config(&pc->adiv5_config) != ERROR_OK) + return ERROR_FAIL; + + return aarch64_init_arch_info(target, aarch64, pc->adiv5_config.dap); } static int aarch64_mmu(struct target *target, int *enabled) @@ -2405,6 +2403,94 @@ static int aarch64_virt2phys(struct target *target, target_addr_t virt, return armv8_mmu_translate_va_pa(target, virt, phys, 1); } +/* + * private target configuration items + */ +enum aarch64_cfg_param { + CFG_CTI, +}; + +static const Jim_Nvp nvp_config_opts[] = { + { .name = "-cti", .value = CFG_CTI }, + { .name = NULL, .value = -1 } +}; + +static int aarch64_jim_configure(struct target *target, Jim_GetOptInfo *goi) +{ + struct aarch64_private_config *pc; + Jim_Nvp *n; + int e; + + pc = (struct aarch64_private_config *)target->private_config; + if (pc == NULL) { + pc = calloc(1, sizeof(struct aarch64_private_config)); + target->private_config = pc; + } + + /* + * Call adiv5_jim_configure() to parse the common DAP options + * It will return JIM_CONTINUE if it didn't find any known + * options, JIM_OK if it correctly parsed the topmost option + * and JIM_ERR if an error occured during parameter evaluation. + * For JIM_CONTINUE, we check our own params. + */ + e = adiv5_jim_configure(target, goi); + if (e != JIM_CONTINUE) + return e; + + /* parse config or cget options ... */ + if (goi->argc > 0) { + Jim_SetEmptyResult(goi->interp); + + /* check first if topmost item is for us */ + e = Jim_Nvp_name2value_obj(goi->interp, nvp_config_opts, + goi->argv[0], &n); + if (e != JIM_OK) + return JIM_CONTINUE; + + e = Jim_GetOpt_Obj(goi, NULL); + if (e != JIM_OK) + return e; + + switch (n->value) { + case CFG_CTI: { + if (goi->isconfigure) { + Jim_Obj *o_cti; + struct arm_cti *cti; + e = Jim_GetOpt_Obj(goi, &o_cti); + if (e != JIM_OK) + return e; + cti = cti_instance_by_jim_obj(goi->interp, o_cti); + if (cti == NULL) { + Jim_SetResultString(goi->interp, "CTI name invalid!", -1); + return JIM_ERR; + } + pc->cti = cti; + } else { + if (goi->argc != 0) { + Jim_WrongNumArgs(goi->interp, + goi->argc, goi->argv, + "NO PARAMS"); + return JIM_ERR; + } + + if (pc == NULL || pc->cti == NULL) { + Jim_SetResultString(goi->interp, "CTI not configured", -1); + return JIM_ERR; + } + Jim_SetResultString(goi->interp, arm_cti_name(pc->cti), -1); + } + break; + } + + default: + return JIM_CONTINUE; + } + } + + return JIM_OK; +} + COMMAND_HANDLER(aarch64_handle_cache_info_command) { struct target *target = get_current_target(CMD_CTX); @@ -2570,6 +2656,7 @@ struct target_type aarch64_target = { .commands = aarch64_command_handlers, .target_create = aarch64_target_create, + .target_jim_configure = aarch64_jim_configure, .init_target = aarch64_init_target, .examine = aarch64_examine, diff --git a/src/target/adi_v5_jtag.c b/src/target/adi_v5_jtag.c index c7dc4f7c9..dc0237900 100644 --- a/src/target/adi_v5_jtag.c +++ b/src/target/adi_v5_jtag.c @@ -574,6 +574,7 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap) if ((ctrlstat & (CDBGPWRUPREQ | CDBGPWRUPACK | CSYSPWRUPREQ | CSYSPWRUPACK)) != (CDBGPWRUPREQ | CDBGPWRUPACK | CSYSPWRUPREQ | CSYSPWRUPACK)) { LOG_ERROR("Debug regions are unpowered, an unexpected reset might have happened"); + dap->do_reconnect = true; } if (ctrlstat & SSTICKYERR) @@ -598,6 +599,20 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap) /*--------------------------------------------------------------------------*/ +static int jtag_connect(struct adiv5_dap *dap) +{ + dap->do_reconnect = false; + return dap_dp_init(dap); +} + +static int jtag_check_reconnect(struct adiv5_dap *dap) +{ + if (dap->do_reconnect) + return jtag_connect(dap); + + return ERROR_OK; +} + static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { @@ -633,7 +648,11 @@ static int jtag_ap_q_bankselect(struct adiv5_ap *ap, unsigned reg) static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned reg, uint32_t *data) { - int retval = jtag_ap_q_bankselect(ap, reg); + int retval = jtag_check_reconnect(ap->dap); + if (retval != ERROR_OK) + return retval; + + retval = jtag_ap_q_bankselect(ap, reg); if (retval != ERROR_OK) return retval; @@ -647,7 +666,11 @@ static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned reg, static int jtag_ap_q_write(struct adiv5_ap *ap, unsigned reg, uint32_t data) { - int retval = jtag_ap_q_bankselect(ap, reg); + int retval = jtag_check_reconnect(ap->dap); + if (retval != ERROR_OK) + return retval; + + retval = jtag_ap_q_bankselect(ap, reg); if (retval != ERROR_OK) return retval; @@ -692,6 +715,7 @@ static int jtag_dp_sync(struct adiv5_dap *dap) * part of DAP setup */ const struct dap_ops jtag_dp_ops = { + .connect = jtag_connect, .queue_dp_read = jtag_dp_q_read, .queue_dp_write = jtag_dp_q_write, .queue_ap_read = jtag_ap_q_read, diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index c503f090b..0de272dd9 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -53,13 +53,11 @@ #include -/* YUK! - but this is currently a global.... */ -extern struct jtag_interface *jtag_interface; static bool do_sync; static void swd_finish_read(struct adiv5_dap *dap) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); if (dap->last_read != NULL) { swd->read_reg(swd_cmd(true, false, DP_RDBUFF), dap->last_read, 0); dap->last_read = NULL; @@ -73,7 +71,7 @@ static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, static void swd_clear_sticky_errors(struct adiv5_dap *dap) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); swd->write_reg(swd_cmd(false, false, DP_ABORT), @@ -82,7 +80,7 @@ static void swd_clear_sticky_errors(struct adiv5_dap *dap) static int swd_run_inner(struct adiv5_dap *dap) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); int retval; retval = swd->run(); @@ -97,6 +95,7 @@ static int swd_run_inner(struct adiv5_dap *dap) static int swd_connect(struct adiv5_dap *dap) { + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); uint32_t dpidr; int status; @@ -120,7 +119,7 @@ static int swd_connect(struct adiv5_dap *dap) } /* Note, debugport_init() does setup too */ - jtag_interface->swd->switch_seq(JTAG_TO_SWD); + swd->switch_seq(JTAG_TO_SWD); /* Clear link state, including the SELECT cache. */ dap->do_reconnect = false; @@ -136,6 +135,7 @@ static int swd_connect(struct adiv5_dap *dap) if (status == ERROR_OK) { LOG_INFO("SWD DPIDR %#8.8" PRIx32, dpidr); dap->do_reconnect = false; + status = dap_dp_init(dap); } else dap->do_reconnect = true; @@ -157,7 +157,7 @@ static int swd_check_reconnect(struct adiv5_dap *dap) static int swd_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); swd->write_reg(swd_cmd(false, false, DP_ABORT), @@ -187,7 +187,7 @@ static void swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned reg) static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); int retval = swd_check_reconnect(dap); @@ -203,7 +203,7 @@ static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg, uint32_t data) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); int retval = swd_check_reconnect(dap); @@ -236,10 +236,9 @@ static void swd_queue_ap_bankselect(struct adiv5_ap *ap, unsigned reg) static int swd_queue_ap_read(struct adiv5_ap *ap, unsigned reg, uint32_t *data) { - const struct swd_driver *swd = jtag_interface->swd; - assert(swd); - struct adiv5_dap *dap = ap->dap; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); + assert(swd); int retval = swd_check_reconnect(dap); if (retval != ERROR_OK) @@ -255,10 +254,9 @@ static int swd_queue_ap_read(struct adiv5_ap *ap, unsigned reg, static int swd_queue_ap_write(struct adiv5_ap *ap, unsigned reg, uint32_t data) { - const struct swd_driver *swd = jtag_interface->swd; - assert(swd); - struct adiv5_dap *dap = ap->dap; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); + assert(swd); int retval = swd_check_reconnect(dap); if (retval != ERROR_OK) @@ -279,6 +277,7 @@ static int swd_run(struct adiv5_dap *dap) } const struct dap_ops swd_dap_ops = { + .connect = swd_connect, .queue_dp_read = swd_queue_dp_read, .queue_dp_write = swd_queue_dp_write, .queue_ap_read = swd_queue_ap_read, @@ -381,15 +380,15 @@ static const struct command_registration swd_handlers[] = { static int swd_select(struct command_context *ctx) { + /* FIXME: only place where global 'jtag_interface' is still needed */ + extern struct jtag_interface *jtag_interface; + const struct swd_driver *swd = jtag_interface->swd; int retval; retval = register_commands(ctx, NULL, swd_handlers); - if (retval != ERROR_OK) return retval; - const struct swd_driver *swd = jtag_interface->swd; - /* be sure driver is in SWD mode; start * with hardware default TRN (1), it can be changed later */ @@ -404,33 +403,14 @@ static int swd_select(struct command_context *ctx) return retval; } - /* force DAP into SWD mode (not JTAG) */ - /*retval = dap_to_swd(target);*/ - - if (ctx->current_target) { - /* force DAP into SWD mode (not JTAG) */ - struct target *target = get_current_target(ctx); - retval = dap_to_swd(target); - } - return retval; } static int swd_init(struct command_context *ctx) { - struct target *target = get_current_target(ctx); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - /* Force the DAP's ops vector for SWD mode. - * messy - is there a better way? */ - arm->dap->ops = &swd_dap_ops; - /* First connect after init is not reconnecting. */ - dap->do_reconnect = false; - - int retval = swd_connect(dap); - if (retval != ERROR_OK) - LOG_ERROR("SWD connect failed"); - return retval; + /* nothing done here, SWD is initialized + * together with the DAP */ + return ERROR_OK; } static struct transport swd_transport = { diff --git a/src/target/arm.h b/src/target/arm.h index eb4a51f98..62fbb7368 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -77,6 +77,43 @@ enum arm_mode { ARM_MODE_ANY = -1 }; +/* VFPv3 internal register numbers mapping to d0:31 */ +enum { + ARM_VFP_V3_D0 = 51, + ARM_VFP_V3_D1, + ARM_VFP_V3_D2, + ARM_VFP_V3_D3, + ARM_VFP_V3_D4, + ARM_VFP_V3_D5, + ARM_VFP_V3_D6, + ARM_VFP_V3_D7, + ARM_VFP_V3_D8, + ARM_VFP_V3_D9, + ARM_VFP_V3_D10, + ARM_VFP_V3_D11, + ARM_VFP_V3_D12, + ARM_VFP_V3_D13, + ARM_VFP_V3_D14, + ARM_VFP_V3_D15, + ARM_VFP_V3_D16, + ARM_VFP_V3_D17, + ARM_VFP_V3_D18, + ARM_VFP_V3_D19, + ARM_VFP_V3_D20, + ARM_VFP_V3_D21, + ARM_VFP_V3_D22, + ARM_VFP_V3_D23, + ARM_VFP_V3_D24, + ARM_VFP_V3_D25, + ARM_VFP_V3_D26, + ARM_VFP_V3_D27, + ARM_VFP_V3_D28, + ARM_VFP_V3_D29, + ARM_VFP_V3_D30, + ARM_VFP_V3_D31, + ARM_VFP_V3_FPSCR, +}; + const char *arm_mode_name(unsigned psr_mode); bool is_arm_mode(unsigned psr_mode); @@ -89,6 +126,14 @@ enum arm_state { ARM_STATE_AARCH64, }; +/** ARM vector floating point enabled, if yes which version. */ +enum arm_vfp_version { + ARM_VFP_DISABLED, + ARM_VFP_V1, + ARM_VFP_V2, + ARM_VFP_V3, +}; + #define ARM_COMMON_MAGIC 0x0A450A45 /** @@ -145,6 +190,9 @@ struct arm { /** Flag reporting whether semihosting fileio operation is active. */ bool semihosting_hit_fileio; + /** Floating point or VFP version, 0 if disabled. */ + int arm_vfp_version; + /** Current semihosting operation. */ int semihosting_op; @@ -225,7 +273,7 @@ struct arm_reg { enum arm_mode mode; struct target *target; struct arm *arm; - uint8_t value[8]; + uint8_t value[16]; }; struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm); diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index dfbc5ade2..2b7d7b22d 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -76,6 +76,7 @@ #include #include #include +#include /* ARM ADI Specification requires at least 10 bits used for TAR autoincrement */ @@ -614,33 +615,8 @@ int mem_ap_write_buf_noincr(struct adiv5_ap *ap, #define DAP_POWER_DOMAIN_TIMEOUT (10) -/* FIXME don't import ... just initialize as - * part of DAP transport setup -*/ -extern const struct dap_ops jtag_dp_ops; - /*--------------------------------------------------------------------------*/ -/** - * Create a new DAP - */ -struct adiv5_dap *dap_init(void) -{ - struct adiv5_dap *dap = calloc(1, sizeof(struct adiv5_dap)); - int i; - /* Set up with safe defaults */ - for (i = 0; i <= 255; i++) { - dap->ap[i].dap = dap; - dap->ap[i].ap_num = i; - /* memaccess_tck max is 255 */ - dap->ap[i].memaccess_tck = 255; - /* Number of bits for tar autoincrement, impl. dep. at least 10 */ - dap->ap[i].tar_autoincr_block = (1<<10); - } - INIT_LIST_HEAD(&dap->cmd_journal); - return dap; -} - /** * Invalidate cached DP select and cached TAR and CSW of all APs */ @@ -667,14 +643,7 @@ int dap_dp_init(struct adiv5_dap *dap) { int retval; - LOG_DEBUG(" "); - /* JTAG-DP or SWJ-DP, in JTAG mode - * ... for SWD mode this is patched as part - * of link switchover - * FIXME: This should already be setup by the respective transport specific DAP creation. - */ - if (!dap->ops) - dap->ops = &jtag_dp_ops; + LOG_DEBUG("%s", adiv5_dap_name(dap)); dap_invalidate_cache(dap); @@ -1376,7 +1345,7 @@ static int dap_rom_display(struct command_context *cmd_ctx, return ERROR_OK; } -static int dap_info_command(struct command_context *cmd_ctx, +int dap_info_command(struct command_context *cmd_ctx, struct adiv5_ap *ap) { int retval; @@ -1434,46 +1403,131 @@ static int dap_info_command(struct command_context *cmd_ctx, return ERROR_OK; } +enum adiv5_cfg_param { + CFG_DAP, + CFG_AP_NUM +}; + +static const Jim_Nvp nvp_config_opts[] = { + { .name = "-dap", .value = CFG_DAP }, + { .name = "-ap-num", .value = CFG_AP_NUM }, + { .name = NULL, .value = -1 } +}; + int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi) { struct adiv5_private_config *pc; - const char *arg; - jim_wide ap_num; int e; - /* check if argv[0] is for us */ - arg = Jim_GetString(goi->argv[0], NULL); - if (strcmp(arg, "-ap-num")) - return JIM_CONTINUE; - - e = Jim_GetOpt_String(goi, &arg, NULL); - if (e != JIM_OK) - return e; - - if (goi->argc == 0) { - Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-ap-num ?ap-number? ..."); - return JIM_ERR; - } - - e = Jim_GetOpt_Wide(goi, &ap_num); - if (e != JIM_OK) - return e; - - if (target->private_config == NULL) { + pc = (struct adiv5_private_config *)target->private_config; + if (pc == NULL) { pc = calloc(1, sizeof(struct adiv5_private_config)); + pc->ap_num = -1; target->private_config = pc; - pc->ap_num = ap_num; } + target->has_dap = true; + + if (goi->argc > 0) { + Jim_Nvp *n; + + Jim_SetEmptyResult(goi->interp); + + /* check first if topmost item is for us */ + e = Jim_Nvp_name2value_obj(goi->interp, nvp_config_opts, + goi->argv[0], &n); + if (e != JIM_OK) + return JIM_CONTINUE; + + e = Jim_GetOpt_Obj(goi, NULL); + if (e != JIM_OK) + return e; + + switch (n->value) { + case CFG_DAP: + if (goi->isconfigure) { + Jim_Obj *o_t; + struct adiv5_dap *dap; + e = Jim_GetOpt_Obj(goi, &o_t); + if (e != JIM_OK) + return e; + dap = dap_instance_by_jim_obj(goi->interp, o_t); + if (dap == NULL) { + Jim_SetResultString(goi->interp, "DAP name invalid!", -1); + return JIM_ERR; + } + if (pc->dap != NULL && pc->dap != dap) { + Jim_SetResultString(goi->interp, + "DAP assignment cannot be changed after target was created!", -1); + return JIM_ERR; + } + if (target->tap_configured) { + Jim_SetResultString(goi->interp, + "-chain-position and -dap configparams are mutually exclusive!", -1); + return JIM_ERR; + } + pc->dap = dap; + target->tap = dap->tap; + target->dap_configured = true; + } else { + if (goi->argc != 0) { + Jim_WrongNumArgs(goi->interp, + goi->argc, goi->argv, + "NO PARAMS"); + return JIM_ERR; + } + + if (pc->dap == NULL) { + Jim_SetResultString(goi->interp, "DAP not configured", -1); + return JIM_ERR; + } + Jim_SetResultString(goi->interp, adiv5_dap_name(pc->dap), -1); + } + break; + + case CFG_AP_NUM: + if (goi->isconfigure) { + jim_wide ap_num; + e = Jim_GetOpt_Wide(goi, &ap_num); + if (e != JIM_OK) + return e; + pc->ap_num = ap_num; + } else { + if (goi->argc != 0) { + Jim_WrongNumArgs(goi->interp, + goi->argc, goi->argv, + "NO PARAMS"); + return JIM_ERR; + } + + if (pc->ap_num < 0) { + Jim_SetResultString(goi->interp, "AP number not configured", -1); + return JIM_ERR; + } + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, (int)pc->ap_num)); + } + break; + } + } return JIM_OK; } +int adiv5_verify_config(struct adiv5_private_config *pc) +{ + if (pc == NULL) + return ERROR_FAIL; + + if (pc->dap == NULL) + return ERROR_FAIL; + + return ERROR_OK; +} + + COMMAND_HANDLER(handle_dap_info_command) { - struct target *target = get_current_target(CMD_CTX); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint32_t apsel; switch (CMD_ARGC) { @@ -1494,10 +1548,7 @@ COMMAND_HANDLER(handle_dap_info_command) COMMAND_HANDLER(dap_baseaddr_command) { - struct target *target = get_current_target(CMD_CTX); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint32_t apsel, baseaddr; int retval; @@ -1534,10 +1585,7 @@ COMMAND_HANDLER(dap_baseaddr_command) COMMAND_HANDLER(dap_memaccess_command) { - struct target *target = get_current_target(CMD_CTX); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint32_t memaccess_tck; switch (CMD_ARGC) { @@ -1560,10 +1608,7 @@ COMMAND_HANDLER(dap_memaccess_command) COMMAND_HANDLER(dap_apsel_command) { - struct target *target = get_current_target(CMD_CTX); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint32_t apsel, apid; int retval; @@ -1598,11 +1643,9 @@ COMMAND_HANDLER(dap_apsel_command) COMMAND_HANDLER(dap_apcsw_command) { - struct target *target = get_current_target(CMD_CTX); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - - uint32_t apcsw = dap->ap[dap->apsel].csw_default, sprot = 0; + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); + uint32_t apcsw = dap->ap[dap->apsel].csw_default; + uint32_t sprot = 0; switch (CMD_ARGC) { case 0: @@ -1631,10 +1674,7 @@ COMMAND_HANDLER(dap_apcsw_command) COMMAND_HANDLER(dap_apid_command) { - struct target *target = get_current_target(CMD_CTX); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint32_t apsel, apid; int retval; @@ -1666,10 +1706,7 @@ COMMAND_HANDLER(dap_apid_command) COMMAND_HANDLER(dap_apreg_command) { - struct target *target = get_current_target(CMD_CTX); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint32_t apsel, reg, value; int retval; @@ -1705,10 +1742,7 @@ COMMAND_HANDLER(dap_apreg_command) COMMAND_HANDLER(dap_ti_be_32_quirks_command) { - struct target *target = get_current_target(CMD_CTX); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint32_t enable = dap->ti_be_32_quirks; switch (CMD_ARGC) { @@ -1729,7 +1763,7 @@ COMMAND_HANDLER(dap_ti_be_32_quirks_command) return 0; } -static const struct command_registration dap_commands[] = { +const struct command_registration dap_instance_commands[] = { { .name = "info", .handler = handle_dap_info_command, @@ -1795,14 +1829,3 @@ static const struct command_registration dap_commands[] = { }, COMMAND_REGISTRATION_DONE }; - -const struct command_registration dap_command_handlers[] = { - { - .name = "dap", - .mode = COMMAND_EXEC, - .help = "DAP command group", - .usage = "", - .chain = dap_commands, - }, - COMMAND_REGISTRATION_DONE -}; diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index 657427b25..aa5fa42fe 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -254,6 +254,8 @@ struct adiv5_dap { * available until run(). */ struct dap_ops { + /** connect operation for SWD */ + int (*connect)(struct adiv5_dap *dap); /** DP register read. */ int (*queue_dp_read)(struct adiv5_dap *dap, unsigned reg, uint32_t *data); @@ -473,9 +475,6 @@ int mem_ap_read_buf_noincr(struct adiv5_ap *ap, int mem_ap_write_buf_noincr(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t address); -/* Create DAP struct */ -struct adiv5_dap *dap_init(void); - /* Initialisation of the debug system, power domains and registers */ int dap_dp_init(struct adiv5_dap *dap); int mem_ap_init(struct adiv5_ap *ap); @@ -509,12 +508,24 @@ int dap_to_swd(struct target *target); /* Put debug link into JTAG mode */ int dap_to_jtag(struct target *target); -extern const struct command_registration dap_command_handlers[]; +extern const struct command_registration dap_instance_commands[]; + +struct arm_dap_object; +extern struct adiv5_dap *dap_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o); +extern struct adiv5_dap *adiv5_get_dap(struct arm_dap_object *obj); +extern int dap_info_command(struct command_context *cmd_ctx, + struct adiv5_ap *ap); +extern int dap_register_commands(struct command_context *cmd_ctx); +extern const char *adiv5_dap_name(struct adiv5_dap *self); +extern const struct swd_driver *adiv5_dap_swd_driver(struct adiv5_dap *self); +extern int dap_cleanup_all(void); struct adiv5_private_config { int ap_num; + struct adiv5_dap *dap; }; +extern int adiv5_verify_config(struct adiv5_private_config *pc); extern int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi); #endif /* OPENOCD_TARGET_ARM_ADI_V5_H */ diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c index 75169b2ee..547b96158 100644 --- a/src/target/arm_cti.c +++ b/src/target/arm_cti.c @@ -27,21 +27,47 @@ #include "target/arm_cti.h" #include "target/target.h" #include "helper/time_support.h" +#include "helper/list.h" +#include "helper/command.h" struct arm_cti { - uint32_t base; + target_addr_t base; struct adiv5_ap *ap; }; -struct arm_cti *arm_cti_create(struct adiv5_ap *ap, uint32_t base) -{ - struct arm_cti *self = calloc(1, sizeof(struct arm_cti)); - if (!self) - return NULL; +struct arm_cti_object { + struct list_head lh; + struct arm_cti cti; + int ap_num; + char *name; +}; - self->base = base; - self->ap = ap; - return self; +static LIST_HEAD(all_cti); + +const char *arm_cti_name(struct arm_cti *self) +{ + struct arm_cti_object *obj = container_of(self, struct arm_cti_object, cti); + return obj->name; +} + +struct arm_cti *cti_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) +{ + struct arm_cti_object *obj = NULL; + const char *name; + bool found = false; + + name = Jim_GetString(o, NULL); + + list_for_each_entry(obj, &all_cti, lh) { + if (!strcmp(name, obj->name)) { + found = true; + break; + } + } + + if (found) + return &obj->cti; + return NULL; } static int arm_cti_mod_reg_bits(struct arm_cti *self, unsigned int reg, uint32_t mask, uint32_t value) @@ -146,3 +172,396 @@ int arm_cti_clear_channel(struct arm_cti *self, uint32_t channel) return arm_cti_write_reg(self, CTI_APPCLEAR, CTI_CHNL(channel)); } + +static uint32_t cti_regs[26]; + +static const struct { + uint32_t offset; + const char *label; + uint32_t *p_val; +} cti_names[] = { + { CTI_CTR, "CTR", &cti_regs[0] }, + { CTI_GATE, "GATE", &cti_regs[1] }, + { CTI_INEN0, "INEN0", &cti_regs[2] }, + { CTI_INEN1, "INEN1", &cti_regs[3] }, + { CTI_INEN2, "INEN2", &cti_regs[4] }, + { CTI_INEN3, "INEN3", &cti_regs[5] }, + { CTI_INEN4, "INEN4", &cti_regs[6] }, + { CTI_INEN5, "INEN5", &cti_regs[7] }, + { CTI_INEN6, "INEN6", &cti_regs[8] }, + { CTI_INEN7, "INEN7", &cti_regs[9] }, + { CTI_INEN8, "INEN8", &cti_regs[10] }, + { CTI_OUTEN0, "OUTEN0", &cti_regs[11] }, + { CTI_OUTEN1, "OUTEN1", &cti_regs[12] }, + { CTI_OUTEN2, "OUTEN2", &cti_regs[13] }, + { CTI_OUTEN3, "OUTEN3", &cti_regs[14] }, + { CTI_OUTEN4, "OUTEN4", &cti_regs[15] }, + { CTI_OUTEN5, "OUTEN5", &cti_regs[16] }, + { CTI_OUTEN6, "OUTEN6", &cti_regs[17] }, + { CTI_OUTEN7, "OUTEN7", &cti_regs[18] }, + { CTI_OUTEN8, "OUTEN8", &cti_regs[19] }, + { CTI_TRIN_STATUS, "TRIN", &cti_regs[20] }, + { CTI_TROUT_STATUS, "TROUT", &cti_regs[21] }, + { CTI_CHIN_STATUS, "CHIN", &cti_regs[22] }, + { CTI_CHOU_STATUS, "CHOUT", &cti_regs[23] }, + { CTI_APPSET, "APPSET", &cti_regs[24] }, + { CTI_APPCLEAR, "APPCLR", &cti_regs[25] }, +}; + +static int cti_find_reg_offset(const char *name) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(cti_names); i++) { + if (!strcmp(name, cti_names[i].label)) + return cti_names[i].offset; + } + return -1; +} + +COMMAND_HANDLER(handle_cti_dump) +{ + struct arm_cti_object *obj = CMD_DATA; + struct arm_cti *cti = &obj->cti; + int retval = ERROR_OK; + + for (int i = 0; (retval == ERROR_OK) && (i < (int)ARRAY_SIZE(cti_names)); i++) + retval = mem_ap_read_u32(cti->ap, + cti->base + cti_names[i].offset, cti_names[i].p_val); + + if (retval == ERROR_OK) + retval = dap_run(cti->ap->dap); + + if (retval != ERROR_OK) + return JIM_ERR; + + for (int i = 0; i < (int)ARRAY_SIZE(cti_names); i++) + command_print(CMD_CTX, "%8.8s (0x%04"PRIx32") 0x%08"PRIx32, + cti_names[i].label, cti_names[i].offset, *cti_names[i].p_val); + + return JIM_OK; +} + +COMMAND_HANDLER(handle_cti_enable) +{ + struct arm_cti_object *obj = CMD_DATA; + Jim_Interp *interp = CMD_CTX->interp; + struct arm_cti *cti = &obj->cti; + bool on_off; + + if (CMD_ARGC != 1) { + Jim_SetResultString(interp, "wrong number of args", -1); + return ERROR_FAIL; + } + + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off); + + return arm_cti_enable(cti, on_off); +} + +COMMAND_HANDLER(handle_cti_testmode) +{ + struct arm_cti_object *obj = CMD_DATA; + Jim_Interp *interp = CMD_CTX->interp; + struct arm_cti *cti = &obj->cti; + bool on_off; + + if (CMD_ARGC != 1) { + Jim_SetResultString(interp, "wrong number of args", -1); + return ERROR_FAIL; + } + + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off); + + return arm_cti_write_reg(cti, 0xf00, on_off ? 0x1 : 0x0); +} + +COMMAND_HANDLER(handle_cti_write) +{ + struct arm_cti_object *obj = CMD_DATA; + Jim_Interp *interp = CMD_CTX->interp; + struct arm_cti *cti = &obj->cti; + int offset; + uint32_t value; + + if (CMD_ARGC != 2) { + Jim_SetResultString(interp, "Wrong numer of args", -1); + return ERROR_FAIL; + } + + offset = cti_find_reg_offset(CMD_ARGV[0]); + if (offset < 0) + return ERROR_FAIL; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + + return arm_cti_write_reg(cti, offset, value); +} + +COMMAND_HANDLER(handle_cti_read) +{ + struct arm_cti_object *obj = CMD_DATA; + Jim_Interp *interp = CMD_CTX->interp; + struct arm_cti *cti = &obj->cti; + int offset; + int retval; + uint32_t value; + + if (CMD_ARGC != 1) { + Jim_SetResultString(interp, "Wrong numer of args", -1); + return ERROR_FAIL; + } + + offset = cti_find_reg_offset(CMD_ARGV[0]); + if (offset < 0) + return ERROR_FAIL; + + retval = arm_cti_read_reg(cti, offset, &value); + if (retval != ERROR_OK) + return retval; + + command_print(CMD_CTX, "0x%08"PRIx32, value); + + return ERROR_OK; +} + +static const struct command_registration cti_instance_command_handlers[] = { + { + .name = "dump", + .mode = COMMAND_EXEC, + .handler = handle_cti_dump, + .help = "dump CTI registers", + .usage = "", + }, + { + .name = "enable", + .mode = COMMAND_EXEC, + .handler = handle_cti_enable, + .help = "enable or disable the CTI", + .usage = "'on'|'off'", + }, + { + .name = "testmode", + .mode = COMMAND_EXEC, + .handler = handle_cti_testmode, + .help = "enable or disable integration test mode", + .usage = "'on'|'off'", + }, + { + .name = "write", + .mode = COMMAND_EXEC, + .handler = handle_cti_write, + .help = "write to a CTI register", + .usage = "register_name value", + }, + { + .name = "read", + .mode = COMMAND_EXEC, + .handler = handle_cti_read, + .help = "read a CTI register", + .usage = "register_name", + }, + COMMAND_REGISTRATION_DONE +}; + +enum cti_cfg_param { + CFG_DAP, + CFG_AP_NUM, + CFG_CTIBASE +}; + +static const Jim_Nvp nvp_config_opts[] = { + { .name = "-dap", .value = CFG_DAP }, + { .name = "-ctibase", .value = CFG_CTIBASE }, + { .name = "-ap-num", .value = CFG_AP_NUM }, + { .name = NULL, .value = -1 } +}; + +static int cti_configure(Jim_GetOptInfo *goi, struct arm_cti_object *cti) +{ + struct adiv5_dap *dap = NULL; + Jim_Nvp *n; + jim_wide w; + int e; + + /* parse config or cget options ... */ + while (goi->argc > 0) { + Jim_SetEmptyResult(goi->interp); + + e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n); + if (e != JIM_OK) { + Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0); + return e; + } + switch (n->value) { + case CFG_DAP: { + Jim_Obj *o_t; + e = Jim_GetOpt_Obj(goi, &o_t); + if (e != JIM_OK) + return e; + dap = dap_instance_by_jim_obj(goi->interp, o_t); + if (dap == NULL) { + Jim_SetResultString(goi->interp, "-dap is invalid", -1); + return JIM_ERR; + } + /* loop for more */ + break; + } + case CFG_CTIBASE: + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + cti->cti.base = (uint32_t)w; + /* loop for more */ + break; + + case CFG_AP_NUM: + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + cti->ap_num = (uint32_t)w; + } + } + + if (dap == NULL) { + Jim_SetResultString(goi->interp, "-dap required when creating CTI", -1); + return JIM_ERR; + } + + cti->cti.ap = dap_ap(dap, cti->ap_num); + + return JIM_OK; +} + +static int cti_create(Jim_GetOptInfo *goi) +{ + struct command_context *cmd_ctx; + static struct arm_cti_object *cti; + Jim_Obj *new_cmd; + Jim_Cmd *cmd; + const char *cp; + int e; + + cmd_ctx = current_command_context(goi->interp); + assert(cmd_ctx != NULL); + + if (goi->argc < 3) { + Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options..."); + return JIM_ERR; + } + /* COMMAND */ + Jim_GetOpt_Obj(goi, &new_cmd); + /* does this command exist? */ + cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_ERRMSG); + if (cmd) { + cp = Jim_GetString(new_cmd, NULL); + Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp); + return JIM_ERR; + } + + /* Create it */ + cti = calloc(1, sizeof(struct arm_cti_object)); + if (cti == NULL) + return JIM_ERR; + + e = cti_configure(goi, cti); + if (e != JIM_OK) { + free(cti); + return e; + } + + cp = Jim_GetString(new_cmd, NULL); + cti->name = strdup(cp); + + /* now - create the new cti name command */ + const struct command_registration cti_subcommands[] = { + { + .chain = cti_instance_command_handlers, + }, + COMMAND_REGISTRATION_DONE + }; + const struct command_registration cti_commands[] = { + { + .name = cp, + .mode = COMMAND_ANY, + .help = "cti instance command group", + .usage = "", + .chain = cti_subcommands, + }, + COMMAND_REGISTRATION_DONE + }; + e = register_commands(cmd_ctx, NULL, cti_commands); + if (ERROR_OK != e) + return JIM_ERR; + + struct command *c = command_find_in_context(cmd_ctx, cp); + assert(c); + command_set_handler_data(c, cti); + + list_add_tail(&cti->lh, &all_cti); + + return (ERROR_OK == e) ? JIM_OK : JIM_ERR; +} + +static int jim_cti_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + Jim_GetOptInfo goi; + Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); + if (goi.argc < 2) { + Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, + " [ ...]"); + return JIM_ERR; + } + return cti_create(&goi); +} + +static int jim_cti_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + struct arm_cti_object *obj; + + if (argc != 1) { + Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); + return JIM_ERR; + } + Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); + list_for_each_entry(obj, &all_cti, lh) { + Jim_ListAppendElement(interp, Jim_GetResult(interp), + Jim_NewStringObj(interp, obj->name, -1)); + } + return JIM_OK; +} + + +static const struct command_registration cti_subcommand_handlers[] = { + { + .name = "create", + .mode = COMMAND_ANY, + .jim_handler = jim_cti_create, + .usage = "name '-chain-position' name [options ...]", + .help = "Creates a new CTI object", + }, + { + .name = "names", + .mode = COMMAND_ANY, + .jim_handler = jim_cti_names, + .usage = "", + .help = "Lists all registered CTI objects by name", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration cti_command_handlers[] = { + { + .name = "cti", + .mode = COMMAND_CONFIG, + .help = "CTI commands", + .chain = cti_subcommand_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +int cti_register_commands(struct command_context *cmd_ctx) +{ + return register_commands(cmd_ctx, NULL, cti_command_handlers); +} + diff --git a/src/target/arm_cti.h b/src/target/arm_cti.h index 99724c406..181f06447 100644 --- a/src/target/arm_cti.h +++ b/src/target/arm_cti.h @@ -34,6 +34,7 @@ #define CTI_INEN5 0x34 #define CTI_INEN6 0x38 #define CTI_INEN7 0x3C +#define CTI_INEN8 0x40 #define CTI_INEN(n) (0x20 + 4 * n) #define CTI_OUTEN0 0xA0 #define CTI_OUTEN1 0xA4 @@ -43,6 +44,7 @@ #define CTI_OUTEN5 0xB4 #define CTI_OUTEN6 0xB8 #define CTI_OUTEN7 0xBC +#define CTI_OUTEN8 0xC0 #define CTI_OUTEN(n) (0xA0 + 4 * n) #define CTI_TRIN_STATUS 0x130 #define CTI_TROUT_STATUS 0x134 @@ -58,8 +60,10 @@ /* forward-declare arm_cti struct */ struct arm_cti; +struct adiv5_ap; -extern struct arm_cti *arm_cti_create(struct adiv5_ap *ap, uint32_t base); +extern const char *arm_cti_name(struct arm_cti *self); +extern struct arm_cti *cti_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o); extern int arm_cti_enable(struct arm_cti *self, bool enable); extern int arm_cti_ack_events(struct arm_cti *self, uint32_t event); extern int arm_cti_gate_channel(struct arm_cti *self, uint32_t channel); @@ -70,4 +74,6 @@ extern int arm_cti_pulse_channel(struct arm_cti *self, uint32_t channel); extern int arm_cti_set_channel(struct arm_cti *self, uint32_t channel); extern int arm_cti_clear_channel(struct arm_cti *self, uint32_t channel); +extern int cti_register_commands(struct command_context *cmd_ctx); + #endif /* OPENOCD_TARGET_ARM_CTI_H */ diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c new file mode 100644 index 000000000..692feb322 --- /dev/null +++ b/src/target/arm_dap.c @@ -0,0 +1,366 @@ +/*************************************************************************** + * Copyright (C) 2016 by Matthias Welwarsky * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "target/arm_adi_v5.h" +#include "target/arm.h" +#include "helper/list.h" +#include "helper/command.h" +#include "transport/transport.h" +#include "jtag/interface.h" + +static LIST_HEAD(all_dap); + +extern const struct dap_ops swd_dap_ops; +extern const struct dap_ops jtag_dp_ops; +extern struct jtag_interface *jtag_interface; + +/* DAP command support */ +struct arm_dap_object { + struct list_head lh; + struct adiv5_dap dap; + char *name; + const struct swd_driver *swd; +}; + +static void dap_instance_init(struct adiv5_dap *dap) +{ + int i; + /* Set up with safe defaults */ + for (i = 0; i <= 255; i++) { + dap->ap[i].dap = dap; + dap->ap[i].ap_num = i; + /* memaccess_tck max is 255 */ + dap->ap[i].memaccess_tck = 255; + /* Number of bits for tar autoincrement, impl. dep. at least 10 */ + dap->ap[i].tar_autoincr_block = (1<<10); + } + INIT_LIST_HEAD(&dap->cmd_journal); +} + +const char *adiv5_dap_name(struct adiv5_dap *self) +{ + struct arm_dap_object *obj = container_of(self, struct arm_dap_object, dap); + return obj->name; +} + +const struct swd_driver *adiv5_dap_swd_driver(struct adiv5_dap *self) +{ + struct arm_dap_object *obj = container_of(self, struct arm_dap_object, dap); + return obj->swd; +} + +struct adiv5_dap *adiv5_get_dap(struct arm_dap_object *obj) +{ + return &obj->dap; +} +struct adiv5_dap *dap_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) +{ + struct arm_dap_object *obj = NULL; + const char *name; + bool found = false; + + name = Jim_GetString(o, NULL); + + list_for_each_entry(obj, &all_dap, lh) { + if (!strcmp(name, obj->name)) { + found = true; + break; + } + } + + if (found) + return &obj->dap; + return NULL; +} + +static int dap_init_all(void) +{ + struct arm_dap_object *obj; + int retval; + + LOG_DEBUG("Initializing all DAPs ..."); + + list_for_each_entry(obj, &all_dap, lh) { + struct adiv5_dap *dap = &obj->dap; + + /* with hla, dap is just a dummy */ + if (transport_is_hla()) + continue; + + /* skip taps that are disabled */ + if (!dap->tap->enabled) + continue; + + if (transport_is_swd()) { + dap->ops = &swd_dap_ops; + obj->swd = jtag_interface->swd; + } else + dap->ops = &jtag_dp_ops; + + retval = dap->ops->connect(dap); + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + +int dap_cleanup_all(void) +{ + struct arm_dap_object *obj, *tmp; + + list_for_each_entry_safe(obj, tmp, &all_dap, lh) { + free(obj->name); + free(obj); + } + + return ERROR_OK; +} + +enum dap_cfg_param { + CFG_CHAIN_POSITION, +}; + +static const Jim_Nvp nvp_config_opts[] = { + { .name = "-chain-position", .value = CFG_CHAIN_POSITION }, + { .name = NULL, .value = -1 } +}; + +static int dap_configure(Jim_GetOptInfo *goi, struct arm_dap_object *dap) +{ + struct jtag_tap *tap = NULL; + Jim_Nvp *n; + int e; + + /* parse config or cget options ... */ + while (goi->argc > 0) { + Jim_SetEmptyResult(goi->interp); + + e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n); + if (e != JIM_OK) { + Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0); + return e; + } + switch (n->value) { + case CFG_CHAIN_POSITION: { + Jim_Obj *o_t; + e = Jim_GetOpt_Obj(goi, &o_t); + if (e != JIM_OK) + return e; + tap = jtag_tap_by_jim_obj(goi->interp, o_t); + if (tap == NULL) { + Jim_SetResultString(goi->interp, "-chain-position is invalid", -1); + return JIM_ERR; + } + /* loop for more */ + break; + } + default: + break; + } + } + + if (tap == NULL) { + Jim_SetResultString(goi->interp, "-chain-position required when creating DAP", -1); + return JIM_ERR; + } + + dap_instance_init(&dap->dap); + dap->dap.tap = tap; + + return JIM_OK; +} + +static int dap_create(Jim_GetOptInfo *goi) +{ + struct command_context *cmd_ctx; + static struct arm_dap_object *dap; + Jim_Obj *new_cmd; + Jim_Cmd *cmd; + const char *cp; + int e; + + cmd_ctx = current_command_context(goi->interp); + assert(cmd_ctx != NULL); + + if (goi->argc < 3) { + Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options..."); + return JIM_ERR; + } + /* COMMAND */ + Jim_GetOpt_Obj(goi, &new_cmd); + /* does this command exist? */ + cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_ERRMSG); + if (cmd) { + cp = Jim_GetString(new_cmd, NULL); + Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp); + return JIM_ERR; + } + + /* Create it */ + dap = calloc(1, sizeof(struct arm_dap_object)); + if (dap == NULL) + return JIM_ERR; + + e = dap_configure(goi, dap); + if (e != JIM_OK) { + free(dap); + return e; + } + + cp = Jim_GetString(new_cmd, NULL); + dap->name = strdup(cp); + + struct command_registration dap_commands[] = { + { + .name = cp, + .mode = COMMAND_ANY, + .help = "dap instance command group", + .usage = "", + .chain = dap_instance_commands, + }, + COMMAND_REGISTRATION_DONE + }; + + /* don't expose the instance commands when using hla */ + if (transport_is_hla()) + dap_commands[0].chain = NULL; + + e = register_commands(cmd_ctx, NULL, dap_commands); + if (ERROR_OK != e) + return JIM_ERR; + + struct command *c = command_find_in_context(cmd_ctx, cp); + assert(c); + command_set_handler_data(c, dap); + + list_add_tail(&dap->lh, &all_dap); + + return (ERROR_OK == e) ? JIM_OK : JIM_ERR; +} + +static int jim_dap_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + Jim_GetOptInfo goi; + Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); + if (goi.argc < 2) { + Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, + " [ ...]"); + return JIM_ERR; + } + return dap_create(&goi); +} + +static int jim_dap_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + struct arm_dap_object *obj; + + if (argc != 1) { + Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); + return JIM_ERR; + } + Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); + list_for_each_entry(obj, &all_dap, lh) { + Jim_ListAppendElement(interp, Jim_GetResult(interp), + Jim_NewStringObj(interp, obj->name, -1)); + } + return JIM_OK; +} + +COMMAND_HANDLER(handle_dap_init) +{ + return dap_init_all(); +} + +COMMAND_HANDLER(handle_dap_info_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct arm *arm = target_to_arm(target); + struct adiv5_dap *dap = arm->dap; + uint32_t apsel; + + switch (CMD_ARGC) { + case 0: + apsel = dap->apsel; + break; + case 1: + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); + if (apsel >= 256) + return ERROR_COMMAND_SYNTAX_ERROR; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + return dap_info_command(CMD_CTX, &dap->ap[apsel]); +} + +static const struct command_registration dap_subcommand_handlers[] = { + { + .name = "create", + .mode = COMMAND_ANY, + .jim_handler = jim_dap_create, + .usage = "name '-chain-position' name", + .help = "Creates a new DAP instance", + }, + { + .name = "names", + .mode = COMMAND_ANY, + .jim_handler = jim_dap_names, + .usage = "", + .help = "Lists all registered DAP instances by name", + }, + { + .name = "init", + .mode = COMMAND_ANY, + .handler = handle_dap_init, + .usage = "", + .help = "Initialize all registered DAP instances" + }, + { + .name = "info", + .handler = handle_dap_info_command, + .mode = COMMAND_EXEC, + .help = "display ROM table for MEM-AP of current target " + "(default currently selected AP)", + .usage = "[ap_num]", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration dap_commands[] = { + { + .name = "dap", + .mode = COMMAND_CONFIG, + .help = "DAP commands", + .chain = dap_subcommand_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +int dap_register_commands(struct command_context *cmd_ctx) +{ + return register_commands(cmd_ctx, NULL, dap_commands); +} diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c index ef69a203c..8e783d342 100644 --- a/src/target/arm_disassembler.c +++ b/src/target/arm_disassembler.c @@ -2978,6 +2978,7 @@ static int t2ev_b_bl(uint32_t opcode, uint32_t address, case 0x4: inst = "BLX"; instruction->type = ARM_BLX; + address &= 0xfffffffc; break; case 0x5: inst = "BL"; diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index 3e8180c36..65790995a 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -131,6 +131,42 @@ int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) return retval; } +/* Read 64bit VFP registers */ +static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum) +{ + int retval = ERROR_FAIL; + uint32_t value_r0, value_r1; + + switch (regnum) { + case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: + /* move from double word register to r0:r1: "vmov r0, r1, vm" + * then read r0 via dcc + */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_VMOV(1, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4), + ((regnum - ARM_VFP_V3_D0) & 0xf)), &value_r0); + /* read r1 via dcc */ + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, 1, 0, 5, 0), + &value_r1); + break; + default: + + break; + } + + if (retval == ERROR_OK) { + buf_set_u32(r->value, 0, 32, value_r0); + buf_set_u32(r->value + 4, 0, 32, value_r1); + r->valid = true; + r->dirty = false; + LOG_DEBUG("READ: %s, %8.8x, %8.8x", r->name, + (unsigned) value_r0, (unsigned) value_r1); + } + + return retval; +} + /* just read the register -- rely on the core mode being right */ static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { @@ -171,6 +207,14 @@ static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) break; } break; + case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: + return dpm_read_reg_u64(dpm, r, regnum); + break; + case ARM_VFP_V3_FPSCR: + /* "VMRS r0, FPSCR"; then return via DCC */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_VMRS(0), &value); + break; default: /* 16: "MRS r0, CPSR"; then return via DCC * 17: "MRS r0, SPSR"; then return via DCC @@ -191,6 +235,40 @@ static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) return retval; } +/* Write 64bit VFP registers */ +static int dpm_write_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum) +{ + int retval = ERROR_FAIL; + uint32_t value_r0 = buf_get_u32(r->value, 0, 32); + uint32_t value_r1 = buf_get_u32(r->value + 4, 0, 32); + + switch (regnum) { + case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: + /* write value_r1 to r1 via dcc */ + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, 1, 0, 5, 0), + value_r1); + /* write value_r0 to r0 via dcc then, + * move to double word register from r0:r1: "vmov vm, r0, r1" + */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_VMOV(0, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4), + ((regnum - ARM_VFP_V3_D0) & 0xf)), value_r0); + break; + default: + + break; + } + + if (retval == ERROR_OK) { + r->dirty = false; + LOG_DEBUG("WRITE: %s, %8.8x, %8.8x", r->name, + (unsigned) value_r0, (unsigned) value_r1); + } + + return retval; +} + /* just write the register -- rely on the core mode being right */ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { @@ -208,6 +286,14 @@ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) * read r0 from DCC; then "MOV pc, r0" */ retval = dpm->instr_write_data_r0(dpm, 0xe1a0f000, value); break; + case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: + return dpm_write_reg_u64(dpm, r, regnum); + break; + case ARM_VFP_V3_FPSCR: + /* move to r0 from DCC, then "VMSR FPSCR, r0" */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_VMSR(0), value); + break; default: /* 16: read r0 from DCC, then "MSR r0, CPSR_cxsf" * 17: read r0 from DCC, then "MSR r0, SPSR_cxsf" @@ -262,14 +348,16 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm) if (retval != ERROR_OK) return retval; - /* read R0 first (it's used for scratch), then CPSR */ - r = arm->core_cache->reg_list + 0; - if (!r->valid) { - retval = dpm_read_reg(dpm, r, 0); - if (retval != ERROR_OK) - goto fail; + /* read R0 and R1 first (it's used for scratch), then CPSR */ + for (unsigned i = 0; i < 2; i++) { + r = arm->core_cache->reg_list + i; + if (!r->valid) { + retval = dpm_read_reg(dpm, r, i); + if (retval != ERROR_OK) + goto fail; + } + r->dirty = true; } - r->dirty = true; retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr); if (retval != ERROR_OK) @@ -279,7 +367,7 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm) arm_set_cpsr(arm, cpsr); /* REVISIT we can probably avoid reading R1..R14, saving time... */ - for (unsigned i = 1; i < 16; i++) { + for (unsigned i = 2; i < 16; i++) { r = arm_reg_current(arm, i); if (r->valid) continue; @@ -412,8 +500,8 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) did_write = false; - /* check everything except our scratch register R0 */ - for (unsigned i = 1; i < cache->num_regs; i++) { + /* check everything except our scratch registers R0 and R1 */ + for (unsigned i = 2; i < cache->num_regs; i++) { struct arm_reg *r; unsigned regnum; @@ -540,6 +628,7 @@ static enum arm_mode dpm_mapmode(struct arm *arm, /* r13/sp, and r14/lr are always shadowed */ case 13: case 14: + case ARM_VFP_V3_D0 ... ARM_VFP_V3_FPSCR: return mode; default: LOG_WARNING("invalid register #%u", num); @@ -561,7 +650,8 @@ static int arm_dpm_read_core_reg(struct target *target, struct reg *r, struct arm_dpm *dpm = target_to_arm(target)->dpm; int retval; - if (regnum < 0 || regnum > 16) + if (regnum < 0 || (regnum > 16 && regnum < ARM_VFP_V3_D0) || + (regnum > ARM_VFP_V3_FPSCR)) return ERROR_COMMAND_SYNTAX_ERROR; if (regnum == 16) { @@ -604,7 +694,8 @@ static int arm_dpm_write_core_reg(struct target *target, struct reg *r, int retval; - if (regnum < 0 || regnum > 16) + if (regnum < 0 || (regnum > 16 && regnum < ARM_VFP_V3_D0) || + (regnum > ARM_VFP_V3_FPSCR)) return ERROR_COMMAND_SYNTAX_ERROR; if (regnum == 16) { diff --git a/src/target/arm_opcodes.h b/src/target/arm_opcodes.h index a53fee71e..482abe630 100644 --- a/src/target/arm_opcodes.h +++ b/src/target/arm_opcodes.h @@ -132,6 +132,30 @@ */ #define ARMV4_5_BX(Rm) (0xe12fff10 | (Rm)) +/* Copies two words from two ARM core registers + * into a doubleword extension register, or + * from a doubleword extension register to two ARM core registers. + * See Armv7-A arch reference manual section A8.8.345 + * Rt: Arm core register 1 + * Rt2: Arm core register 2 + * Vm: The doubleword extension register + * M: m = UInt(M:Vm); + * op: to_arm_registers = (op == ‘1’); + */ +#define ARMV4_5_VMOV(op, Rt2, Rt, M, Vm) \ + (0xec400b10 | ((op) << 20) | ((Rt2) << 16) | \ + ((Rt) << 12) | ((M) << 5) | (Vm)) + +/* Moves the value of the FPSCR to an ARM core register + * Rt: Arm core register + */ +#define ARMV4_5_VMRS(Rt) (0xeef10a10 | ((Rt) << 12)) + +/* Moves the value of an ARM core register to the FPSCR. + * Rt: Arm core register + */ +#define ARMV4_5_VMSR(Rt) (0xeee10a10 | ((Rt) << 12)) + /* Store data from coprocessor to consecutive memory * See Armv7-A arch doc section A8.6.187 * P: 1=index mode (offset from Rn) diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 48050b078..a6fadaa0b 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -340,6 +340,50 @@ static const struct { }; +static const struct { + unsigned int id; + const char *name; + uint32_t bits; + enum arm_mode mode; + enum reg_type type; + const char *group; + const char *feature; +} arm_vfp_v3_regs[] = { + { ARM_VFP_V3_D0, "d0", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D1, "d1", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D2, "d2", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D3, "d3", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D4, "d4", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D5, "d5", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D6, "d6", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D7, "d7", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D8, "d8", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D9, "d9", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D10, "d10", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D11, "d11", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D12, "d12", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D13, "d13", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D14, "d14", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D15, "d15", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D16, "d16", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D17, "d17", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D18, "d18", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D19, "d19", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D20, "d20", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D21, "d21", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D22, "d22", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D23, "d23", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D24, "d24", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D25, "d25", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D26, "d26", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D27, "d27", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D28, "d28", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D29, "d29", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D30, "d30", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D31, "d31", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_FPSCR, "fpscr", 32, ARM_MODE_ANY, REG_TYPE_INT, "float", "org.gnu.gdb.arm.vfp"}, +}; + /* map core mode (USR, FIQ, ...) and register number to * indices into the register cache */ @@ -567,6 +611,10 @@ static int armv4_5_set_core_reg(struct reg *reg, uint8_t *buf) } } else { buf_set_u32(reg->value, 0, 32, value); + if (reg->size == 64) { + value = buf_get_u32(buf + 4, 0, 32); + buf_set_u32(reg->value + 4, 0, 32, value); + } reg->valid = 1; } reg->dirty = 1; @@ -582,6 +630,10 @@ static const struct reg_arch_type arm_reg_type = { struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) { int num_regs = ARRAY_SIZE(arm_core_regs); + int num_core_regs = num_regs; + if (arm->arm_vfp_version == ARM_VFP_V3) + num_regs += ARRAY_SIZE(arm_vfp_v3_regs); + struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); struct arm_reg *reg_arch_info = calloc(num_regs, sizeof(struct arm_reg)); @@ -599,7 +651,7 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) cache->reg_list = reg_list; cache->num_regs = 0; - for (i = 0; i < num_regs; i++) { + for (i = 0; i < num_core_regs; i++) { /* Skip registers this core doesn't expose */ if (arm_core_regs[i].mode == ARM_MODE_MON && arm->core_type != ARM_MODE_MON) @@ -651,9 +703,38 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) cache->num_regs++; } + int j; + for (i = num_core_regs, j = 0; i < num_regs; i++, j++) { + reg_arch_info[i].num = arm_vfp_v3_regs[j].id; + reg_arch_info[i].mode = arm_vfp_v3_regs[j].mode; + reg_arch_info[i].target = target; + reg_arch_info[i].arm = arm; + + reg_list[i].name = arm_vfp_v3_regs[j].name; + reg_list[i].number = arm_vfp_v3_regs[j].id; + reg_list[i].size = arm_vfp_v3_regs[j].bits; + reg_list[i].value = reg_arch_info[i].value; + reg_list[i].type = &arm_reg_type; + reg_list[i].arch_info = ®_arch_info[i]; + reg_list[i].exist = true; + + reg_list[i].caller_save = false; + + reg_list[i].reg_data_type = malloc(sizeof(struct reg_data_type)); + reg_list[i].reg_data_type->type = arm_vfp_v3_regs[j].type; + + reg_list[i].feature = malloc(sizeof(struct reg_feature)); + reg_list[i].feature->name = arm_vfp_v3_regs[j].feature; + + reg_list[i].group = arm_vfp_v3_regs[j].group; + + cache->num_regs++; + } + arm->pc = reg_list + 15; arm->cpsr = reg_list + ARMV4_5_CPSR; arm->core_cache = cache; + return cache; } @@ -1229,6 +1310,10 @@ int arm_get_gdb_reg_list(struct target *target, case REG_CLASS_ALL: *reg_list_size = (arm->core_type != ARM_MODE_MON ? 48 : 51); + unsigned int list_size_core = *reg_list_size; + if (arm->arm_vfp_version == ARM_VFP_V3) + *reg_list_size += 33; + *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < 16; i++) @@ -1249,6 +1334,12 @@ int arm_get_gdb_reg_list(struct target *target, (*reg_list)[24] = &arm_gdb_dummy_fps_reg; (*reg_list)[24]->size = 0; + if (arm->arm_vfp_version == ARM_VFP_V3) { + unsigned int num_core_regs = ARRAY_SIZE(arm_core_regs); + for (i = 0; i < 33; i++) + (*reg_list)[list_size_core + i] = &(arm->core_cache->reg_list[num_core_regs + i]); + } + return ERROR_OK; break; diff --git a/src/target/armv7a.c b/src/target/armv7a.c index db72afd21..fab736310 100644 --- a/src/target/armv7a.c +++ b/src/target/armv7a.c @@ -129,9 +129,13 @@ static int armv7a_read_ttbcr(struct target *target) struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; uint32_t ttbcr, ttbcr_n; - int retval = dpm->prepare(dpm); + int ttbidx; + int retval; + + retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; + /* MRC p15,0,,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 2, 0, 2), @@ -145,6 +149,15 @@ static int armv7a_read_ttbcr(struct target *target) armv7a->armv7a_mmu.ttbcr = ttbcr; armv7a->armv7a_mmu.cached = 1; + for (ttbidx = 0; ttbidx < 2; ttbidx++) { + /* MRC p15,0,,c2,c0,ttbidx */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRC(15, 0, 0, 2, 0, ttbidx), + &armv7a->armv7a_mmu.ttbr[ttbidx]); + if (retval != ERROR_OK) + goto done; + } + /* * ARM Architecture Reference Manual (ARMv7-A and ARMv7-Redition), * document # ARM DDI 0406C @@ -182,42 +195,21 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val) uint32_t second_lvl_descriptor = 0x0; int retval; struct armv7a_common *armv7a = target_to_armv7a(target); - struct arm_dpm *dpm = armv7a->arm.dpm; uint32_t ttbidx = 0; /* default to ttbr0 */ uint32_t ttb_mask; uint32_t va_mask; - uint32_t ttbcr; uint32_t ttb; - retval = dpm->prepare(dpm); - if (retval != ERROR_OK) - goto done; - - /* MRC p15,0,,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/ - retval = dpm->instr_read_data_r0(dpm, - ARMV4_5_MRC(15, 0, 0, 2, 0, 2), - &ttbcr); - if (retval != ERROR_OK) - goto done; - - /* if ttbcr has changed or was not read before, re-read the information */ - if ((armv7a->armv7a_mmu.cached == 0) || - (armv7a->armv7a_mmu.ttbcr != ttbcr)) { - armv7a_read_ttbcr(target); - } + if (target->state != TARGET_HALTED) + LOG_INFO("target not halted, using cached values for translation table!"); /* if va is above the range handled by ttbr0, select ttbr1 */ if (va > armv7a->armv7a_mmu.ttbr_range[0]) { /* select ttb 1 */ ttbidx = 1; } - /* MRC p15,0,,c2,c0,ttbidx */ - retval = dpm->instr_read_data_r0(dpm, - ARMV4_5_MRC(15, 0, 0, 2, 0, ttbidx), - &ttb); - if (retval != ERROR_OK) - return retval; + ttb = armv7a->armv7a_mmu.ttbr[ttbidx]; ttb_mask = armv7a->armv7a_mmu.ttbr_mask[ttbidx]; va_mask = 0xfff00000 & armv7a->armv7a_mmu.ttbr_range[ttbidx]; @@ -279,9 +271,6 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val) } return ERROR_OK; - -done: - return retval; } /* V7 method VA TO PA */ @@ -740,6 +729,8 @@ 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], @@ -785,9 +776,6 @@ const struct command_registration l2x_cache_command_handlers[] = { }; const struct command_registration armv7a_command_handlers[] = { - { - .chain = dap_command_handlers, - }, { .chain = l2x_cache_command_handlers, }, diff --git a/src/target/armv7a.h b/src/target/armv7a.h index 14112e4ed..33f6f5dbe 100644 --- a/src/target/armv7a.h +++ b/src/target/armv7a.h @@ -87,6 +87,7 @@ struct armv7a_mmu_common { /* following field mmu working way */ int32_t cached; /* 0: not initialized, 1: initialized */ uint32_t ttbcr; /* cache for ttbcr register */ + uint32_t ttbr[2]; uint32_t ttbr_mask[2]; uint32_t ttbr_range[2]; diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c index 7af3e6d4e..3e5f8d6de 100644 --- a/src/target/armv7a_cache.c +++ b/src/target/armv7a_cache.c @@ -148,10 +148,11 @@ int armv7a_cache_auto_flush_all_data(struct target *target) } else retval = armv7a_l1_d_cache_clean_inval_all(target); - /* do outer cache flushing after inner caches have been flushed */ - retval = arm7a_l2x_flush_all_data(target); + if (retval != ERROR_OK) + return retval; - return retval; + /* do outer cache flushing after inner caches have been flushed */ + return arm7a_l2x_flush_all_data(target); } diff --git a/src/target/armv7m.c b/src/target/armv7m.c index e0911c30f..a8ddfe894 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -843,8 +843,5 @@ const struct command_registration armv7m_command_handlers[] = { { .chain = arm_command_handlers, }, - { - .chain = dap_command_handlers, - }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/armv8.c b/src/target/armv8.c index 1b8e45016..3321dd600 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -135,6 +135,16 @@ static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regv ARMV8_MRS_DSPSR(0), &value); value_64 = value; break; + case ARMV8_FPSR: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS_FPSR(0), &value); + value_64 = value; + break; + case ARMV8_FPCR: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS_FPCR(0), &value); + value_64 = value; + break; case ARMV8_ELR_EL1: retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_ELR_EL1, 0), &value_64); @@ -184,6 +194,31 @@ static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regv if (retval == ERROR_OK && regval != NULL) *regval = value_64; + else + retval = ERROR_FAIL; + + return retval; +} + +static int armv8_read_reg_simdfp_aarch64(struct armv8_common *armv8, int regnum, uint64_t *lvalue, uint64_t *hvalue) +{ + int retval = ERROR_FAIL; + struct arm_dpm *dpm = &armv8->dpm; + + switch (regnum) { + case ARMV8_V0 ... ARMV8_V31: + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MOV_GPR_VFP(0, (regnum - ARMV8_V0), 1), hvalue); + if (retval != ERROR_OK) + return retval; + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MOV_GPR_VFP(0, (regnum - ARMV8_V0), 0), lvalue); + break; + + default: + retval = ERROR_FAIL; + break; + } return retval; } @@ -216,6 +251,18 @@ static int armv8_write_reg(struct armv8_common *armv8, int regnum, uint64_t valu ARMV8_MSR_DSPSR(0), value); break; + case ARMV8_FPSR: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_FPSR(0), + value); + break; + case ARMV8_FPCR: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_FPCR(0), + value); + break; /* registers clobbered by taking exception in debug state */ case ARMV8_ELR_EL1: retval = dpm->instr_write_data_r0_64(dpm, @@ -267,6 +314,29 @@ static int armv8_write_reg(struct armv8_common *armv8, int regnum, uint64_t valu return retval; } +static int armv8_write_reg_simdfp_aarch64(struct armv8_common *armv8, int regnum, uint64_t lvalue, uint64_t hvalue) +{ + int retval = ERROR_FAIL; + struct arm_dpm *dpm = &armv8->dpm; + + switch (regnum) { + case ARMV8_V0 ... ARMV8_V31: + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MOV_VFP_GPR((regnum - ARMV8_V0), 0, 1), hvalue); + if (retval != ERROR_OK) + return retval; + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MOV_VFP_GPR((regnum - ARMV8_V0), 0, 0), lvalue); + break; + + default: + retval = ERROR_FAIL; + break; + } + + return retval; +} + static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *regval) { struct arm_dpm *dpm = &armv8->dpm; @@ -338,6 +408,11 @@ static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *re ARMV8_MRS_xPSR_T1(1, 0), &value); break; + case ARMV8_FPSR: + /* "VMRS r0, FPSCR"; then return via DCC */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_VMRS(0), &value); + break; default: retval = ERROR_FAIL; break; @@ -349,6 +424,56 @@ static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *re return retval; } +static int armv8_read_reg_simdfp_aarch32(struct armv8_common *armv8, int regnum, uint64_t *lvalue, uint64_t *hvalue) +{ + int retval = ERROR_FAIL; + struct arm_dpm *dpm = &armv8->dpm; + struct reg *reg_r1 = dpm->arm->core_cache->reg_list + ARMV8_R1; + uint32_t value_r0 = 0, value_r1 = 0; + unsigned num = (regnum - ARMV8_V0) << 1; + + switch (regnum) { + case ARMV8_V0 ... ARMV8_V15: + /* we are going to write R1, mark it dirty */ + reg_r1->dirty = true; + /* move from double word register to r0:r1: "vmov r0, r1, vm" + * then read r0 via dcc + */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_VMOV(1, 1, 0, (num >> 4), (num & 0xf)), + &value_r0); + /* read r1 via dcc */ + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, 1, 0, 5, 0), + &value_r1); + if (retval == ERROR_OK) { + *lvalue = value_r1; + *lvalue = ((*lvalue) << 32) | value_r0; + } else + return retval; + + num++; + /* repeat above steps for high 64 bits of V register */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_VMOV(1, 1, 0, (num >> 4), (num & 0xf)), + &value_r0); + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, 1, 0, 5, 0), + &value_r1); + if (retval == ERROR_OK) { + *hvalue = value_r1; + *hvalue = ((*hvalue) << 32) | value_r0; + } else + return retval; + break; + default: + retval = ERROR_FAIL; + break; + } + + return retval; +} + static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t value) { struct arm_dpm *dpm = &armv8->dpm; @@ -417,6 +542,11 @@ static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t va ARMV8_MSR_GP_xPSR_T1(1, 0, 15), value); break; + case ARMV8_FPSR: + /* move to r0 from DCC, then "VMSR FPSCR, r0" */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_VMSR(0), value); + break; default: retval = ERROR_FAIL; break; @@ -426,14 +556,63 @@ static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t va } +static int armv8_write_reg_simdfp_aarch32(struct armv8_common *armv8, int regnum, uint64_t lvalue, uint64_t hvalue) +{ + int retval = ERROR_FAIL; + struct arm_dpm *dpm = &armv8->dpm; + struct reg *reg_r1 = dpm->arm->core_cache->reg_list + ARMV8_R1; + uint32_t value_r0 = 0, value_r1 = 0; + unsigned num = (regnum - ARMV8_V0) << 1; + + switch (regnum) { + case ARMV8_V0 ... ARMV8_V15: + /* we are going to write R1, mark it dirty */ + reg_r1->dirty = true; + value_r1 = lvalue >> 32; + value_r0 = lvalue & 0xFFFFFFFF; + /* write value_r1 to r1 via dcc */ + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, 1, 0, 5, 0), + value_r1); + /* write value_r0 to r0 via dcc then, + * move to double word register from r0:r1: "vmov vm, r0, r1" + */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_VMOV(0, 1, 0, (num >> 4), (num & 0xf)), + value_r0); + + num++; + /* repeat above steps for high 64 bits of V register */ + value_r1 = hvalue >> 32; + value_r0 = hvalue & 0xFFFFFFFF; + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, 1, 0, 5, 0), + value_r1); + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_VMOV(0, 1, 0, (num >> 4), (num & 0xf)), + value_r0); + break; + default: + retval = ERROR_FAIL; + break; + } + + return retval; +} + void armv8_select_reg_access(struct armv8_common *armv8, bool is_aarch64) { if (is_aarch64) { armv8->read_reg_u64 = armv8_read_reg; armv8->write_reg_u64 = armv8_write_reg; + armv8->read_reg_u128 = armv8_read_reg_simdfp_aarch64; + armv8->write_reg_u128 = armv8_write_reg_simdfp_aarch64; + } else { armv8->read_reg_u64 = armv8_read_reg32; armv8->write_reg_u64 = armv8_write_reg32; + armv8->read_reg_u128 = armv8_read_reg_simdfp_aarch32; + armv8->write_reg_u128 = armv8_write_reg_simdfp_aarch32; } } @@ -441,6 +620,7 @@ void armv8_select_reg_access(struct armv8_common *armv8, bool is_aarch64) int armv8_read_mpidr(struct armv8_common *armv8) { int retval = ERROR_FAIL; + struct arm *arm = &armv8->arm; struct arm_dpm *dpm = armv8->arm.dpm; uint32_t mpidr; @@ -448,6 +628,13 @@ int armv8_read_mpidr(struct armv8_common *armv8) if (retval != ERROR_OK) goto done; + /* check if we're in an unprivileged mode */ + if (armv8_curel_from_core_mode(arm->core_mode) < SYSTEM_CUREL_EL1) { + retval = armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H); + if (retval != ERROR_OK) + return retval; + } + retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_MPIDR), &mpidr); if (retval != ERROR_OK) goto done; @@ -463,6 +650,7 @@ int armv8_read_mpidr(struct armv8_common *armv8) LOG_ERROR("mpidr not in multiprocessor format"); done: + armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); dpm->finish(dpm); return retval; } @@ -897,63 +1085,150 @@ int armv8_arch_state(struct target *target) return ERROR_OK; } -static const struct { - unsigned id; - const char *name; - unsigned bits; - enum arm_mode mode; - enum reg_type type; - const char *group; - const char *feature; -} armv8_regs[] = { - { ARMV8_R0, "x0", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R1, "x1", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R2, "x2", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R3, "x3", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R4, "x4", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R5, "x5", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R6, "x6", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R7, "x7", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R8, "x8", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R9, "x9", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R10, "x10", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R11, "x11", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R12, "x12", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R13, "x13", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R14, "x14", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R15, "x15", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R16, "x16", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R17, "x17", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R18, "x18", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R19, "x19", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R20, "x20", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R21, "x21", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R22, "x22", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R23, "x23", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R24, "x24", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R25, "x25", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R26, "x26", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R27, "x27", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R28, "x28", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R29, "x29", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R30, "x30", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, +static struct reg_data_type aarch64_vector_base_types[] = { + {REG_TYPE_IEEE_DOUBLE, "ieee_double", 0, {NULL} }, + {REG_TYPE_UINT64, "uint64", 0, {NULL} }, + {REG_TYPE_INT64, "int64", 0, {NULL} }, + {REG_TYPE_IEEE_SINGLE, "ieee_single", 0, {NULL} }, + {REG_TYPE_UINT32, "uint32", 0, {NULL} }, + {REG_TYPE_INT32, "int32", 0, {NULL} }, + {REG_TYPE_UINT16, "uint16", 0, {NULL} }, + {REG_TYPE_INT16, "int16", 0, {NULL} }, + {REG_TYPE_UINT8, "uint8", 0, {NULL} }, + {REG_TYPE_INT8, "int8", 0, {NULL} }, + {REG_TYPE_UINT128, "uint128", 0, {NULL} }, + {REG_TYPE_INT128, "int128", 0, {NULL} } +}; - { ARMV8_SP, "sp", 64, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_PC, "pc", 64, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.aarch64.core" }, +static struct reg_data_type_vector aarch64_vector_types[] = { + {aarch64_vector_base_types + 0, 2}, + {aarch64_vector_base_types + 1, 2}, + {aarch64_vector_base_types + 2, 2}, + {aarch64_vector_base_types + 3, 4}, + {aarch64_vector_base_types + 4, 4}, + {aarch64_vector_base_types + 5, 4}, + {aarch64_vector_base_types + 6, 8}, + {aarch64_vector_base_types + 7, 8}, + {aarch64_vector_base_types + 8, 16}, + {aarch64_vector_base_types + 9, 16}, + {aarch64_vector_base_types + 10, 01}, + {aarch64_vector_base_types + 11, 01}, +}; - { ARMV8_xPSR, "CPSR", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.aarch64.core" }, +static struct reg_data_type aarch64_fpu_vector[] = { + {REG_TYPE_ARCH_DEFINED, "v2d", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 0} }, + {REG_TYPE_ARCH_DEFINED, "v2u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 1} }, + {REG_TYPE_ARCH_DEFINED, "v2i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 2} }, + {REG_TYPE_ARCH_DEFINED, "v4f", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 3} }, + {REG_TYPE_ARCH_DEFINED, "v4u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 4} }, + {REG_TYPE_ARCH_DEFINED, "v4i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 5} }, + {REG_TYPE_ARCH_DEFINED, "v8u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 6} }, + {REG_TYPE_ARCH_DEFINED, "v8i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 7} }, + {REG_TYPE_ARCH_DEFINED, "v16u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 8} }, + {REG_TYPE_ARCH_DEFINED, "v16i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 9} }, + {REG_TYPE_ARCH_DEFINED, "v1u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 10} }, + {REG_TYPE_ARCH_DEFINED, "v1i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 11} }, +}; - { ARMV8_ELR_EL1, "ELR_EL1", 64, ARMV8_64_EL1H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked" }, - { ARMV8_ESR_EL1, "ESR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, - { ARMV8_SPSR_EL1, "SPSR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, +static struct reg_data_type_union_field aarch64_union_fields_vnd[] = { + {"f", aarch64_fpu_vector + 0, aarch64_union_fields_vnd + 1}, + {"u", aarch64_fpu_vector + 1, aarch64_union_fields_vnd + 2}, + {"s", aarch64_fpu_vector + 2, NULL}, +}; - { ARMV8_ELR_EL2, "ELR_EL2", 64, ARMV8_64_EL2H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked" }, - { ARMV8_ESR_EL2, "ESR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, - { ARMV8_SPSR_EL2, "SPSR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, +static struct reg_data_type_union_field aarch64_union_fields_vns[] = { + {"f", aarch64_fpu_vector + 3, aarch64_union_fields_vns + 1}, + {"u", aarch64_fpu_vector + 4, aarch64_union_fields_vns + 2}, + {"s", aarch64_fpu_vector + 5, NULL}, +}; - { ARMV8_ELR_EL3, "ELR_EL3", 64, ARMV8_64_EL3H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked" }, - { ARMV8_ESR_EL3, "ESR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, - { ARMV8_SPSR_EL3, "SPSR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, +static struct reg_data_type_union_field aarch64_union_fields_vnh[] = { + {"u", aarch64_fpu_vector + 6, aarch64_union_fields_vnh + 1}, + {"s", aarch64_fpu_vector + 7, NULL}, +}; + +static struct reg_data_type_union_field aarch64_union_fields_vnb[] = { + {"u", aarch64_fpu_vector + 8, aarch64_union_fields_vnb + 1}, + {"s", aarch64_fpu_vector + 9, NULL}, +}; + +static struct reg_data_type_union_field aarch64_union_fields_vnq[] = { + {"u", aarch64_fpu_vector + 10, aarch64_union_fields_vnq + 1}, + {"s", aarch64_fpu_vector + 11, NULL}, +}; + +static struct reg_data_type_union aarch64_union_types[] = { + {aarch64_union_fields_vnd}, + {aarch64_union_fields_vns}, + {aarch64_union_fields_vnh}, + {aarch64_union_fields_vnb}, + {aarch64_union_fields_vnq}, +}; + +static struct reg_data_type aarch64_fpu_union[] = { + {REG_TYPE_ARCH_DEFINED, "vnd", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 0} }, + {REG_TYPE_ARCH_DEFINED, "vns", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 1} }, + {REG_TYPE_ARCH_DEFINED, "vnh", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 2} }, + {REG_TYPE_ARCH_DEFINED, "vnb", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 3} }, + {REG_TYPE_ARCH_DEFINED, "vnq", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 4} }, +}; + +static struct reg_data_type_union_field aarch64v_union_fields[] = { + {"d", aarch64_fpu_union + 0, aarch64v_union_fields + 1}, + {"s", aarch64_fpu_union + 1, aarch64v_union_fields + 2}, + {"h", aarch64_fpu_union + 2, aarch64v_union_fields + 3}, + {"b", aarch64_fpu_union + 3, aarch64v_union_fields + 4}, + {"q", aarch64_fpu_union + 4, NULL}, +}; + +static struct reg_data_type_union aarch64v_union[] = { + {aarch64v_union_fields} +}; + +static struct reg_data_type aarch64v[] = { + {REG_TYPE_ARCH_DEFINED, "aarch64v", REG_TYPE_CLASS_UNION, + {.reg_type_union = aarch64v_union} }, +}; + +static struct reg_data_type_bitfield aarch64_cpsr_bits[] = { + { 0, 0 , REG_TYPE_UINT8 }, + { 2, 3, REG_TYPE_UINT8 }, + { 4, 4 , REG_TYPE_UINT8 }, + { 6, 6 , REG_TYPE_BOOL }, + { 7, 7 , REG_TYPE_BOOL }, + { 8, 8 , REG_TYPE_BOOL }, + { 9, 9 , REG_TYPE_BOOL }, + { 20, 20, REG_TYPE_BOOL }, + { 21, 21, REG_TYPE_BOOL }, + { 28, 28, REG_TYPE_BOOL }, + { 29, 29, REG_TYPE_BOOL }, + { 30, 30, REG_TYPE_BOOL }, + { 31, 31, REG_TYPE_BOOL }, +}; + +static struct reg_data_type_flags_field aarch64_cpsr_fields[] = { + { "SP", aarch64_cpsr_bits + 0, aarch64_cpsr_fields + 1 }, + { "EL", aarch64_cpsr_bits + 1, aarch64_cpsr_fields + 2 }, + { "nRW", aarch64_cpsr_bits + 2, aarch64_cpsr_fields + 3 }, + { "F" , aarch64_cpsr_bits + 3, aarch64_cpsr_fields + 4 }, + { "I" , aarch64_cpsr_bits + 4, aarch64_cpsr_fields + 5 }, + { "A" , aarch64_cpsr_bits + 5, aarch64_cpsr_fields + 6 }, + { "D" , aarch64_cpsr_bits + 6, aarch64_cpsr_fields + 7 }, + { "IL" , aarch64_cpsr_bits + 7, aarch64_cpsr_fields + 8 }, + { "SS" , aarch64_cpsr_bits + 8, aarch64_cpsr_fields + 9 }, + { "V" , aarch64_cpsr_bits + 9, aarch64_cpsr_fields + 10 }, + { "C" , aarch64_cpsr_bits + 10, aarch64_cpsr_fields + 11 }, + { "Z" , aarch64_cpsr_bits + 11, aarch64_cpsr_fields + 12 }, + { "N" , aarch64_cpsr_bits + 12, NULL } +}; + +static struct reg_data_type_flags aarch64_cpsr_flags[] = { + { 4, aarch64_cpsr_fields } +}; + +static struct reg_data_type aarch64_flags_cpsr[] = { + {REG_TYPE_ARCH_DEFINED, "cpsr_flags", REG_TYPE_CLASS_FLAGS, + {.reg_type_flags = aarch64_cpsr_flags} }, }; static const struct { @@ -964,24 +1239,161 @@ static const struct { enum reg_type type; const char *group; const char *feature; + struct reg_data_type *data_type; +} armv8_regs[] = { + { ARMV8_R0, "x0", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R1, "x1", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R2, "x2", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R3, "x3", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R4, "x4", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R5, "x5", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R6, "x6", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R7, "x7", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R8, "x8", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R9, "x9", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R10, "x10", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R11, "x11", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R12, "x12", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R13, "x13", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R14, "x14", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R15, "x15", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R16, "x16", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R17, "x17", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R18, "x18", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R19, "x19", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R20, "x20", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R21, "x21", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R22, "x22", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R23, "x23", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R24, "x24", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R25, "x25", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R26, "x26", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R27, "x27", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R28, "x28", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R29, "x29", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R30, "x30", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + + { ARMV8_SP, "sp", 64, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_PC, "pc", 64, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_xPSR, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, + "general", "org.gnu.gdb.aarch64.core", aarch64_flags_cpsr}, + { ARMV8_V0, "v0", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V1, "v1", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V2, "v2", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V3, "v3", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V4, "v4", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V5, "v5", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V6, "v6", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V7, "v7", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V8, "v8", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V9, "v9", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V10, "v10", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V11, "v11", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V12, "v12", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V13, "v13", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V14, "v14", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V15, "v15", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V16, "v16", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V17, "v17", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V18, "v18", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V19, "v19", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V20, "v20", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V21, "v21", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V22, "v22", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V23, "v23", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V24, "v24", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V25, "v25", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V26, "v26", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V27, "v27", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V28, "v28", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V29, "v29", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V30, "v30", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V31, "v31", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_FPSR, "fpsr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "simdfp", "org.gnu.gdb.aarch64.fpu", NULL}, + { ARMV8_FPCR, "fpcr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "simdfp", "org.gnu.gdb.aarch64.fpu", NULL}, + + { ARMV8_ELR_EL1, "ELR_EL1", 64, ARMV8_64_EL1H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked", + NULL}, + { ARMV8_ESR_EL1, "ESR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", + NULL}, + { ARMV8_SPSR_EL1, "SPSR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", + NULL}, + + { ARMV8_ELR_EL2, "ELR_EL2", 64, ARMV8_64_EL2H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked", + NULL}, + { ARMV8_ESR_EL2, "ESR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", + NULL}, + { ARMV8_SPSR_EL2, "SPSR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", + NULL}, + + { ARMV8_ELR_EL3, "ELR_EL3", 64, ARMV8_64_EL3H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked", + NULL}, + { ARMV8_ESR_EL3, "ESR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", + NULL}, + { ARMV8_SPSR_EL3, "SPSR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", + NULL}, +}; + +static const struct { + unsigned id; + unsigned mapping; + const char *name; + unsigned bits; + enum arm_mode mode; + enum reg_type type; + const char *group; + const char *feature; } armv8_regs32[] = { - { ARMV8_R0, "r0", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R1, "r1", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R2, "r2", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R3, "r3", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R4, "r4", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R5, "r5", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R6, "r6", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R7, "r7", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R8, "r8", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R9, "r9", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R10, "r10", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R11, "r11", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R12, "r12", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R13, "sp", 32, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R14, "lr", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_PC, "pc", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_xPSR, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R0, 0, "r0", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R1, 0, "r1", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R2, 0, "r2", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R3, 0, "r3", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R4, 0, "r4", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R5, 0, "r5", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R6, 0, "r6", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R7, 0, "r7", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R8, 0, "r8", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R9, 0, "r9", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R10, 0, "r10", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R11, 0, "r11", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R12, 0, "r12", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R13, 0, "sp", 32, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R14, 0, "lr", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_PC, 0, "pc", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_xPSR, 0, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_V0, 0, "d0", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V0, 8, "d1", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V1, 0, "d2", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V1, 8, "d3", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V2, 0, "d4", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V2, 8, "d5", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V3, 0, "d6", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V3, 8, "d7", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V4, 0, "d8", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V4, 8, "d9", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V5, 0, "d10", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V5, 8, "d11", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V6, 0, "d12", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V6, 8, "d13", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V7, 0, "d14", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V7, 8, "d15", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V8, 0, "d16", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V8, 8, "d17", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V9, 0, "d18", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V9, 8, "d19", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V10, 0, "d20", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V10, 8, "d21", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V11, 0, "d22", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V11, 8, "d23", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V12, 0, "d24", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V12, 8, "d25", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V13, 0, "d26", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V13, 8, "d27", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V14, 0, "d28", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V14, 8, "d29", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V15, 0, "d30", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V15, 8, "d31", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_FPSR, 0, "fpscr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "float", "org.gnu.gdb.arm.vfp"}, }; #define ARMV8_NUM_REGS ARRAY_SIZE(armv8_regs) @@ -1004,15 +1416,23 @@ static int armv8_set_core_reg(struct reg *reg, uint8_t *buf) struct arm_reg *armv8_reg = reg->arch_info; struct target *target = armv8_reg->target; struct arm *arm = target_to_arm(target); - uint64_t value = buf_get_u64(buf, 0, 64); + uint64_t value = buf_get_u64(buf, 0, reg->size); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; - if (reg == arm->cpsr) { - armv8_set_cpsr(arm, (uint32_t)value); - } else { + if (reg->size <= 64) { + if (reg == arm->cpsr) + armv8_set_cpsr(arm, (uint32_t)value); + else { + buf_set_u64(reg->value, 0, reg->size, value); + reg->valid = 1; + } + } else if (reg->size <= 128) { + uint64_t hvalue = buf_get_u64(buf + 8, 0, reg->size - 64); + buf_set_u64(reg->value, 0, 64, value); + buf_set_u64(reg->value + 8, 0, reg->size - 64, hvalue); reg->valid = 1; } @@ -1061,7 +1481,12 @@ static int armv8_set_core_reg32(struct reg *reg, uint8_t *buf) if (reg64 == arm->cpsr) { armv8_set_cpsr(arm, value); } else { - buf_set_u32(reg->value, 0, 32, value); + if (reg->size <= 32) + buf_set_u32(reg->value, 0, 32, value); + else if (reg->size <= 64) { + uint64_t value64 = buf_get_u64(buf, 0, 64); + buf_set_u64(reg->value, 0, 64, value64); + } reg->valid = 1; reg64->valid = 1; } @@ -1122,11 +1547,15 @@ struct reg_cache *armv8_build_reg_cache(struct target *target) } else LOG_ERROR("unable to allocate feature list"); - reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); - if (reg_list[i].reg_data_type) - reg_list[i].reg_data_type->type = armv8_regs[i].type; - else - LOG_ERROR("unable to allocate reg type list"); + if (armv8_regs[i].data_type == NULL) { + reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); + if (reg_list[i].reg_data_type) + reg_list[i].reg_data_type->type = armv8_regs[i].type; + else + LOG_ERROR("unable to allocate reg type list"); + } else + reg_list[i].reg_data_type = armv8_regs[i].data_type; + } arm->cpsr = reg_list + ARMV8_xPSR; @@ -1142,7 +1571,7 @@ struct reg_cache *armv8_build_reg_cache(struct target *target) for (i = 0; i < num_regs32; i++) { reg_list32[i].name = armv8_regs32[i].name; reg_list32[i].size = armv8_regs32[i].bits; - reg_list32[i].value = &arch_info[armv8_regs32[i].id].value[0]; + reg_list32[i].value = &arch_info[armv8_regs32[i].id].value[armv8_regs32[i].mapping]; reg_list32[i].type = &armv8_reg32_type; reg_list32[i].arch_info = &arch_info[armv8_regs32[i].id]; reg_list32[i].group = armv8_regs32[i].group; @@ -1180,13 +1609,9 @@ struct reg *armv8_reg_current(struct arm *arm, unsigned regnum) } const struct command_registration armv8_command_handlers[] = { - { - .chain = dap_command_handlers, - }, COMMAND_REGISTRATION_DONE }; - int armv8_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) @@ -1200,7 +1625,7 @@ int armv8_get_gdb_reg_list(struct target *target, switch (reg_class) { case REG_CLASS_GENERAL: - *reg_list_size = ARMV8_ELR_EL1; + *reg_list_size = ARMV8_V0; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < *reg_list_size; i++) @@ -1227,6 +1652,13 @@ int armv8_get_gdb_reg_list(struct target *target, switch (reg_class) { case REG_CLASS_GENERAL: + *reg_list_size = ARMV8_R14 + 3; + *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); + + for (i = 0; i < *reg_list_size; i++) + (*reg_list)[i] = cache32->reg_list + i; + + return ERROR_OK; case REG_CLASS_ALL: *reg_list_size = cache32->num_regs; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); diff --git a/src/target/armv8.h b/src/target/armv8.h index 0f3e66f65..6525d2601 100644 --- a/src/target/armv8.h +++ b/src/target/armv8.h @@ -63,17 +63,52 @@ enum { ARMV8_PC = 32, ARMV8_xPSR = 33, - ARMV8_ELR_EL1 = 34, - ARMV8_ESR_EL1 = 35, - ARMV8_SPSR_EL1 = 36, + ARMV8_V0 = 34, + ARMV8_V1, + ARMV8_V2, + ARMV8_V3, + ARMV8_V4, + ARMV8_V5, + ARMV8_V6, + ARMV8_V7, + ARMV8_V8, + ARMV8_V9, + ARMV8_V10, + ARMV8_V11, + ARMV8_V12, + ARMV8_V13, + ARMV8_V14, + ARMV8_V15, + ARMV8_V16, + ARMV8_V17, + ARMV8_V18, + ARMV8_V19, + ARMV8_V20, + ARMV8_V21, + ARMV8_V22, + ARMV8_V23, + ARMV8_V24, + ARMV8_V25, + ARMV8_V26, + ARMV8_V27, + ARMV8_V28, + ARMV8_V29, + ARMV8_V30, + ARMV8_V31, + ARMV8_FPSR, + ARMV8_FPCR, - ARMV8_ELR_EL2 = 37, - ARMV8_ESR_EL2 = 38, - ARMV8_SPSR_EL2 = 39, + ARMV8_ELR_EL1 = 68, + ARMV8_ESR_EL1 = 69, + ARMV8_SPSR_EL1 = 70, - ARMV8_ELR_EL3 = 40, - ARMV8_ESR_EL3 = 41, - ARMV8_SPSR_EL3 = 42, + ARMV8_ELR_EL2 = 71, + ARMV8_ESR_EL2 = 72, + ARMV8_SPSR_EL2 = 73, + + ARMV8_ELR_EL3 = 74, + ARMV8_ESR_EL3 = 75, + ARMV8_SPSR_EL3 = 76, ARMV8_LAST_REG, }; @@ -179,6 +214,12 @@ struct armv8_common { 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); + /* SIMD/FPU registers read/write interface */ + int (*read_reg_u128)(struct armv8_common *armv8, int num, + uint64_t *lvalue, uint64_t *hvalue); + int (*write_reg_u128)(struct armv8_common *armv8, int num, + uint64_t lvalue, uint64_t hvalue); + int (*examine_debug_reason)(struct target *target); int (*post_debug_entry)(struct target *target); diff --git a/src/target/armv8_cache.c b/src/target/armv8_cache.c index 7f610c953..40965ebd8 100644 --- a/src/target/armv8_cache.c +++ b/src/target/armv8_cache.c @@ -310,6 +310,7 @@ int armv8_identify_cache(struct armv8_common *armv8) { /* read cache descriptor */ int retval = ERROR_FAIL; + struct arm *arm = &armv8->arm; struct arm_dpm *dpm = armv8->arm.dpm; uint32_t csselr, clidr, ctr; uint32_t cache_reg; @@ -320,6 +321,13 @@ int armv8_identify_cache(struct armv8_common *armv8) if (retval != ERROR_OK) goto done; + /* check if we're in an unprivileged mode */ + if (armv8_curel_from_core_mode(arm->core_mode) < SYSTEM_CUREL_EL1) { + retval = armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H); + if (retval != ERROR_OK) + return retval; + } + /* retrieve CTR */ retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_CTR), &ctr); @@ -417,6 +425,7 @@ int armv8_identify_cache(struct armv8_common *armv8) } done: + armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); dpm->finish(dpm); return retval; diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index c79b1a0ff..3c941fa2d 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -258,7 +258,7 @@ static int dpmv8_exec_opcode(struct arm_dpm *dpm, if (dscr & DSCR_ERR) { LOG_ERROR("Opcode 0x%08"PRIx32", DSCR.ERR=1, DSCR.EL=%i", opcode, dpm->last_el); - armv8_dpm_handle_exception(dpm); + armv8_dpm_handle_exception(dpm, true); retval = ERROR_FAIL; } @@ -600,7 +600,7 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) armv8_opcode(armv8, ARMV8_OPC_DCPS) | target_el); /* DCPS clobbers registers just like an exception taken */ - armv8_dpm_handle_exception(dpm); + armv8_dpm_handle_exception(dpm, false); } else { core_state = armv8_dpm_get_core_state(dpm); if (core_state != ARM_STATE_AARCH64) { @@ -650,21 +650,37 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) static int dpmv8_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { struct armv8_common *armv8 = dpm->arm->arch_info; - uint64_t value_64; - int retval; + int retval = ERROR_FAIL; - retval = armv8->read_reg_u64(armv8, regnum, &value_64); + if (r->size <= 64) { + uint64_t value_64; + retval = armv8->read_reg_u64(armv8, regnum, &value_64); - if (retval == ERROR_OK) { - r->valid = true; - r->dirty = false; - buf_set_u64(r->value, 0, r->size, value_64); - if (r->size == 64) - LOG_DEBUG("READ: %s, %16.8llx", r->name, (unsigned long long) value_64); - else - LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned int) value_64); + if (retval == ERROR_OK) { + r->valid = true; + r->dirty = false; + buf_set_u64(r->value, 0, r->size, value_64); + if (r->size == 64) + LOG_DEBUG("READ: %s, %16.8llx", r->name, (unsigned long long) value_64); + else + LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned int) value_64); + } + } else if (r->size <= 128) { + uint64_t lvalue = 0, hvalue = 0; + retval = armv8->read_reg_u128(armv8, regnum, &lvalue, &hvalue); + + if (retval == ERROR_OK) { + r->valid = true; + r->dirty = false; + + buf_set_u64(r->value, 0, 64, lvalue); + buf_set_u64(r->value + 8, 0, r->size - 64, hvalue); + + LOG_DEBUG("READ: %s, lvalue=%16.8llx", r->name, (unsigned long long) lvalue); + LOG_DEBUG("READ: %s, hvalue=%16.8llx", r->name, (unsigned long long) hvalue); + } } - return ERROR_OK; + return retval; } /* @@ -674,20 +690,36 @@ static int dpmv8_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { struct armv8_common *armv8 = dpm->arm->arch_info; int retval = ERROR_FAIL; - uint64_t value_64; - value_64 = buf_get_u64(r->value, 0, r->size); + if (r->size <= 64) { + uint64_t value_64; - retval = armv8->write_reg_u64(armv8, regnum, value_64); - if (retval == ERROR_OK) { - r->dirty = false; - if (r->size == 64) - LOG_DEBUG("WRITE: %s, %16.8llx", r->name, (unsigned long long)value_64); - else - LOG_DEBUG("WRITE: %s, %8.8x", r->name, (unsigned int)value_64); + value_64 = buf_get_u64(r->value, 0, r->size); + retval = armv8->write_reg_u64(armv8, regnum, value_64); + + if (retval == ERROR_OK) { + r->dirty = false; + if (r->size == 64) + LOG_DEBUG("WRITE: %s, %16.8llx", r->name, (unsigned long long)value_64); + else + LOG_DEBUG("WRITE: %s, %8.8x", r->name, (unsigned int)value_64); + } + } else if (r->size <= 128) { + uint64_t lvalue, hvalue; + + lvalue = buf_get_u64(r->value, 0, 64); + hvalue = buf_get_u64(r->value + 8, 0, r->size - 64); + retval = armv8->write_reg_u128(armv8, regnum, lvalue, hvalue); + + if (retval == ERROR_OK) { + r->dirty = false; + + LOG_DEBUG("WRITE: %s, lvalue=%16.8llx", r->name, (unsigned long long) lvalue); + LOG_DEBUG("WRITE: %s, hvalue=%16.8llx", r->name, (unsigned long long) hvalue); + } } - return ERROR_OK; + return retval; } /** @@ -745,6 +777,10 @@ int armv8_dpm_read_current_registers(struct arm_dpm *dpm) if (r->valid) continue; + /* Skip reading FP-SIMD registers */ + if (r->number >= ARMV8_V0 && r->number <= ARMV8_FPCR) + continue; + /* * Only read registers that are available from the * current EL (or core mode). @@ -1262,7 +1298,7 @@ void armv8_dpm_report_wfar(struct arm_dpm *dpm, uint64_t addr) * This function must not perform any actions that trigger another exception * or a recursion will happen. */ -void armv8_dpm_handle_exception(struct arm_dpm *dpm) +void armv8_dpm_handle_exception(struct arm_dpm *dpm, bool do_restore) { struct armv8_common *armv8 = dpm->arm->arch_info; struct reg_cache *cache = dpm->arm->core_cache; @@ -1308,7 +1344,8 @@ void armv8_dpm_handle_exception(struct arm_dpm *dpm) armv8_select_opcodes(armv8, core_state == ARM_STATE_AARCH64); armv8_select_reg_access(armv8, core_state == ARM_STATE_AARCH64); - armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); + if (do_restore) + armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); } /*----------------------------------------------------------------------*/ diff --git a/src/target/armv8_dpm.h b/src/target/armv8_dpm.h index c03935928..f40440370 100644 --- a/src/target/armv8_dpm.h +++ b/src/target/armv8_dpm.h @@ -116,7 +116,7 @@ void armv8_dpm_report_wfar(struct arm_dpm *, uint64_t wfar); #define PRCR_COREPURQ (1 << 3) void armv8_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dcsr); -void armv8_dpm_handle_exception(struct arm_dpm *dpm); +void armv8_dpm_handle_exception(struct arm_dpm *dpm, bool do_restore); enum arm_state armv8_dpm_get_core_state(struct arm_dpm *dpm); #endif /* OPENOCD_TARGET_ARM_DPM_H */ diff --git a/src/target/armv8_opcodes.h b/src/target/armv8_opcodes.h index 987198a87..3fda29668 100644 --- a/src/target/armv8_opcodes.h +++ b/src/target/armv8_opcodes.h @@ -167,6 +167,14 @@ #define ARMV8_STRH_IP(Rd, Rn) (0x78002400 | (Rn << 5) | Rd) #define ARMV8_STRW_IP(Rd, Rn) (0xb8004400 | (Rn << 5) | Rd) +#define ARMV8_MOV_GPR_VFP(Rd, Rn, Index) (0x4e083c00 | (Index << 20) | (Rn << 5) | Rd) +#define ARMV8_MOV_VFP_GPR(Rd, Rn, Index) (0x4e081c00 | (Index << 20) | (Rn << 5) | Rd) + +#define ARMV8_MRS_FPCR(Rt) (0xd53b4400 | (Rt)) +#define ARMV8_MRS_FPSR(Rt) (0xd53b4420 | (Rt)) +#define ARMV8_MSR_FPCR(Rt) (0xd51b4400 | (Rt)) +#define ARMV8_MSR_FPSR(Rt) (0xd51b4420 | (Rt)) + #define ARMV8_SYS(System, Rt) (0xD5080000 | ((System) << 5) | Rt) enum armv8_opcode { diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 5d90e3416..8985051ee 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -54,7 +54,7 @@ #include "target_type.h" #include "arm_opcodes.h" #include "arm_semihosting.h" -#include "jtag/swd.h" +#include "transport/transport.h" #include static int cortex_a_poll(struct target *target); @@ -206,23 +206,27 @@ static int cortex_a_init_debug_access(struct target *target) /* lock memory-mapped access to debug registers to prevent * software interference */ - retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + retval = mem_ap_write_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_LOCKACCESS, 0); if (retval != ERROR_OK) return retval; /* Disable cacheline fills and force cache write-through in debug state */ - retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + retval = mem_ap_write_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCCR, 0); if (retval != ERROR_OK) return retval; /* Disable TLB lookup and refill/eviction in debug state */ - retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + retval = mem_ap_write_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSMCR, 0); if (retval != ERROR_OK) return retval; + retval = dap_run(armv7a->debug_ap->dap); + if (retval != ERROR_OK) + return retval; + /* Enabling of instruction execution in debug mode is done in debug_entry code */ /* Resync breakpoint registers */ @@ -1496,10 +1500,22 @@ static int cortex_a_set_breakpoint(struct target *target, brp_list[brp_i].value); } else if (breakpoint->type == BKPT_SOFT) { uint8_t code[4]; + /* length == 2: Thumb breakpoint */ if (breakpoint->length == 2) buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11)); else + /* length == 3: Thumb-2 breakpoint, actual encoding is + * a regular Thumb BKPT instruction but we replace a + * 32bit Thumb-2 instruction, so fix-up the breakpoint + * length + */ + if (breakpoint->length == 3) { + buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11)); + breakpoint->length = 4; + } else + /* length == 4, normal ARM breakpoint */ buf_set_u32(code, 0, 32, ARMV5_BKPT(0x11)); + retval = target_read_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, @@ -2931,12 +2947,6 @@ static int cortex_a_examine_first(struct target *target) int retval = ERROR_OK; uint32_t didr, cpuid, dbg_osreg; - retval = dap_dp_init(swjdp); - if (retval != ERROR_OK) { - LOG_ERROR("Could not initialize the debug port"); - return retval; - } - /* Search for the APB-AP - it is needed for access to debug registers */ retval = dap_find_ap(swjdp, AP_TYPE_APB_AP, &armv7a->debug_ap); if (retval != ERROR_OK) { @@ -3118,22 +3128,13 @@ static int cortex_a_init_target(struct command_context *cmd_ctx, } static int cortex_a_init_arch_info(struct target *target, - struct cortex_a_common *cortex_a, struct jtag_tap *tap) + struct cortex_a_common *cortex_a, struct adiv5_dap *dap) { struct armv7a_common *armv7a = &cortex_a->armv7a_common; /* Setup struct cortex_a_common */ cortex_a->common_magic = CORTEX_A_COMMON_MAGIC; - - /* tap has no dap initialized */ - if (!tap->dap) { - tap->dap = dap_init(); - - /* Leave (only) generic DAP stuff for debugport_init() */ - tap->dap->tap = tap; - } - - armv7a->arm.dap = tap->dap; + armv7a->arm.dap = dap; cortex_a->fast_reg_read = 0; @@ -3159,19 +3160,34 @@ static int cortex_a_init_arch_info(struct target *target, static int cortex_a_target_create(struct target *target, Jim_Interp *interp) { struct cortex_a_common *cortex_a = calloc(1, sizeof(struct cortex_a_common)); + cortex_a->common_magic = CORTEX_A_COMMON_MAGIC; + struct adiv5_private_config *pc; + + if (target->private_config == NULL) + return ERROR_FAIL; + + pc = (struct adiv5_private_config *)target->private_config; cortex_a->armv7a_common.is_armv7r = false; - return cortex_a_init_arch_info(target, cortex_a, target->tap); + cortex_a->armv7a_common.arm.arm_vfp_version = ARM_VFP_V3; + + return cortex_a_init_arch_info(target, cortex_a, pc->dap); } static int cortex_r4_target_create(struct target *target, Jim_Interp *interp) { struct cortex_a_common *cortex_a = calloc(1, sizeof(struct cortex_a_common)); + cortex_a->common_magic = CORTEX_A_COMMON_MAGIC; + struct adiv5_private_config *pc; + + pc = (struct adiv5_private_config *)target->private_config; + if (adiv5_verify_config(pc) != ERROR_OK) + return ERROR_FAIL; cortex_a->armv7a_common.is_armv7r = true; - return cortex_a_init_arch_info(target, cortex_a, target->tap); + return cortex_a_init_arch_info(target, cortex_a, pc->dap); } static void cortex_a_deinit_target(struct target *target) @@ -3182,6 +3198,7 @@ static void cortex_a_deinit_target(struct target *target) free(cortex_a->brp_list); free(dpm->dbp); free(dpm->dwp); + free(target->private_config); free(cortex_a); } @@ -3466,6 +3483,7 @@ struct target_type cortexa_target = { .commands = cortex_a_command_handlers, .target_create = cortex_a_target_create, + .target_jim_configure = adiv5_jim_configure, .init_target = cortex_a_init_target, .examine = cortex_a_examine, .deinit_target = cortex_a_deinit_target, @@ -3477,13 +3495,6 @@ struct target_type cortexa_target = { }; static const struct command_registration cortex_r4_exec_command_handlers[] = { - { - .name = "cache_info", - .handler = cortex_a_handle_cache_info_command, - .mode = COMMAND_EXEC, - .help = "display information about target caches", - .usage = "", - }, { .name = "dbginit", .handler = cortex_a_handle_dbginit_command, @@ -3505,9 +3516,6 @@ static const struct command_registration cortex_r4_command_handlers[] = { { .chain = arm_command_handlers, }, - { - .chain = armv7a_command_handlers, - }, { .name = "cortex_r4", .mode = COMMAND_ANY, @@ -3551,6 +3559,7 @@ struct target_type cortexr4_target = { .commands = cortex_r4_command_handlers, .target_create = cortex_r4_target_create, + .target_jim_configure = adiv5_jim_configure, .init_target = cortex_a_init_target, .examine = cortex_a_examine, .deinit_target = cortex_a_deinit_target, diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 79af632ac..a356350a2 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -1854,6 +1854,18 @@ static struct dwt_reg dwt_comp[] = { DWT_COMPARATOR(1), DWT_COMPARATOR(2), DWT_COMPARATOR(3), + DWT_COMPARATOR(4), + DWT_COMPARATOR(5), + DWT_COMPARATOR(6), + DWT_COMPARATOR(7), + DWT_COMPARATOR(8), + DWT_COMPARATOR(9), + DWT_COMPARATOR(10), + DWT_COMPARATOR(11), + DWT_COMPARATOR(12), + DWT_COMPARATOR(13), + DWT_COMPARATOR(14), + DWT_COMPARATOR(15), #undef DWT_COMPARATOR }; @@ -1887,6 +1899,7 @@ void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target) int reg, i; target_read_u32(target, DWT_CTRL, &dwtcr); + LOG_DEBUG("DWT_CTRL: 0x%" PRIx32, dwtcr); if (!dwtcr) { LOG_DEBUG("no DWT"); return; @@ -1992,12 +2005,6 @@ int cortex_m_examine(struct target *target) /* stlink shares the examine handler but does not support * all its calls */ if (!armv7m->stlink) { - retval = dap_dp_init(swjdp); - if (retval != ERROR_OK) { - LOG_ERROR("Could not initialize the debug port"); - return retval; - } - if (cortex_m->apsel < 0) { /* Search for the MEM-AP */ retval = dap_find_ap(swjdp, AP_TYPE_AHB_AP, &armv7m->debug_ap); @@ -2228,25 +2235,17 @@ static int cortex_m_handle_target_request(void *priv) } static int cortex_m_init_arch_info(struct target *target, - struct cortex_m_common *cortex_m, struct jtag_tap *tap) + struct cortex_m_common *cortex_m, struct adiv5_dap *dap) { struct armv7m_common *armv7m = &cortex_m->armv7m; armv7m_init_arch_info(target, armv7m); - /* tap has no dap initialized */ - if (!tap->dap) { - tap->dap = dap_init(); - - /* Leave (only) generic DAP stuff for debugport_init() */ - tap->dap->tap = tap; - } - /* default reset mode is to use srst if fitted * if not it will use CORTEX_M3_RESET_VECTRESET */ cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET; - armv7m->arm.dap = tap->dap; + armv7m->arm.dap = dap; /* register arch-specific functions */ armv7m->examine_debug_reason = cortex_m_examine_debug_reason; @@ -2266,16 +2265,16 @@ static int cortex_m_init_arch_info(struct target *target, static int cortex_m_target_create(struct target *target, Jim_Interp *interp) { struct cortex_m_common *cortex_m = calloc(1, sizeof(struct cortex_m_common)); - cortex_m->common_magic = CORTEX_M_COMMON_MAGIC; - cortex_m_init_arch_info(target, cortex_m, target->tap); + struct adiv5_private_config *pc; - if (target->private_config != NULL) { - struct adiv5_private_config *pc = - (struct adiv5_private_config *)target->private_config; - cortex_m->apsel = pc->ap_num; - } else - cortex_m->apsel = -1; + pc = (struct adiv5_private_config *)target->private_config; + if (adiv5_verify_config(pc) != ERROR_OK) + return ERROR_FAIL; + + cortex_m->apsel = pc->ap_num; + + cortex_m_init_arch_info(target, cortex_m, pc->dap); return ERROR_OK; } diff --git a/src/target/hla_target.c b/src/target/hla_target.c index a3e683597..9ebf24168 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -271,7 +271,10 @@ static int hl_target_request_data(struct target *target, uint32_t i; for (i = 0; i < (size * 4); i++) { - hl_dcc_read(hl_if, &data, &ctrl); + int err = hl_dcc_read(hl_if, &data, &ctrl); + if (err != ERROR_OK) + return err; + buffer[i] = data; } @@ -281,6 +284,8 @@ static int hl_target_request_data(struct target *target, static int hl_handle_target_request(void *priv) { struct target *target = priv; + int err; + if (!target_was_examined(target)) return ERROR_OK; struct hl_interface_s *hl_if = target_to_adapter(target); @@ -292,7 +297,9 @@ static int hl_handle_target_request(void *priv) uint8_t data; uint8_t ctrl; - hl_dcc_read(hl_if, &data, &ctrl); + err = hl_dcc_read(hl_if, &data, &ctrl); + if (err != ERROR_OK) + return err; /* check if we have data */ if (ctrl & (1 << 0)) { @@ -300,11 +307,20 @@ static int hl_handle_target_request(void *priv) /* we assume target is quick enough */ request = data; - hl_dcc_read(hl_if, &data, &ctrl); + err = hl_dcc_read(hl_if, &data, &ctrl); + if (err != ERROR_OK) + return err; + request |= (data << 8); - hl_dcc_read(hl_if, &data, &ctrl); + err = hl_dcc_read(hl_if, &data, &ctrl); + if (err != ERROR_OK) + return err; + request |= (data << 16); - hl_dcc_read(hl_if, &data, &ctrl); + err = hl_dcc_read(hl_if, &data, &ctrl); + if (err != ERROR_OK) + return err; + request |= (data << 24); target_request(target, request); } @@ -349,12 +365,16 @@ static int adapter_target_create(struct target *target, Jim_Interp *interp) { LOG_DEBUG("%s", __func__); - + struct adiv5_private_config *pc = target->private_config; struct cortex_m_common *cortex_m = calloc(1, sizeof(struct cortex_m_common)); - if (!cortex_m) return ERROR_COMMAND_SYNTAX_ERROR; + if (pc != NULL && pc->ap_num > 0) { + LOG_ERROR("hla_target: invalid parameter -ap-num (> 0)"); + return ERROR_FAIL; + } + adapter_init_arch_info(target, cortex_m, target->tap); return ERROR_OK; @@ -785,6 +805,7 @@ struct target_type hla_target = { .init_target = adapter_init_target, .deinit_target = cortex_m_deinit_target, .target_create = adapter_target_create, + .target_jim_configure = adiv5_jim_configure, .examine = cortex_m_examine, .commands = adapter_command_handlers, diff --git a/src/target/image.c b/src/target/image.c index f97d90403..9f56bea04 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -121,8 +121,9 @@ static int image_ihex_buffer_complete_inner(struct image *image, { struct image_ihex *ihex = image->type_private; struct fileio *fileio = ihex->fileio; - uint32_t full_address = 0x0; + uint32_t full_address; uint32_t cooked_bytes; + bool end_rec = false; int i; /* we can't determine the number of sections that we'll have to create ahead of time, @@ -137,175 +138,190 @@ static int image_ihex_buffer_complete_inner(struct image *image, ihex->buffer = malloc(filesize >> 1); cooked_bytes = 0x0; image->num_sections = 0; - section[image->num_sections].private = &ihex->buffer[cooked_bytes]; - section[image->num_sections].base_address = 0x0; - section[image->num_sections].size = 0x0; - section[image->num_sections].flags = 0; - while (fileio_fgets(fileio, 1023, lpszLine) == ERROR_OK) { - uint32_t count; - uint32_t address; - uint32_t record_type; - uint32_t checksum; - uint8_t cal_checksum = 0; - size_t bytes_read = 0; + while (!fileio_feof(fileio)) { + full_address = 0x0; + section[image->num_sections].private = &ihex->buffer[cooked_bytes]; + section[image->num_sections].base_address = 0x0; + section[image->num_sections].size = 0x0; + section[image->num_sections].flags = 0; - if (lpszLine[0] == '#') - continue; + while (fileio_fgets(fileio, 1023, lpszLine) == ERROR_OK) { + uint32_t count; + uint32_t address; + uint32_t record_type; + uint32_t checksum; + uint8_t cal_checksum = 0; + size_t bytes_read = 0; - if (sscanf(&lpszLine[bytes_read], ":%2" SCNx32 "%4" SCNx32 "%2" SCNx32, &count, - &address, &record_type) != 3) - return ERROR_IMAGE_FORMAT_ERROR; - bytes_read += 9; + /* skip comments and blank lines */ + if ((lpszLine[0] == '#') || (strlen(lpszLine + strspn(lpszLine, "\n\t\r ")) == 0)) + continue; - cal_checksum += (uint8_t)count; - cal_checksum += (uint8_t)(address >> 8); - cal_checksum += (uint8_t)address; - cal_checksum += (uint8_t)record_type; + if (sscanf(&lpszLine[bytes_read], ":%2" SCNx32 "%4" SCNx32 "%2" SCNx32, &count, + &address, &record_type) != 3) + return ERROR_IMAGE_FORMAT_ERROR; + bytes_read += 9; - if (record_type == 0) { /* Data Record */ - if ((full_address & 0xffff) != address) { - /* we encountered a nonconsecutive location, create a new section, - * unless the current section has zero size, in which case this specifies - * the current section's base address - */ - if (section[image->num_sections].size != 0) { - image->num_sections++; - if (image->num_sections >= IMAGE_MAX_SECTIONS) { - /* too many sections */ - LOG_ERROR("Too many sections found in IHEX file"); - return ERROR_IMAGE_FORMAT_ERROR; + cal_checksum += (uint8_t)count; + cal_checksum += (uint8_t)(address >> 8); + cal_checksum += (uint8_t)address; + cal_checksum += (uint8_t)record_type; + + if (record_type == 0) { /* Data Record */ + if ((full_address & 0xffff) != address) { + /* we encountered a nonconsecutive location, create a new section, + * unless the current section has zero size, in which case this specifies + * the current section's base address + */ + if (section[image->num_sections].size != 0) { + image->num_sections++; + if (image->num_sections >= IMAGE_MAX_SECTIONS) { + /* too many sections */ + LOG_ERROR("Too many sections found in IHEX file"); + return ERROR_IMAGE_FORMAT_ERROR; + } + section[image->num_sections].size = 0x0; + section[image->num_sections].flags = 0; + section[image->num_sections].private = + &ihex->buffer[cooked_bytes]; } - section[image->num_sections].size = 0x0; - section[image->num_sections].flags = 0; - section[image->num_sections].private = - &ihex->buffer[cooked_bytes]; + section[image->num_sections].base_address = + (full_address & 0xffff0000) | address; + full_address = (full_address & 0xffff0000) | address; } - section[image->num_sections].base_address = - (full_address & 0xffff0000) | address; - full_address = (full_address & 0xffff0000) | address; - } - while (count-- > 0) { - unsigned value; - sscanf(&lpszLine[bytes_read], "%2x", &value); - ihex->buffer[cooked_bytes] = (uint8_t)value; - cal_checksum += (uint8_t)ihex->buffer[cooked_bytes]; - bytes_read += 2; - cooked_bytes += 1; - section[image->num_sections].size += 1; - full_address++; - } - } else if (record_type == 1) { /* End of File Record */ - /* finish the current section */ - image->num_sections++; + while (count-- > 0) { + unsigned value; + sscanf(&lpszLine[bytes_read], "%2x", &value); + ihex->buffer[cooked_bytes] = (uint8_t)value; + cal_checksum += (uint8_t)ihex->buffer[cooked_bytes]; + bytes_read += 2; + cooked_bytes += 1; + section[image->num_sections].size += 1; + full_address++; + } + } else if (record_type == 1) { /* End of File Record */ + /* finish the current section */ + image->num_sections++; - /* copy section information */ - image->sections = malloc(sizeof(struct imagesection) * image->num_sections); - for (i = 0; i < image->num_sections; i++) { - image->sections[i].private = section[i].private; - image->sections[i].base_address = section[i].base_address; - image->sections[i].size = section[i].size; - image->sections[i].flags = section[i].flags; - } + /* copy section information */ + image->sections = malloc(sizeof(struct imagesection) * image->num_sections); + for (i = 0; i < image->num_sections; i++) { + image->sections[i].private = section[i].private; + image->sections[i].base_address = section[i].base_address; + image->sections[i].size = section[i].size; + image->sections[i].flags = section[i].flags; + } - return ERROR_OK; - } else if (record_type == 2) { /* Linear Address Record */ - uint16_t upper_address; + end_rec = true; + break; + } else if (record_type == 2) { /* Linear Address Record */ + uint16_t upper_address; - sscanf(&lpszLine[bytes_read], "%4hx", &upper_address); - cal_checksum += (uint8_t)(upper_address >> 8); - cal_checksum += (uint8_t)upper_address; - bytes_read += 4; + sscanf(&lpszLine[bytes_read], "%4hx", &upper_address); + cal_checksum += (uint8_t)(upper_address >> 8); + cal_checksum += (uint8_t)upper_address; + bytes_read += 4; - if ((full_address >> 4) != upper_address) { - /* we encountered a nonconsecutive location, create a new section, - * unless the current section has zero size, in which case this specifies - * the current section's base address - */ - if (section[image->num_sections].size != 0) { - image->num_sections++; - if (image->num_sections >= IMAGE_MAX_SECTIONS) { - /* too many sections */ - LOG_ERROR("Too many sections found in IHEX file"); - return ERROR_IMAGE_FORMAT_ERROR; + if ((full_address >> 4) != upper_address) { + /* we encountered a nonconsecutive location, create a new section, + * unless the current section has zero size, in which case this specifies + * the current section's base address + */ + if (section[image->num_sections].size != 0) { + image->num_sections++; + if (image->num_sections >= IMAGE_MAX_SECTIONS) { + /* too many sections */ + LOG_ERROR("Too many sections found in IHEX file"); + return ERROR_IMAGE_FORMAT_ERROR; + } + section[image->num_sections].size = 0x0; + section[image->num_sections].flags = 0; + section[image->num_sections].private = + &ihex->buffer[cooked_bytes]; } - section[image->num_sections].size = 0x0; - section[image->num_sections].flags = 0; - section[image->num_sections].private = - &ihex->buffer[cooked_bytes]; + section[image->num_sections].base_address = + (full_address & 0xffff) | (upper_address << 4); + full_address = (full_address & 0xffff) | (upper_address << 4); } - section[image->num_sections].base_address = - (full_address & 0xffff) | (upper_address << 4); - full_address = (full_address & 0xffff) | (upper_address << 4); - } - } else if (record_type == 3) { /* Start Segment Address Record */ - uint32_t dummy; + } else if (record_type == 3) { /* Start Segment Address Record */ + uint32_t dummy; - /* "Start Segment Address Record" will not be supported - * but we must consume it, and do not create an error. */ - while (count-- > 0) { - sscanf(&lpszLine[bytes_read], "%2" SCNx32, &dummy); - cal_checksum += (uint8_t)dummy; - bytes_read += 2; - } - } else if (record_type == 4) { /* Extended Linear Address Record */ - uint16_t upper_address; + /* "Start Segment Address Record" will not be supported + * but we must consume it, and do not create an error. */ + while (count-- > 0) { + sscanf(&lpszLine[bytes_read], "%2" SCNx32, &dummy); + cal_checksum += (uint8_t)dummy; + bytes_read += 2; + } + } else if (record_type == 4) { /* Extended Linear Address Record */ + uint16_t upper_address; - sscanf(&lpszLine[bytes_read], "%4hx", &upper_address); - cal_checksum += (uint8_t)(upper_address >> 8); - cal_checksum += (uint8_t)upper_address; - bytes_read += 4; + sscanf(&lpszLine[bytes_read], "%4hx", &upper_address); + cal_checksum += (uint8_t)(upper_address >> 8); + cal_checksum += (uint8_t)upper_address; + bytes_read += 4; - if ((full_address >> 16) != upper_address) { - /* we encountered a nonconsecutive location, create a new section, - * unless the current section has zero size, in which case this specifies - * the current section's base address - */ - if (section[image->num_sections].size != 0) { - image->num_sections++; - if (image->num_sections >= IMAGE_MAX_SECTIONS) { - /* too many sections */ - LOG_ERROR("Too many sections found in IHEX file"); - return ERROR_IMAGE_FORMAT_ERROR; + if ((full_address >> 16) != upper_address) { + /* we encountered a nonconsecutive location, create a new section, + * unless the current section has zero size, in which case this specifies + * the current section's base address + */ + if (section[image->num_sections].size != 0) { + image->num_sections++; + if (image->num_sections >= IMAGE_MAX_SECTIONS) { + /* too many sections */ + LOG_ERROR("Too many sections found in IHEX file"); + return ERROR_IMAGE_FORMAT_ERROR; + } + section[image->num_sections].size = 0x0; + section[image->num_sections].flags = 0; + section[image->num_sections].private = + &ihex->buffer[cooked_bytes]; } - section[image->num_sections].size = 0x0; - section[image->num_sections].flags = 0; - section[image->num_sections].private = - &ihex->buffer[cooked_bytes]; + section[image->num_sections].base_address = + (full_address & 0xffff) | (upper_address << 16); + full_address = (full_address & 0xffff) | (upper_address << 16); } - section[image->num_sections].base_address = - (full_address & 0xffff) | (upper_address << 16); - full_address = (full_address & 0xffff) | (upper_address << 16); + } else if (record_type == 5) { /* Start Linear Address Record */ + uint32_t start_address; + + sscanf(&lpszLine[bytes_read], "%8" SCNx32, &start_address); + cal_checksum += (uint8_t)(start_address >> 24); + cal_checksum += (uint8_t)(start_address >> 16); + cal_checksum += (uint8_t)(start_address >> 8); + cal_checksum += (uint8_t)start_address; + bytes_read += 8; + + image->start_address_set = 1; + image->start_address = be_to_h_u32((uint8_t *)&start_address); + } else { + LOG_ERROR("unhandled IHEX record type: %i", (int)record_type); + return ERROR_IMAGE_FORMAT_ERROR; } - } else if (record_type == 5) { /* Start Linear Address Record */ - uint32_t start_address; - sscanf(&lpszLine[bytes_read], "%8" SCNx32, &start_address); - cal_checksum += (uint8_t)(start_address >> 24); - cal_checksum += (uint8_t)(start_address >> 16); - cal_checksum += (uint8_t)(start_address >> 8); - cal_checksum += (uint8_t)start_address; - bytes_read += 8; + sscanf(&lpszLine[bytes_read], "%2" SCNx32, &checksum); - image->start_address_set = 1; - image->start_address = be_to_h_u32((uint8_t *)&start_address); - } else { - LOG_ERROR("unhandled IHEX record type: %i", (int)record_type); - return ERROR_IMAGE_FORMAT_ERROR; - } + if ((uint8_t)checksum != (uint8_t)(~cal_checksum + 1)) { + /* checksum failed */ + LOG_ERROR("incorrect record checksum found in IHEX file"); + return ERROR_IMAGE_CHECKSUM; + } - sscanf(&lpszLine[bytes_read], "%2" SCNx32, &checksum); - - if ((uint8_t)checksum != (uint8_t)(~cal_checksum + 1)) { - /* checksum failed */ - LOG_ERROR("incorrect record checksum found in IHEX file"); - return ERROR_IMAGE_CHECKSUM; + if (end_rec) { + end_rec = false; + LOG_WARNING("continuing after end-of-file record: %.40s", lpszLine); + } } } - LOG_ERROR("premature end of IHEX file, no end-of-file record found"); - return ERROR_IMAGE_FORMAT_ERROR; + if (end_rec) + return ERROR_OK; + else { + LOG_ERROR("premature end of IHEX file, no matching end-of-file record found"); + return ERROR_IMAGE_FORMAT_ERROR; + } } /** @@ -510,8 +526,9 @@ static int image_mot_buffer_complete_inner(struct image *image, { struct image_mot *mot = image->type_private; struct fileio *fileio = mot->fileio; - uint32_t full_address = 0x0; + uint32_t full_address; uint32_t cooked_bytes; + bool end_rec = false; int i; /* we can't determine the number of sections that we'll have to create ahead of time, @@ -526,140 +543,158 @@ static int image_mot_buffer_complete_inner(struct image *image, mot->buffer = malloc(filesize >> 1); cooked_bytes = 0x0; image->num_sections = 0; - section[image->num_sections].private = &mot->buffer[cooked_bytes]; - section[image->num_sections].base_address = 0x0; - section[image->num_sections].size = 0x0; - section[image->num_sections].flags = 0; - while (fileio_fgets(fileio, 1023, lpszLine) == ERROR_OK) { - uint32_t count; - uint32_t address; - uint32_t record_type; - uint32_t checksum; - uint8_t cal_checksum = 0; - uint32_t bytes_read = 0; + while (!fileio_feof(fileio)) { + full_address = 0x0; + section[image->num_sections].private = &mot->buffer[cooked_bytes]; + section[image->num_sections].base_address = 0x0; + section[image->num_sections].size = 0x0; + section[image->num_sections].flags = 0; - /* get record type and record length */ - if (sscanf(&lpszLine[bytes_read], "S%1" SCNx32 "%2" SCNx32, &record_type, - &count) != 2) - return ERROR_IMAGE_FORMAT_ERROR; + while (fileio_fgets(fileio, 1023, lpszLine) == ERROR_OK) { + uint32_t count; + uint32_t address; + uint32_t record_type; + uint32_t checksum; + uint8_t cal_checksum = 0; + uint32_t bytes_read = 0; - bytes_read += 4; - cal_checksum += (uint8_t)count; + /* skip comments and blank lines */ + if ((lpszLine[0] == '#') || (strlen(lpszLine + strspn(lpszLine, "\n\t\r ")) == 0)) + continue; - /* skip checksum byte */ - count -= 1; + /* get record type and record length */ + if (sscanf(&lpszLine[bytes_read], "S%1" SCNx32 "%2" SCNx32, &record_type, + &count) != 2) + return ERROR_IMAGE_FORMAT_ERROR; - if (record_type == 0) { - /* S0 - starting record (optional) */ - int iValue; + bytes_read += 4; + cal_checksum += (uint8_t)count; - while (count-- > 0) { - sscanf(&lpszLine[bytes_read], "%2x", &iValue); - cal_checksum += (uint8_t)iValue; - bytes_read += 2; - } - } else if (record_type >= 1 && record_type <= 3) { - switch (record_type) { - case 1: - /* S1 - 16 bit address data record */ - sscanf(&lpszLine[bytes_read], "%4" SCNx32, &address); - cal_checksum += (uint8_t)(address >> 8); - cal_checksum += (uint8_t)address; - bytes_read += 4; - count -= 2; - break; + /* skip checksum byte */ + count -= 1; - case 2: - /* S2 - 24 bit address data record */ - sscanf(&lpszLine[bytes_read], "%6" SCNx32, &address); - cal_checksum += (uint8_t)(address >> 16); - cal_checksum += (uint8_t)(address >> 8); - cal_checksum += (uint8_t)address; - bytes_read += 6; - count -= 3; - break; + if (record_type == 0) { + /* S0 - starting record (optional) */ + int iValue; - case 3: - /* S3 - 32 bit address data record */ - sscanf(&lpszLine[bytes_read], "%8" SCNx32, &address); - cal_checksum += (uint8_t)(address >> 24); - cal_checksum += (uint8_t)(address >> 16); - cal_checksum += (uint8_t)(address >> 8); - cal_checksum += (uint8_t)address; - bytes_read += 8; - count -= 4; - break; - - } - - if (full_address != address) { - /* we encountered a nonconsecutive location, create a new section, - * unless the current section has zero size, in which case this specifies - * the current section's base address - */ - if (section[image->num_sections].size != 0) { - image->num_sections++; - section[image->num_sections].size = 0x0; - section[image->num_sections].flags = 0; - section[image->num_sections].private = - &mot->buffer[cooked_bytes]; + while (count-- > 0) { + sscanf(&lpszLine[bytes_read], "%2x", &iValue); + cal_checksum += (uint8_t)iValue; + bytes_read += 2; } - section[image->num_sections].base_address = address; - full_address = address; + } else if (record_type >= 1 && record_type <= 3) { + switch (record_type) { + case 1: + /* S1 - 16 bit address data record */ + sscanf(&lpszLine[bytes_read], "%4" SCNx32, &address); + cal_checksum += (uint8_t)(address >> 8); + cal_checksum += (uint8_t)address; + bytes_read += 4; + count -= 2; + break; + + case 2: + /* S2 - 24 bit address data record */ + sscanf(&lpszLine[bytes_read], "%6" SCNx32, &address); + cal_checksum += (uint8_t)(address >> 16); + cal_checksum += (uint8_t)(address >> 8); + cal_checksum += (uint8_t)address; + bytes_read += 6; + count -= 3; + break; + + case 3: + /* S3 - 32 bit address data record */ + sscanf(&lpszLine[bytes_read], "%8" SCNx32, &address); + cal_checksum += (uint8_t)(address >> 24); + cal_checksum += (uint8_t)(address >> 16); + cal_checksum += (uint8_t)(address >> 8); + cal_checksum += (uint8_t)address; + bytes_read += 8; + count -= 4; + break; + + } + + if (full_address != address) { + /* we encountered a nonconsecutive location, create a new section, + * unless the current section has zero size, in which case this specifies + * the current section's base address + */ + if (section[image->num_sections].size != 0) { + image->num_sections++; + section[image->num_sections].size = 0x0; + section[image->num_sections].flags = 0; + section[image->num_sections].private = + &mot->buffer[cooked_bytes]; + } + section[image->num_sections].base_address = address; + full_address = address; + } + + while (count-- > 0) { + unsigned value; + sscanf(&lpszLine[bytes_read], "%2x", &value); + mot->buffer[cooked_bytes] = (uint8_t)value; + cal_checksum += (uint8_t)mot->buffer[cooked_bytes]; + bytes_read += 2; + cooked_bytes += 1; + section[image->num_sections].size += 1; + full_address++; + } + } else if (record_type == 5) { + /* S5 is the data count record, we ignore it */ + uint32_t dummy; + + while (count-- > 0) { + sscanf(&lpszLine[bytes_read], "%2" SCNx32, &dummy); + cal_checksum += (uint8_t)dummy; + bytes_read += 2; + } + } else if (record_type >= 7 && record_type <= 9) { + /* S7, S8, S9 - ending records for 32, 24 and 16bit */ + image->num_sections++; + + /* copy section information */ + image->sections = malloc(sizeof(struct imagesection) * image->num_sections); + for (i = 0; i < image->num_sections; i++) { + image->sections[i].private = section[i].private; + image->sections[i].base_address = section[i].base_address; + image->sections[i].size = section[i].size; + image->sections[i].flags = section[i].flags; + } + + end_rec = true; + break; + } else { + LOG_ERROR("unhandled S19 record type: %i", (int)(record_type)); + return ERROR_IMAGE_FORMAT_ERROR; } - while (count-- > 0) { - unsigned value; - sscanf(&lpszLine[bytes_read], "%2x", &value); - mot->buffer[cooked_bytes] = (uint8_t)value; - cal_checksum += (uint8_t)mot->buffer[cooked_bytes]; - bytes_read += 2; - cooked_bytes += 1; - section[image->num_sections].size += 1; - full_address++; - } - } else if (record_type == 5) { - /* S5 is the data count record, we ignore it */ - uint32_t dummy; + /* account for checksum, will always be 0xFF */ + sscanf(&lpszLine[bytes_read], "%2" SCNx32, &checksum); + cal_checksum += (uint8_t)checksum; - while (count-- > 0) { - sscanf(&lpszLine[bytes_read], "%2" SCNx32, &dummy); - cal_checksum += (uint8_t)dummy; - bytes_read += 2; - } - } else if (record_type >= 7 && record_type <= 9) { - /* S7, S8, S9 - ending records for 32, 24 and 16bit */ - image->num_sections++; - - /* copy section information */ - image->sections = malloc(sizeof(struct imagesection) * image->num_sections); - for (i = 0; i < image->num_sections; i++) { - image->sections[i].private = section[i].private; - image->sections[i].base_address = section[i].base_address; - image->sections[i].size = section[i].size; - image->sections[i].flags = section[i].flags; + if (cal_checksum != 0xFF) { + /* checksum failed */ + LOG_ERROR("incorrect record checksum found in S19 file"); + return ERROR_IMAGE_CHECKSUM; } - return ERROR_OK; - } else { - LOG_ERROR("unhandled S19 record type: %i", (int)(record_type)); - return ERROR_IMAGE_FORMAT_ERROR; - } - - /* account for checksum, will always be 0xFF */ - sscanf(&lpszLine[bytes_read], "%2" SCNx32, &checksum); - cal_checksum += (uint8_t)checksum; - - if (cal_checksum != 0xFF) { - /* checksum failed */ - LOG_ERROR("incorrect record checksum found in S19 file"); - return ERROR_IMAGE_CHECKSUM; + if (end_rec) { + end_rec = false; + LOG_WARNING("continuing after end-of-file record: %.40s", lpszLine); + } } } - LOG_ERROR("premature end of S19 file, no end-of-file record found"); - return ERROR_IMAGE_FORMAT_ERROR; + if (end_rec) + return ERROR_OK; + else { + LOG_ERROR("premature end of S19 file, no matching end-of-file record found"); + return ERROR_IMAGE_FORMAT_ERROR; + } } /** diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index 7d1c06cf0..78718ca16 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -702,7 +702,7 @@ static int mips_m4k_set_breakpoint(struct target *target, } if (verify == 0) { - LOG_ERROR("Unable to set 32bit breakpoint at address %08" PRIx64 + LOG_ERROR("Unable to set 32bit breakpoint at address %08" TARGET_PRIxADDR " - check that memory is read/writable", breakpoint->address); return ERROR_OK; } @@ -723,7 +723,7 @@ static int mips_m4k_set_breakpoint(struct target *target, return retval; if (verify != MIPS16_SDBBP(isa_req)) { - LOG_ERROR("Unable to set 16bit breakpoint at address %08" PRIx64 + LOG_ERROR("Unable to set 16bit breakpoint at address %08" TARGET_PRIxADDR " - check that memory is read/writable", breakpoint->address); return ERROR_OK; } diff --git a/src/target/openrisc/jsp_server.c b/src/target/openrisc/jsp_server.c index 2d90114fa..6cd53f43c 100644 --- a/src/target/openrisc/jsp_server.c +++ b/src/target/openrisc/jsp_server.c @@ -242,3 +242,7 @@ int jsp_register_commands(struct command_context *cmd_ctx) return register_commands(cmd_ctx, NULL, jsp_command_handlers); } +void jsp_service_free(void) +{ + free(jsp_port); +} diff --git a/src/target/openrisc/jsp_server.h b/src/target/openrisc/jsp_server.h index f8e71215a..e5cfaa8b4 100644 --- a/src/target/openrisc/jsp_server.h +++ b/src/target/openrisc/jsp_server.h @@ -13,5 +13,6 @@ struct jsp_service { int jsp_init(struct or1k_jtag *jtag_info, char *banner); int jsp_register_commands(struct command_context *cmd_ctx); +void jsp_service_free(void); #endif /* OPENOCD_TARGET_OPENRISC_JSP_SERVER_H */ diff --git a/src/target/register.h b/src/target/register.h index dc18e9a89..32c1f39ac 100644 --- a/src/target/register.h +++ b/src/target/register.h @@ -25,12 +25,14 @@ struct target; enum reg_type { + REG_TYPE_BOOL, REG_TYPE_INT, REG_TYPE_INT8, REG_TYPE_INT16, REG_TYPE_INT32, REG_TYPE_INT64, REG_TYPE_INT128, + REG_TYPE_UINT, REG_TYPE_UINT8, REG_TYPE_UINT16, REG_TYPE_UINT32, @@ -66,6 +68,7 @@ struct reg_data_type_union { struct reg_data_type_bitfield { uint32_t start; uint32_t end; + enum reg_type type; }; struct reg_data_type_struct_field { diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index 25a06760c..5e899b252 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -64,7 +64,7 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) return ERROR_FAIL; if (riscv_execute_debug_buffer(t) != ERROR_OK) { - LOG_ERROR("Unable to execute program %p", p); + LOG_DEBUG("Unable to execute program %p", p); return ERROR_FAIL; } diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index 632567f35..b450d2b0f 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -1572,11 +1572,11 @@ static int examine(struct target *target) } LOG_DEBUG("Discovered XLEN is %d", riscv_xlen(target)); - if (read_csr(target, &r->misa, CSR_MISA) != ERROR_OK) { + if (read_csr(target, &r->misa[0], CSR_MISA) != ERROR_OK) { const unsigned old_csr_misa = 0xf10; LOG_WARNING("Failed to read misa at 0x%x; trying 0x%x.", CSR_MISA, old_csr_misa); - if (read_csr(target, &r->misa, old_csr_misa) != ERROR_OK) { + if (read_csr(target, &r->misa[0], old_csr_misa) != ERROR_OK) { /* Maybe this is an old core that still has $misa at the old * address. */ LOG_ERROR("Failed to read misa at 0x%x.", old_csr_misa); @@ -1598,7 +1598,7 @@ static int examine(struct target *target) for (size_t i = 0; i < 32; ++i) reg_cache_set(target, i, -1); LOG_INFO("Examined RISCV core; XLEN=%d, misa=0x%" PRIx64, - riscv_xlen(target), r->misa); + riscv_xlen(target), r->misa[0]); return ERROR_OK; } diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 0879d51e6..8b16a4e97 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -19,6 +19,7 @@ #include "target/register.h" #include "target/breakpoints.h" #include "helper/time_support.h" +#include "helper/list.h" #include "riscv.h" #include "rtos/riscv_debug.h" #include "debug_defines.h" @@ -136,6 +137,20 @@ typedef enum { YNM_NO } yes_no_maybe_t; +typedef struct { + struct list_head list; + int abs_chain_position; + /* Indicates we already reset this DM, so don't need to do it again. */ + bool was_reset; + /* Targets that are connected to this DM. */ + struct list_head target_list; +} dm013_info_t; + +typedef struct { + struct list_head list; + struct target *target; +} target_list_t; + typedef struct { /* Number of address bits in the dbus register. */ unsigned abits; @@ -144,6 +159,9 @@ typedef struct { /* Number of words in the Program Buffer. */ unsigned progbufsize; + /* We cache the read-only bits of sbcs here. */ + uint32_t sbcs; + yes_no_maybe_t progbuf_writable; /* We only need the address so that we know the alignment of the buffer. */ riscv_addr_t progbuf_address; @@ -157,6 +175,10 @@ typedef struct { * in between accesses. */ unsigned int dmi_busy_delay; + /* Number of run-test/idle cycles to add between consecutive bus master + * reads/writes respectively. */ + unsigned int bus_master_write_delay, bus_master_read_delay; + /* This value is increased every time we tried to execute two commands * consecutively, and the second one failed because the previous hadn't * completed yet. It's used to add extra run-test/idle cycles after @@ -183,14 +205,62 @@ typedef struct { /* The width of the hartsel field. */ unsigned hartsellen; + + /* DM that provides access to this target. */ + dm013_info_t *dm; } riscv013_info_t; +LIST_HEAD(dm_list); + static riscv013_info_t *get_info(const struct target *target) { riscv_info_t *info = (riscv_info_t *) target->arch_info; return (riscv013_info_t *) info->version_specific; } +/** + * Return the DM structure for this target. If there isn't one, find it in the + * global list of DMs. If it's not in there, then create one and initialize it + * to 0. + */ +static dm013_info_t *get_dm(struct target *target) +{ + RISCV013_INFO(info); + if (info->dm) + return info->dm; + + int abs_chain_position = target->tap->abs_chain_position; + + dm013_info_t *entry; + dm013_info_t *dm = NULL; + list_for_each_entry(entry, &dm_list, list) { + if (entry->abs_chain_position == abs_chain_position) { + dm = entry; + break; + } + } + + if (!dm) { + dm = calloc(1, sizeof(dm013_info_t)); + dm->abs_chain_position = abs_chain_position; + INIT_LIST_HEAD(&dm->target_list); + list_add(&dm->list, &dm_list); + } + + info->dm = dm; + target_list_t *target_entry; + list_for_each_entry(target_entry, &dm->target_list, list) { + if (target_entry->target == target) { + return dm; + } + } + target_entry = calloc(1, sizeof(*target_entry)); + target_entry->target = target; + list_add(&target_entry->list, &dm->target_list); + + return dm; +} + static uint32_t hartsel_mask(const struct target *target) { RISCV013_INFO(info); @@ -234,6 +304,18 @@ static void decode_dmi(char *text, unsigned address, unsigned data) { DMI_ABSTRACTCS, DMI_ABSTRACTCS_DATACOUNT, "datacount" }, { DMI_COMMAND, DMI_COMMAND_CMDTYPE, "cmdtype" }, + + { DMI_SBCS, DMI_SBCS_SBREADONADDR, "sbreadonaddr" }, + { DMI_SBCS, DMI_SBCS_SBACCESS, "sbaccess" }, + { DMI_SBCS, DMI_SBCS_SBAUTOINCREMENT, "sbautoincrement" }, + { DMI_SBCS, DMI_SBCS_SBREADONDATA, "sbreadondata" }, + { DMI_SBCS, DMI_SBCS_SBERROR, "sberror" }, + { DMI_SBCS, DMI_SBCS_SBASIZE, "sbasize" }, + { DMI_SBCS, DMI_SBCS_SBACCESS128, "sbaccess128" }, + { DMI_SBCS, DMI_SBCS_SBACCESS64, "sbaccess64" }, + { DMI_SBCS, DMI_SBCS_SBACCESS32, "sbaccess32" }, + { DMI_SBCS, DMI_SBCS_SBACCESS16, "sbaccess16" }, + { DMI_SBCS, DMI_SBCS_SBACCESS8, "sbaccess8" }, }; text[0] = 0; @@ -352,8 +434,8 @@ static void increase_dmi_busy_delay(struct target *target) * exec: If this is set, assume the scan results in an execution, so more * run-test/idle cycles may be required. */ -static dmi_status_t dmi_scan(struct target *target, uint16_t *address_in, - uint32_t *data_in, dmi_op_t op, uint16_t address_out, uint32_t data_out, +static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, + uint32_t *data_in, dmi_op_t op, uint32_t address_out, uint32_t data_out, bool exec) { riscv013_info_t *info = get_info(target); @@ -402,12 +484,12 @@ static dmi_status_t dmi_scan(struct target *target, uint16_t *address_in, return buf_get_u32(in, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); } -static uint32_t dmi_read(struct target *target, uint16_t address) +static int dmi_read(struct target *target, uint32_t *value, uint32_t address) { select_dmi(target); dmi_status_t status; - uint16_t address_in; + uint32_t address_in; unsigned i = 0; @@ -422,31 +504,22 @@ static uint32_t dmi_read(struct target *target, uint16_t address) } else if (status == DMI_STATUS_SUCCESS) { break; } else { - static int once = 1; - if (once) { - LOG_ERROR("failed read from 0x%x, status=%d", address, status); - once = 0; - } - break; + LOG_ERROR("failed read from 0x%x, status=%d", address, status); + return ERROR_FAIL; } usleep(100000); } if (status != DMI_STATUS_SUCCESS) { - static int once = 1; - if (once) { - LOG_INFO("Failed read from 0x%x; status=%d", address, status); - once = 0; - } - return ~0; + LOG_ERROR("Failed read from 0x%x; status=%d", address, status); + return ERROR_FAIL; } /* This second loop ensures that we got the read * data back. Note that NOP can result in a 'busy' result as well, but * that would be noticed on the next DMI access we do. */ - uint32_t value; for (i = 0; i < 256; i++) { - status = dmi_scan(target, &address_in, &value, DMI_OP_NOP, address, 0, + status = dmi_scan(target, &address_in, value, DMI_OP_NOP, address, 0, false); if (status == DMI_STATUS_BUSY) { increase_dmi_busy_delay(target); @@ -454,7 +527,7 @@ static uint32_t dmi_read(struct target *target, uint16_t address) break; } else { LOG_ERROR("failed read (NOP) at 0x%x, status=%d", address, status); - break; + return ERROR_FAIL; } } @@ -463,15 +536,15 @@ static uint32_t dmi_read(struct target *target, uint16_t address) LOG_ERROR("Failed read (NOP) from 0x%x; status=%d", address, status); } else { LOG_ERROR("Failed read (NOP) from 0x%x; value=0x%x, status=%d", - address, value, status); + address, *value, status); } - return ~0; + return ERROR_FAIL; } - return value; + return ERROR_OK; } -static int dmi_write(struct target *target, uint16_t address, uint64_t value) +static int dmi_write(struct target *target, uint32_t address, uint32_t value) { select_dmi(target); dmi_status_t status = DMI_STATUS_BUSY; @@ -513,13 +586,27 @@ static int dmi_write(struct target *target, uint16_t address, uint64_t value) } } if (status != DMI_STATUS_SUCCESS) { - LOG_ERROR("failed to write (NOP) 0x%" PRIx64 " to 0x%x; status=%d", value, address, status); + LOG_ERROR("failed to write (NOP) 0x%x to 0x%x; status=%d", value, address, status); return ERROR_FAIL; } return ERROR_OK; } +int dmstatus_read(struct target *target, uint32_t *dmstatus, + bool authenticated) +{ + if (dmi_read(target, dmstatus, DMI_DMSTATUS) != ERROR_OK) + return ERROR_FAIL; + if (authenticated && !get_field(*dmstatus, DMI_DMSTATUS_AUTHENTICATED)) { + LOG_ERROR("Debugger is not authenticated to target Debug Module. " + "(dmstatus=0x%x). Use `riscv authdata_read` and " + "`riscv authdata_write` commands to authenticate.", *dmstatus); + return ERROR_FAIL; + } + return ERROR_OK; +} + static void increase_ac_busy_delay(struct target *target) { riscv013_info_t *info = get_info(target); @@ -551,7 +638,8 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs) RISCV013_INFO(info); time_t start = time(NULL); while (1) { - *abstractcs = dmi_read(target, DMI_ABSTRACTCS); + if (dmi_read(target, abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; if (get_field(*abstractcs, DMI_ABSTRACTCS_BUSY) == 0) return ERROR_OK; @@ -593,7 +681,9 @@ static int execute_abstract_command(struct target *target, uint32_t command) wait_for_idle(target, &abstractcs); } - uint32_t cs = dmi_read(target, DMI_ABSTRACTCS); + uint32_t cs; + if (dmi_read(target, &cs, DMI_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; info->cmderr = get_field(cs, DMI_ABSTRACTCS_CMDERR); if (info->cmderr != 0) { LOG_DEBUG("command 0x%x failed; abstractcs=0x%x", command, cs); @@ -606,34 +696,38 @@ static int execute_abstract_command(struct target *target, uint32_t command) return ERROR_OK; } -static riscv_reg_t read_abstract_arg(struct target *target, unsigned index) +static riscv_reg_t read_abstract_arg(struct target *target, unsigned index, + unsigned size_bits) { riscv_reg_t value = 0; - unsigned xlen = riscv_xlen(target); - unsigned offset = index * xlen / 32; - switch (xlen) { + uint32_t v; + unsigned offset = index * size_bits / 32; + switch (size_bits) { default: - LOG_ERROR("Unsupported xlen: %d", xlen); + LOG_ERROR("Unsupported size: %d", size_bits); return ~0; case 64: - value |= ((uint64_t) dmi_read(target, DMI_DATA0 + offset + 1)) << 32; + dmi_read(target, &v, DMI_DATA0 + offset + 1); + value |= ((uint64_t) v) << 32; + /* falls through */ case 32: - value |= dmi_read(target, DMI_DATA0 + offset); + dmi_read(target, &v, DMI_DATA0 + offset); + value |= v; } return value; } static int write_abstract_arg(struct target *target, unsigned index, - riscv_reg_t value) + riscv_reg_t value, unsigned size_bits) { - unsigned xlen = riscv_xlen(target); - unsigned offset = index * xlen / 32; - switch (xlen) { + unsigned offset = index * size_bits / 32; + switch (size_bits) { default: - LOG_ERROR("Unsupported xlen: %d", xlen); - return ~0; + LOG_ERROR("Unsupported size: %d", size_bits); + return ERROR_FAIL; case 64: dmi_write(target, DMI_DATA0 + offset + 1, value >> 32); + /* falls through */ case 32: dmi_write(target, DMI_DATA0 + offset, value); } @@ -706,7 +800,7 @@ static int register_read_abstract(struct target *target, uint64_t *value, } if (value) - *value = read_abstract_arg(target, 0); + *value = read_abstract_arg(target, 0, size); return ERROR_OK; } @@ -727,7 +821,7 @@ static int register_write_abstract(struct target *target, uint32_t number, AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_WRITE); - if (write_abstract_arg(target, 0, value) != ERROR_OK) + if (write_abstract_arg(target, 0, value, size) != ERROR_OK) return ERROR_FAIL; int result = execute_abstract_command(target, command); @@ -789,14 +883,16 @@ static int examine_progbuf(struct target *target) return ERROR_OK; } - uint32_t written = dmi_read(target, DMI_PROGBUF0); + uint32_t written; + if (dmi_read(target, &written, DMI_PROGBUF0) != ERROR_OK) + return ERROR_FAIL; if (written == (uint32_t) info->progbuf_address) { - LOG_INFO("progbuf is writable at 0x%" TARGET_PRIxADDR, + LOG_INFO("progbuf is writable at 0x%" PRIx64, info->progbuf_address); info->progbuf_writable = YNM_YES; } else { - LOG_INFO("progbuf is not writeable at 0x%" TARGET_PRIxADDR, + LOG_INFO("progbuf is not writeable at 0x%" PRIx64, info->progbuf_address); info->progbuf_writable = YNM_NO; } @@ -879,16 +975,23 @@ static int scratch_find(struct target *target, static int scratch_read64(struct target *target, scratch_mem_t *scratch, uint64_t *value) { + uint32_t v; switch (scratch->memory_space) { case SPACE_DMI_DATA: - *value = dmi_read(target, DMI_DATA0 + scratch->debug_address); - *value |= ((uint64_t) dmi_read(target, DMI_DATA1 + - scratch->debug_address)) << 32; + if (dmi_read(target, &v, DMI_DATA0 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value = v; + if (dmi_read(target, &v, DMI_DATA1 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value |= ((uint64_t) v) << 32; break; case SPACE_DMI_PROGBUF: - *value = dmi_read(target, DMI_PROGBUF0 + scratch->debug_address); - *value |= ((uint64_t) dmi_read(target, DMI_PROGBUF1 + - scratch->debug_address)) << 32; + if (dmi_read(target, &v, DMI_PROGBUF0 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value = v; + if (dmi_read(target, &v, DMI_PROGBUF1 + scratch->debug_address) != ERROR_OK) + return ERROR_FAIL; + *value |= ((uint64_t) v) << 32; break; case SPACE_DMI_RAM: { @@ -941,16 +1044,31 @@ static int scratch_write64(struct target *target, scratch_mem_t *scratch, return ERROR_OK; } +/** Return register size in bits. */ +static unsigned register_size(struct target *target, unsigned number) +{ + /* If reg_cache hasn't been initialized yet, make a guess. We need this for + * when this function is called during examine(). */ + if (target->reg_cache) + return target->reg_cache->reg_list[number].size; + else + return riscv_xlen(target); +} + static int register_write_direct(struct target *target, unsigned number, uint64_t value) { + RISCV013_INFO(info); + RISCV_INFO(r); + LOG_DEBUG("[%d] reg[0x%x] <- 0x%" PRIx64, riscv_current_hartid(target), number, value); int result = register_write_abstract(target, number, value, - riscv_xlen(target)); - if (result == ERROR_OK) - return ERROR_OK; + register_size(target, number)); + if (result == ERROR_OK || info->progbufsize + r->impebreak < 2 || + !riscv_is_halted(target)) + return result; struct riscv_program program; riscv_program_init(&program, target); @@ -960,7 +1078,7 @@ static int register_write_direct(struct target *target, unsigned number, return ERROR_FAIL; if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && - riscv_supports_extension(target, 'D') && + riscv_supports_extension(target, riscv_current_hartid(target), 'D') && riscv_xlen(target) < 64) { /* There are no instructions to move all the bits from a register, so * we need to use some scratch RAM. */ @@ -982,7 +1100,7 @@ static int register_write_direct(struct target *target, unsigned number, return ERROR_FAIL; if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - if (riscv_supports_extension(target, 'D')) + if (riscv_supports_extension(target, riscv_current_hartid(target), 'D')) riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); else riscv_program_insert(&program, fmv_w_x(number - GDB_REGNO_FPR0, S0)); @@ -995,6 +1113,7 @@ static int register_write_direct(struct target *target, unsigned number, } int exec_out = riscv_program_exec(&program, target); + /* Don't message on error. Probably the register doesn't exist. */ /* Restore S0. */ if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) @@ -1006,10 +1125,14 @@ static int register_write_direct(struct target *target, unsigned number, /** Actually read registers from the target right now. */ static int register_read_direct(struct target *target, uint64_t *value, uint32_t number) { - int result = register_read_abstract(target, value, number, - riscv_xlen(target)); + RISCV013_INFO(info); + RISCV_INFO(r); - if (result != ERROR_OK) { + int result = register_read_abstract(target, value, number, + register_size(target, number)); + + if (result != ERROR_OK && info->progbufsize + r->impebreak >= 2 && + riscv_is_halted(target)) { assert(number != GDB_REGNO_S0); struct riscv_program program; @@ -1033,7 +1156,8 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t set_field(mstatus, MSTATUS_FS, 1)) != ERROR_OK) return ERROR_FAIL; - if (riscv_supports_extension(target, 'D') && riscv_xlen(target) < 64) { + if (riscv_supports_extension(target, riscv_current_hartid(target), 'D') + && riscv_xlen(target) < 64) { /* There are no instructions to move all the bits from a * register, so we need to use some scratch RAM. */ riscv_program_insert(&program, fsd(number - GDB_REGNO_FPR0, S0, @@ -1046,7 +1170,8 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t if (register_write_direct(target, GDB_REGNO_S0, scratch.hart_address) != ERROR_OK) return ERROR_FAIL; - } else if (riscv_supports_extension(target, 'D')) { + } else if (riscv_supports_extension(target, + riscv_current_hartid(target), 'D')) { riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)); } else { riscv_program_insert(&program, fmv_x_w(S0, number - GDB_REGNO_FPR0)); @@ -1060,6 +1185,7 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t /* Execute program. */ result = riscv_program_exec(&program, target); + /* Don't message on error. Probably the register doesn't exist. */ if (use_scratch) { if (scratch_read64(target, &scratch, value) != ERROR_OK) @@ -1088,56 +1214,31 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t return result; } -/*** OpenOCD target functions. ***/ - -static int init_target(struct command_context *cmd_ctx, - struct target *target) +int wait_for_authbusy(struct target *target, uint32_t *dmstatus) { - LOG_DEBUG("init"); - riscv_info_t *generic_info = (riscv_info_t *) target->arch_info; - - generic_info->get_register = &riscv013_get_register; - generic_info->set_register = &riscv013_set_register; - generic_info->select_current_hart = &riscv013_select_current_hart; - generic_info->is_halted = &riscv013_is_halted; - generic_info->halt_current_hart = &riscv013_halt_current_hart; - generic_info->resume_current_hart = &riscv013_resume_current_hart; - generic_info->step_current_hart = &riscv013_step_current_hart; - generic_info->on_halt = &riscv013_on_halt; - generic_info->on_resume = &riscv013_on_resume; - generic_info->on_step = &riscv013_on_step; - generic_info->halt_reason = &riscv013_halt_reason; - generic_info->read_debug_buffer = &riscv013_read_debug_buffer; - generic_info->write_debug_buffer = &riscv013_write_debug_buffer; - generic_info->execute_debug_buffer = &riscv013_execute_debug_buffer; - generic_info->fill_dmi_write_u64 = &riscv013_fill_dmi_write_u64; - generic_info->fill_dmi_read_u64 = &riscv013_fill_dmi_read_u64; - generic_info->fill_dmi_nop_u64 = &riscv013_fill_dmi_nop_u64; - generic_info->dmi_write_u64_bits = &riscv013_dmi_write_u64_bits; - generic_info->test_compliance = &riscv013_test_compliance; - generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); - if (!generic_info->version_specific) - return ERROR_FAIL; - riscv013_info_t *info = get_info(target); - - info->progbufsize = -1; - - info->dmi_busy_delay = 0; - info->ac_busy_delay = 0; - - /* Assume all these abstract commands are supported until we learn - * otherwise. - * TODO: The spec allows eg. one CSR to be able to be accessed abstractly - * while another one isn't. We don't track that this closely here, but in - * the future we probably should. */ - info->abstract_read_csr_supported = true; - info->abstract_write_csr_supported = true; - info->abstract_read_fpr_supported = true; - info->abstract_write_fpr_supported = true; + time_t start = time(NULL); + while (1) { + uint32_t value; + if (dmstatus_read(target, &value, false) != ERROR_OK) + return ERROR_FAIL; + if (dmstatus) + *dmstatus = value; + if (!get_field(value, DMI_DMSTATUS_AUTHBUSY)) + break; + if (time(NULL) - start > riscv_command_timeout_sec) { + LOG_ERROR("Timed out after %ds waiting for authbusy to go low (dmstatus=0x%x). " + "Increase the timeout with riscv set_command_timeout_sec.", + riscv_command_timeout_sec, + value); + return ERROR_FAIL; + } + } return ERROR_OK; } +/*** OpenOCD target functions. ***/ + static void deinit_target(struct target *target) { LOG_DEBUG("riscv_deinit_target()"); @@ -1171,7 +1272,10 @@ static int examine(struct target *target) info->abits = get_field(dtmcontrol, DTM_DTMCS_ABITS); info->dtmcontrol_idle = get_field(dtmcontrol, DTM_DTMCS_IDLE); - uint32_t dmstatus = dmi_read(target, DMI_DMSTATUS); + uint32_t dmstatus; + if (dmstatus_read(target, &dmstatus, false) != ERROR_OK) + return ERROR_FAIL; + LOG_DEBUG("dmstatus: 0x%08x", dmstatus); if (get_field(dmstatus, DMI_DMSTATUS_VERSION) != 2) { LOG_ERROR("OpenOCD only supports Debug Module version 2, not %d " "(dmstatus=0x%x)", get_field(dmstatus, DMI_DMSTATUS_VERSION), dmstatus); @@ -1179,12 +1283,18 @@ static int examine(struct target *target) } /* Reset the Debug Module. */ - dmi_write(target, DMI_DMCONTROL, 0); - dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE); + dm013_info_t *dm = get_dm(target); + if (!dm->was_reset) { + dmi_write(target, DMI_DMCONTROL, 0); + dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE); + dm->was_reset = true; + } uint32_t max_hartsel_mask = ((1L<<10)-1) << DMI_DMCONTROL_HARTSEL_OFFSET; dmi_write(target, DMI_DMCONTROL, max_hartsel_mask | DMI_DMCONTROL_DMACTIVE); - uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); + uint32_t dmcontrol; + if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; if (!get_field(dmcontrol, DMI_DMCONTROL_DMACTIVE)) { LOG_ERROR("Debug Module did not become active. dmcontrol=0x%x", @@ -1200,26 +1310,47 @@ static int examine(struct target *target) } LOG_DEBUG("hartsellen=%d", info->hartsellen); - uint32_t hartinfo = dmi_read(target, DMI_HARTINFO); + uint32_t hartinfo; + if (dmi_read(target, &hartinfo, DMI_HARTINFO) != ERROR_OK) + return ERROR_FAIL; info->datasize = get_field(hartinfo, DMI_HARTINFO_DATASIZE); info->dataaccess = get_field(hartinfo, DMI_HARTINFO_DATAACCESS); info->dataaddr = get_field(hartinfo, DMI_HARTINFO_DATAADDR); if (!get_field(dmstatus, DMI_DMSTATUS_AUTHENTICATED)) { - LOG_ERROR("Authentication required by RISC-V core but not " - "supported by OpenOCD. dmcontrol=0x%x", dmcontrol); - return ERROR_FAIL; + LOG_ERROR("Debugger is not authenticated to target Debug Module. " + "(dmstatus=0x%x). Use `riscv authdata_read` and " + "`riscv authdata_write` commands to authenticate.", dmstatus); + /* If we return ERROR_FAIL here, then in a multicore setup the next + * core won't be examined, which means we won't set up the + * authentication commands for them, which means the config script + * needs to be a lot more complex. */ + return ERROR_OK; } + if (dmi_read(target, &info->sbcs, DMI_SBCS) != ERROR_OK) + return ERROR_FAIL; + /* Check that abstract data registers are accessible. */ - uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); + uint32_t abstractcs; + if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; info->datacount = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); info->progbufsize = get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); + LOG_INFO("datacount=%d progbufsize=%d", info->datacount, info->progbufsize); + RISCV_INFO(r); r->impebreak = get_field(dmstatus, DMI_DMSTATUS_IMPEBREAK); + if (info->progbufsize + r->impebreak < 2) { + LOG_WARNING("We won't be able to execute fence instructions on this " + "target. Memory may not always appear consistent. " + "(progbufsize=%d, impebreak=%d)", info->progbufsize, + r->impebreak); + } + /* Before doing anything else we must first enumerate the harts. */ /* Don't call any riscv_* functions until after we've counted the number of @@ -1231,7 +1362,9 @@ static int examine(struct target *target) r->current_hartid = i; riscv013_select_current_hart(target); - uint32_t s = dmi_read(target, DMI_DMSTATUS); + uint32_t s; + if (dmstatus_read(target, &s, true) != ERROR_OK) + return ERROR_FAIL; if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT)) break; r->hart_count = i + 1; @@ -1253,7 +1386,7 @@ static int examine(struct target *target) else r->xlen[i] = 32; - if (register_read_direct(target, &r->misa, GDB_REGNO_MISA)) { + if (register_read_direct(target, &r->misa[i], GDB_REGNO_MISA)) { LOG_ERROR("Fatal: Failed to read MISA from hart %d.", i); return ERROR_FAIL; } @@ -1265,7 +1398,7 @@ static int examine(struct target *target) /* Display this as early as possible to help people who are using * really slow simulators. */ LOG_DEBUG(" hart %d: XLEN=%d, misa=0x%" PRIx64, i, r->xlen[i], - r->misa); + r->misa[i]); } LOG_DEBUG("Enumerated %d harts", r->hart_count); @@ -1295,8 +1428,8 @@ static int examine(struct target *target) riscv_count_harts(target)); for (int i = 0; i < riscv_count_harts(target); ++i) { if (riscv_hart_enabled(target, i)) { - LOG_INFO(" hart %d: XLEN=%d, %d triggers", i, r->xlen[i], - r->trigger_count[i]); + LOG_INFO(" hart %d: XLEN=%d, misa=0x%" PRIx64 ", %d triggers", i, + r->xlen[i], r->misa[i], r->trigger_count[i]); } else { LOG_INFO(" hart %d: currently disabled", i); } @@ -1304,6 +1437,95 @@ static int examine(struct target *target) return ERROR_OK; } +int riscv013_authdata_read(struct target *target, uint32_t *value) +{ + if (wait_for_authbusy(target, NULL) != ERROR_OK) + return ERROR_FAIL; + + return dmi_read(target, value, DMI_AUTHDATA); +} + +int riscv013_authdata_write(struct target *target, uint32_t value) +{ + uint32_t before, after; + if (wait_for_authbusy(target, &before) != ERROR_OK) + return ERROR_FAIL; + + dmi_write(target, DMI_AUTHDATA, value); + + if (wait_for_authbusy(target, &after) != ERROR_OK) + return ERROR_FAIL; + + if (!get_field(before, DMI_DMSTATUS_AUTHENTICATED) && + get_field(after, DMI_DMSTATUS_AUTHENTICATED)) { + LOG_INFO("authdata_write resulted in successful authentication"); + int result = ERROR_OK; + dm013_info_t *dm = get_dm(target); + target_list_t *entry; + list_for_each_entry(entry, &dm->target_list, list) { + if (examine(entry->target) != ERROR_OK) + result = ERROR_FAIL; + } + return result; + } + + return ERROR_OK; +} + +static int init_target(struct command_context *cmd_ctx, + struct target *target) +{ + LOG_DEBUG("init"); + riscv_info_t *generic_info = (riscv_info_t *) target->arch_info; + + generic_info->get_register = &riscv013_get_register; + generic_info->set_register = &riscv013_set_register; + generic_info->select_current_hart = &riscv013_select_current_hart; + generic_info->is_halted = &riscv013_is_halted; + generic_info->halt_current_hart = &riscv013_halt_current_hart; + generic_info->resume_current_hart = &riscv013_resume_current_hart; + generic_info->step_current_hart = &riscv013_step_current_hart; + generic_info->on_halt = &riscv013_on_halt; + generic_info->on_resume = &riscv013_on_resume; + generic_info->on_step = &riscv013_on_step; + generic_info->halt_reason = &riscv013_halt_reason; + generic_info->read_debug_buffer = &riscv013_read_debug_buffer; + generic_info->write_debug_buffer = &riscv013_write_debug_buffer; + generic_info->execute_debug_buffer = &riscv013_execute_debug_buffer; + generic_info->fill_dmi_write_u64 = &riscv013_fill_dmi_write_u64; + generic_info->fill_dmi_read_u64 = &riscv013_fill_dmi_read_u64; + generic_info->fill_dmi_nop_u64 = &riscv013_fill_dmi_nop_u64; + generic_info->dmi_write_u64_bits = &riscv013_dmi_write_u64_bits; + generic_info->authdata_read = &riscv013_authdata_read; + generic_info->authdata_write = &riscv013_authdata_write; + generic_info->dmi_read = &dmi_read; + generic_info->dmi_write = &dmi_write; + generic_info->test_compliance = &riscv013_test_compliance; + generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); + if (!generic_info->version_specific) + return ERROR_FAIL; + riscv013_info_t *info = get_info(target); + + info->progbufsize = -1; + + info->dmi_busy_delay = 0; + info->bus_master_read_delay = 0; + info->bus_master_write_delay = 0; + info->ac_busy_delay = 0; + + /* Assume all these abstract commands are supported until we learn + * otherwise. + * TODO: The spec allows eg. one CSR to be able to be accessed abstractly + * while another one isn't. We don't track that this closely here, but in + * the future we probably should. */ + info->abstract_read_csr_supported = true; + info->abstract_write_csr_supported = true; + info->abstract_read_fpr_supported = true; + info->abstract_write_fpr_supported = true; + + return ERROR_OK; +} + static int assert_reset(struct target *target) { RISCV_INFO(r); @@ -1343,7 +1565,9 @@ static int assert_reset(struct target *target) dmi_write(target, DMI_DMCONTROL, control); /* Read back to check if hartreset is supported. */ - uint32_t rb = dmi_read(target, DMI_DMCONTROL); + uint32_t rb; + if (dmi_read(target, &rb, DMI_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; if (!get_field(rb, DMI_DMCONTROL_HARTRESET)) { /* Use ndmreset instead. That will reset the entire device, but * that's probably what OpenOCD wants anyway. */ @@ -1380,7 +1604,8 @@ static int deassert_reset(struct target *target) if (target->reset_halt) { LOG_DEBUG("Waiting for hart to be halted."); do { - dmstatus = dmi_read(target, DMI_DMSTATUS); + if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) + return ERROR_FAIL; if (time(NULL) - start > riscv_reset_timeout_sec) { LOG_ERROR("Hart didn't halt coming out of reset in %ds; " "dmstatus=0x%x; " @@ -1397,7 +1622,8 @@ static int deassert_reset(struct target *target) } else { LOG_DEBUG("Waiting for hart to be running."); do { - dmstatus = dmi_read(target, DMI_DMSTATUS); + if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) + return ERROR_FAIL; if (get_field(dmstatus, DMI_DMSTATUS_ANYHALTED) || get_field(dmstatus, DMI_DMSTATUS_ANYUNAVAIL)) { LOG_ERROR("Unexpected hart status during reset. dmstatus=0x%x", @@ -1429,11 +1655,14 @@ static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) buffer[6] = value >> 48; buffer[5] = value >> 40; buffer[4] = value >> 32; + /* falls through */ case 4: buffer[3] = value >> 24; buffer[2] = value >> 16; + /* falls through */ case 2: buffer[1] = value >> 8; + /* falls through */ case 1: buffer[0] = value; break; @@ -1466,11 +1695,256 @@ static void log_memory_access(target_addr_t address, uint64_t value, LOG_DEBUG(fmt, value); } +/* Read the relevant sbdata regs depending on size, and put the results into + * buffer. */ +static int read_memory_bus_word(struct target *target, target_addr_t address, + uint32_t size, uint8_t *buffer) +{ + uint32_t value; + if (size > 12) { + if (dmi_read(target, &value, DMI_SBDATA3) != ERROR_OK) + return ERROR_FAIL; + write_to_buf(buffer + 12, value, 4); + log_memory_access(address + 12, value, 4, true); + } + if (size > 8) { + if (dmi_read(target, &value, DMI_SBDATA2) != ERROR_OK) + return ERROR_FAIL; + write_to_buf(buffer + 8, value, 4); + log_memory_access(address + 8, value, 4, true); + } + if (size > 4) { + if (dmi_read(target, &value, DMI_SBDATA1) != ERROR_OK) + return ERROR_FAIL; + write_to_buf(buffer + 4, value, 4); + log_memory_access(address + 4, value, 4, true); + } + if (dmi_read(target, &value, DMI_SBDATA0) != ERROR_OK) + return ERROR_FAIL; + write_to_buf(buffer, value, MIN(size, 4)); + log_memory_access(address, value, MIN(size, 4), true); + return ERROR_OK; +} + +static uint32_t sb_sbaccess(unsigned size_bytes) +{ + switch (size_bytes) { + case 1: + return set_field(0, DMI_SBCS_SBACCESS, 0); + case 2: + return set_field(0, DMI_SBCS_SBACCESS, 1); + case 4: + return set_field(0, DMI_SBCS_SBACCESS, 2); + case 8: + return set_field(0, DMI_SBCS_SBACCESS, 3); + case 16: + return set_field(0, DMI_SBCS_SBACCESS, 4); + } + assert(0); + return 0; /* Make mingw happy. */ +} + +static target_addr_t sb_read_address(struct target *target) +{ + RISCV013_INFO(info); + unsigned sbasize = get_field(info->sbcs, DMI_SBCS_SBASIZE); + target_addr_t address = 0; + uint32_t v; + if (sbasize > 32) { +#if BUILD_TARGET64 + dmi_read(target, &v, DMI_SBADDRESS1); + address |= v; + address <<= 32; +#endif + } + dmi_read(target, &v, DMI_SBADDRESS0); + address |= v; + return address; +} + +static int sb_write_address(struct target *target, target_addr_t address) +{ + RISCV013_INFO(info); + unsigned sbasize = get_field(info->sbcs, DMI_SBCS_SBASIZE); + /* There currently is no support for >64-bit addresses in OpenOCD. */ + if (sbasize > 96) { + dmi_write(target, DMI_SBADDRESS3, 0); + } + if (sbasize > 64) { + dmi_write(target, DMI_SBADDRESS2, 0); + } + if (sbasize > 32) { +#if BUILD_TARGET64 + dmi_write(target, DMI_SBADDRESS1, address >> 32); +#else + dmi_write(target, DMI_SBADDRESS1, 0); +#endif + } + return dmi_write(target, DMI_SBADDRESS0, address); +} + +static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs) +{ + time_t start = time(NULL); + while (1) { + if (dmi_read(target, sbcs, DMI_SBCS) != ERROR_OK) + return ERROR_FAIL; + if (!get_field(*sbcs, DMI_SBCS_SBBUSY)) + return ERROR_OK; + if (time(NULL) - start > riscv_command_timeout_sec) { + LOG_ERROR("Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). " + "Increase the timeout with riscv set_command_timeout_sec.", + riscv_command_timeout_sec, *sbcs); + } + return ERROR_FAIL; + } +} + +static int read_memory_bus_v0(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" + TARGET_PRIxADDR, size, count, address); + uint8_t *t_buffer = buffer; + riscv_addr_t cur_addr = address; + riscv_addr_t fin_addr = address + (count * size); + uint32_t access = 0; + + const int DMI_SBCS_SBSINGLEREAD_OFFSET = 20; + const uint32_t DMI_SBCS_SBSINGLEREAD = (0x1U << DMI_SBCS_SBSINGLEREAD_OFFSET); + + const int DMI_SBCS_SBAUTOREAD_OFFSET = 15; + const uint32_t DMI_SBCS_SBAUTOREAD = (0x1U << DMI_SBCS_SBAUTOREAD_OFFSET); + + /* ww favorise one off reading if there is an issue */ + if (count == 1) { + for (uint32_t i = 0; i < count; i++) { + if (dmi_read(target, &access, DMI_SBCS) != ERROR_OK) + return ERROR_FAIL; + dmi_write(target, DMI_SBADDRESS0, cur_addr); + /* size/2 matching the bit access of the spec 0.13 */ + access = set_field(access, DMI_SBCS_SBACCESS, size/2); + access = set_field(access, DMI_SBCS_SBSINGLEREAD, 1); + LOG_DEBUG("\r\nread_memory: sab: access: 0x%08x", access); + dmi_write(target, DMI_SBCS, access); + /* 3) read */ + uint32_t value; + if (dmi_read(target, &value, DMI_SBDATA0) != ERROR_OK) + return ERROR_FAIL; + LOG_DEBUG("\r\nread_memory: sab: value: 0x%08x", value); + write_to_buf(t_buffer, value, size); + t_buffer += size; + cur_addr += size; + } + return ERROR_OK; + } + + /* has to be the same size if we want to read a block */ + LOG_DEBUG("reading block until final address 0x%" PRIx64, fin_addr); + if (dmi_read(target, &access, DMI_SBCS) != ERROR_OK) + return ERROR_FAIL; + /* set current address */ + dmi_write(target, DMI_SBADDRESS0, cur_addr); + /* 2) write sbaccess=2, sbsingleread,sbautoread,sbautoincrement + * size/2 matching the bit access of the spec 0.13 */ + access = set_field(access, DMI_SBCS_SBACCESS, size/2); + access = set_field(access, DMI_SBCS_SBAUTOREAD, 1); + access = set_field(access, DMI_SBCS_SBSINGLEREAD, 1); + access = set_field(access, DMI_SBCS_SBAUTOINCREMENT, 1); + LOG_DEBUG("\r\naccess: 0x%08x", access); + dmi_write(target, DMI_SBCS, access); + + while (cur_addr < fin_addr) { + LOG_DEBUG("\r\nsab:autoincrement: \r\n size: %d\tcount:%d\taddress: 0x%08" + PRIx64, size, count, cur_addr); + /* read */ + uint32_t value; + if (dmi_read(target, &value, DMI_SBDATA0) != ERROR_OK) + return ERROR_FAIL; + write_to_buf(t_buffer, value, size); + cur_addr += size; + t_buffer += size; + + /* if we are reaching last address, we must clear autoread */ + if (cur_addr == fin_addr && count != 1) { + dmi_write(target, DMI_SBCS, 0); + if (dmi_read(target, &value, DMI_SBDATA0) != ERROR_OK) + return ERROR_FAIL; + write_to_buf(t_buffer, value, size); + } + } + + return ERROR_OK; +} + +/** + * Read the requested memory using the system bus interface. + */ +static int read_memory_bus_v1(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + RISCV013_INFO(info); + target_addr_t next_address = address; + target_addr_t end_address = address + count * size; + + while (next_address < end_address) { + uint32_t sbcs = set_field(0, DMI_SBCS_SBREADONADDR, 1); + sbcs |= sb_sbaccess(size); + sbcs = set_field(sbcs, DMI_SBCS_SBAUTOINCREMENT, 1); + sbcs = set_field(sbcs, DMI_SBCS_SBREADONDATA, count > 1); + dmi_write(target, DMI_SBCS, sbcs); + + /* This address write will trigger the first read. */ + sb_write_address(target, next_address); + + if (info->bus_master_read_delay) { + jtag_add_runtest(info->bus_master_read_delay, TAP_IDLE); + if (jtag_execute_queue() != ERROR_OK) { + LOG_ERROR("Failed to scan idle sequence"); + return ERROR_FAIL; + } + } + + for (uint32_t i = (next_address - address) / size; i < count - 1; i++) { + read_memory_bus_word(target, address + i * size, size, + buffer + i * size); + } + + sbcs = set_field(sbcs, DMI_SBCS_SBREADONDATA, 0); + dmi_write(target, DMI_SBCS, sbcs); + + read_memory_bus_word(target, address + (count - 1) * size, size, + buffer + (count - 1) * size); + + if (read_sbcs_nonbusy(target, &sbcs) != ERROR_OK) + return ERROR_FAIL; + + if (get_field(sbcs, DMI_SBCS_SBBUSYERROR)) { + /* We read while the target was busy. Slow down and try again. */ + dmi_write(target, DMI_SBCS, DMI_SBCS_SBBUSYERROR); + next_address = sb_read_address(target); + info->bus_master_read_delay += info->bus_master_read_delay / 10 + 1; + } + + unsigned error = get_field(sbcs, DMI_SBCS_SBERROR); + if (error == 0) { + next_address = end_address; + } else { + /* Some error indicating the bus access failed, but not because of + * something we did wrong. */ + dmi_write(target, DMI_SBCS, DMI_SBCS_SBERROR); + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + /** * Read the requested memory, taking care to execute every read exactly once, * even if cmderr=busy is encountered. */ -static int read_memory(struct target *target, target_addr_t address, +static int read_memory_progbuf(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { RISCV013_INFO(info); @@ -1550,8 +2024,8 @@ static int read_memory(struct target *target, target_addr_t address, * dm_data0 contains mem[s0 - 2*size] * s1 contains mem[s0-size] */ - LOG_DEBUG("creating burst to read from 0x%" TARGET_PRIxADDR - " up to 0x%" TARGET_PRIxADDR, read_addr, fin_addr); + LOG_DEBUG("creating burst to read from 0x%" PRIx64 + " up to 0x%" PRIx64, read_addr, fin_addr); assert(read_addr >= address && read_addr < fin_addr); struct riscv_batch *batch = riscv_batch_alloc(target, 32, info->dmi_busy_delay + info->ac_busy_delay); @@ -1569,9 +2043,12 @@ static int read_memory(struct target *target, target_addr_t address, /* Wait for the target to finish performing the last abstract command, * and update our copy of cmderr. */ - uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); + uint32_t abstractcs; + if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) - abstractcs = dmi_read(target, DMI_ABSTRACTCS); + if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); unsigned cmderr = info->cmderr; @@ -1620,7 +2097,10 @@ static int read_memory(struct target *target, target_addr_t address, /* This is definitely a good version of the value that we * attempted to read when we discovered that the target was * busy. */ - dmi_data0 = dmi_read(target, DMI_DATA0); + if (dmi_read(target, &dmi_data0, DMI_DATA0) != ERROR_OK) { + riscv_batch_free(batch); + goto error; + } /* Clobbers DMI_DATA0. */ result = register_read_direct(target, &next_read_addr, @@ -1680,7 +2160,9 @@ static int read_memory(struct target *target, target_addr_t address, if (count > 1) { /* Read the penultimate word. */ - uint64_t value = dmi_read(target, DMI_DATA0); + uint32_t value; + if (dmi_read(target, &value, DMI_DATA0) != ERROR_OK) + goto error; write_to_buf(buffer + receive_addr - address, value, size); log_memory_access(receive_addr, value, size, true); receive_addr += size; @@ -1706,7 +2188,197 @@ error: return result; } -static int write_memory(struct target *target, target_addr_t address, +static int read_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + RISCV013_INFO(info); + if (info->progbufsize >= 2 && !riscv_prefer_sba) + return read_memory_progbuf(target, address, size, count, buffer); + + if ((get_field(info->sbcs, DMI_SBCS_SBACCESS8) && size == 1) || + (get_field(info->sbcs, DMI_SBCS_SBACCESS16) && size == 2) || + (get_field(info->sbcs, DMI_SBCS_SBACCESS32) && size == 4) || + (get_field(info->sbcs, DMI_SBCS_SBACCESS64) && size == 8) || + (get_field(info->sbcs, DMI_SBCS_SBACCESS128) && size == 16)) { + if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 0) + return read_memory_bus_v0(target, address, size, count, buffer); + else if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 1) + return read_memory_bus_v1(target, address, size, count, buffer); + } + + if (info->progbufsize >= 2) + return read_memory_progbuf(target, address, size, count, buffer); + + LOG_ERROR("Don't know how to read memory on this target."); + return ERROR_FAIL; +} + +static int write_memory_bus_v0(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + /*1) write sbaddress: for singlewrite and autoincrement, we need to write the address once*/ + LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" + TARGET_PRIxADDR, size, count, address); + dmi_write(target, DMI_SBADDRESS0, address); + int64_t value = 0; + int64_t access = 0; + riscv_addr_t offset = 0; + riscv_addr_t t_addr = 0; + const uint8_t *t_buffer = buffer + offset; + + /* B.8 Writing Memory, single write check if we write in one go */ + if (count == 1) { /* count is in bytes here */ + /* check the size */ + switch (size) { + case 1: + value = t_buffer[0]; + break; + case 2: + value = t_buffer[0] + | ((uint32_t) t_buffer[1] << 8); + break; + case 4: + value = t_buffer[0] + | ((uint32_t) t_buffer[1] << 8) + | ((uint32_t) t_buffer[2] << 16) + | ((uint32_t) t_buffer[3] << 24); + break; + default: + LOG_ERROR("unsupported access size: %d", size); + return ERROR_FAIL; + } + + access = 0; + access = set_field(access, DMI_SBCS_SBACCESS, size/2); + dmi_write(target, DMI_SBCS, access); + LOG_DEBUG("\r\naccess: 0x%08" PRIx64, access); + LOG_DEBUG("\r\nwrite_memory:SAB: ONE OFF: value 0x%08" PRIx64, value); + dmi_write(target, DMI_SBDATA0, value); + return ERROR_OK; + } + + /*B.8 Writing Memory, using autoincrement*/ + + access = 0; + access = set_field(access, DMI_SBCS_SBACCESS, size/2); + access = set_field(access, DMI_SBCS_SBAUTOINCREMENT, 1); + LOG_DEBUG("\r\naccess: 0x%08" PRIx64, access); + dmi_write(target, DMI_SBCS, access); + + /*2)set the value according to the size required and write*/ + for (riscv_addr_t i = 0; i < count; ++i) { + offset = size*i; + /* for monitoring only */ + t_addr = address + offset; + t_buffer = buffer + offset; + + switch (size) { + case 1: + value = t_buffer[0]; + break; + case 2: + value = t_buffer[0] + | ((uint32_t) t_buffer[1] << 8); + break; + case 4: + value = t_buffer[0] + | ((uint32_t) t_buffer[1] << 8) + | ((uint32_t) t_buffer[2] << 16) + | ((uint32_t) t_buffer[3] << 24); + break; + default: + LOG_ERROR("unsupported access size: %d", size); + return ERROR_FAIL; + } + LOG_DEBUG("SAB:autoincrement: expected address: 0x%08x value: 0x%08x" + PRIx64, (uint32_t)t_addr, (uint32_t)value); + dmi_write(target, DMI_SBDATA0, value); + } + /*reset the autoincrement when finished (something weird is happening if this is not done at the end*/ + access = set_field(access, DMI_SBCS_SBAUTOINCREMENT, 0); + dmi_write(target, DMI_SBCS, access); + + return ERROR_OK; +} + +static int write_memory_bus_v1(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + RISCV013_INFO(info); + uint32_t sbcs = sb_sbaccess(size); + sbcs = set_field(sbcs, DMI_SBCS_SBAUTOINCREMENT, 1); + dmi_write(target, DMI_SBCS, sbcs); + + target_addr_t next_address = address; + target_addr_t end_address = address + count * size; + + sb_write_address(target, next_address); + while (next_address < end_address) { + for (uint32_t i = (next_address - address) / size; i < count; i++) { + const uint8_t *p = buffer + i * size; + if (size > 12) + dmi_write(target, DMI_SBDATA3, + ((uint32_t) p[12]) | + (((uint32_t) p[13]) << 8) | + (((uint32_t) p[14]) << 16) | + (((uint32_t) p[15]) << 24)); + if (size > 8) + dmi_write(target, DMI_SBDATA2, + ((uint32_t) p[8]) | + (((uint32_t) p[9]) << 8) | + (((uint32_t) p[10]) << 16) | + (((uint32_t) p[11]) << 24)); + if (size > 4) + dmi_write(target, DMI_SBDATA1, + ((uint32_t) p[4]) | + (((uint32_t) p[5]) << 8) | + (((uint32_t) p[6]) << 16) | + (((uint32_t) p[7]) << 24)); + uint32_t value = p[0]; + if (size > 2) { + value |= ((uint32_t) p[2]) << 16; + value |= ((uint32_t) p[3]) << 24; + } + if (size > 1) + value |= ((uint32_t) p[1]) << 8; + dmi_write(target, DMI_SBDATA0, value); + + log_memory_access(address + i * size, value, size, false); + + if (info->bus_master_write_delay) { + jtag_add_runtest(info->bus_master_write_delay, TAP_IDLE); + if (jtag_execute_queue() != ERROR_OK) { + LOG_ERROR("Failed to scan idle sequence"); + return ERROR_FAIL; + } + } + } + + if (read_sbcs_nonbusy(target, &sbcs) != ERROR_OK) + return ERROR_FAIL; + + if (get_field(sbcs, DMI_SBCS_SBBUSYERROR)) { + /* We wrote while the target was busy. Slow down and try again. */ + dmi_write(target, DMI_SBCS, DMI_SBCS_SBBUSYERROR); + next_address = sb_read_address(target); + info->bus_master_write_delay += info->bus_master_write_delay / 10 + 1; + } + + unsigned error = get_field(sbcs, DMI_SBCS_SBERROR); + if (error == 0) { + next_address = end_address; + } else { + /* Some error indicating the bus access failed, but not because of + * something we did wrong. */ + dmi_write(target, DMI_SBCS, DMI_SBCS_SBERROR); + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + +static int write_memory_progbuf(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { RISCV013_INFO(info); @@ -1841,9 +2513,12 @@ static int write_memory(struct target *target, target_addr_t address, * is this read to abstractcs that will cause the dmi_busy_delay * to be incremented if necessary. */ - uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); + uint32_t abstractcs; + if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + goto error; while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) - abstractcs = dmi_read(target, DMI_ABSTRACTCS); + if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK) + return ERROR_FAIL; info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); switch (info->cmderr) { case CMDERR_NONE: @@ -1883,6 +2558,31 @@ error: return result; } +static int write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + RISCV013_INFO(info); + if (info->progbufsize >= 2 && !riscv_prefer_sba) + return write_memory_progbuf(target, address, size, count, buffer); + + if ((get_field(info->sbcs, DMI_SBCS_SBACCESS8) && size == 1) || + (get_field(info->sbcs, DMI_SBCS_SBACCESS16) && size == 2) || + (get_field(info->sbcs, DMI_SBCS_SBACCESS32) && size == 4) || + (get_field(info->sbcs, DMI_SBCS_SBACCESS64) && size == 8) || + (get_field(info->sbcs, DMI_SBCS_SBACCESS128) && size == 16)) { + if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 0) + return write_memory_bus_v0(target, address, size, count, buffer); + else if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 1) + return write_memory_bus_v1(target, address, size, count, buffer); + } + + if (info->progbufsize >= 2) + return write_memory_progbuf(target, address, size, count, buffer); + + LOG_ERROR("Don't know how to write memory on this target."); + return ERROR_FAIL; +} + static int arch_state(struct target *target) { return ERROR_OK; @@ -1918,21 +2618,17 @@ static int riscv013_get_register(struct target *target, riscv_set_current_hartid(target, hid); int result = ERROR_OK; - if (rid <= GDB_REGNO_XPR31) { - result = register_read_direct(target, value, rid); - } else if (rid == GDB_REGNO_PC) { + if (rid == GDB_REGNO_PC) { result = register_read_direct(target, value, GDB_REGNO_DPC); LOG_DEBUG("read PC from DPC: 0x%016" PRIx64, *value); } else if (rid == GDB_REGNO_PRIV) { uint64_t dcsr; result = register_read_direct(target, &dcsr, GDB_REGNO_DCSR); - buf_set_u64((unsigned char *)value, 0, 8, get_field(dcsr, CSR_DCSR_PRV)); + *value = get_field(dcsr, CSR_DCSR_PRV); } else { result = register_read_direct(target, value, rid); - if (result != ERROR_OK) { - LOG_ERROR("Unable to read %s", gdb_regno_name(rid)); + if (result != ERROR_OK) *value = -1; - } } return result; @@ -1974,7 +2670,8 @@ static void riscv013_select_current_hart(struct target *target) { RISCV_INFO(r); - uint64_t dmcontrol = dmi_read(target, DMI_DMCONTROL); + uint32_t dmcontrol; + dmi_read(target, &dmcontrol, DMI_DMCONTROL); dmcontrol = set_field(dmcontrol, hartsel_mask(target), r->current_hartid); dmi_write(target, DMI_DMCONTROL, dmcontrol); } @@ -1987,7 +2684,9 @@ static int riscv013_halt_current_hart(struct target *target) LOG_ERROR("Hart %d is already halted!", r->current_hartid); /* Issue the halt command, and then wait for the current hart to halt. */ - uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); + uint32_t dmcontrol; + if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HALTREQ, 1); dmi_write(target, DMI_DMCONTROL, dmcontrol); for (size_t i = 0; i < 256; ++i) @@ -1995,8 +2694,11 @@ static int riscv013_halt_current_hart(struct target *target) break; if (!riscv_is_halted(target)) { - uint32_t dmstatus = dmi_read(target, DMI_DMSTATUS); - dmcontrol = dmi_read(target, DMI_DMCONTROL); + uint32_t dmstatus; + if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) + return ERROR_FAIL; + if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; LOG_ERROR("unable to halt hart %d", r->current_hartid); LOG_ERROR(" dmcontrol=0x%08x", dmcontrol); @@ -2037,7 +2739,9 @@ static int riscv013_on_halt(struct target *target) static bool riscv013_is_halted(struct target *target) { - uint32_t dmstatus = dmi_read(target, DMI_DMSTATUS); + uint32_t dmstatus; + if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) + return false; if (get_field(dmstatus, DMI_DMSTATUS_ANYUNAVAIL)) LOG_ERROR("hart %d is unavailiable", riscv_current_hartid(target)); if (get_field(dmstatus, DMI_DMSTATUS_ANYNONEXISTENT)) @@ -2054,8 +2758,9 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) switch (get_field(dcsr, CSR_DCSR_CAUSE)) { case CSR_DCSR_CAUSE_SWBP: - case CSR_DCSR_CAUSE_TRIGGER: return RISCV_HALT_BREAKPOINT; + case CSR_DCSR_CAUSE_TRIGGER: + return RISCV_HALT_TRIGGER; case CSR_DCSR_CAUSE_STEP: return RISCV_HALT_SINGLESTEP; case CSR_DCSR_CAUSE_DEBUGINT: @@ -2075,7 +2780,9 @@ int riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_ins riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index) { - return dmi_read(target, DMI_PROGBUF0 + index); + uint32_t value; + dmi_read(target, &value, DMI_PROGBUF0 + index); + return value; } int riscv013_execute_debug_buffer(struct target *target) @@ -2119,15 +2826,28 @@ int riscv013_dmi_write_u64_bits(struct target *target) return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH; } +static int maybe_execute_fence_i(struct target *target) +{ + RISCV013_INFO(info); + RISCV_INFO(r); + if (info->progbufsize + r->impebreak >= 2) { + struct riscv_program program; + riscv_program_init(&program, target); + if (riscv_program_fence_i(&program) != ERROR_OK) + return ERROR_FAIL; + if (riscv_program_exec(&program, target) != ERROR_OK) { + LOG_ERROR("Failed to execute fence.i"); + return ERROR_FAIL; + } + } + return ERROR_OK; +} /* Helper Functions. */ static int riscv013_on_step_or_resume(struct target *target, bool step) { - struct riscv_program program; - riscv_program_init(&program, target); - riscv_program_fence_i(&program); - if (riscv_program_exec(&program, target) != ERROR_OK) - LOG_ERROR("Unable to execute fence.i"); + if (maybe_execute_fence_i(target) != ERROR_OK) + return ERROR_FAIL; /* We want to twiddle some bits in the debug CSR so debugging works. */ riscv_reg_t dcsr; @@ -2150,20 +2870,21 @@ static int riscv013_step_or_resume_current_hart(struct target *target, bool step return ERROR_FAIL; } - struct riscv_program program; - riscv_program_init(&program, target); - riscv_program_fence_i(&program); - if (riscv_program_exec(&program, target) != ERROR_OK) + if (maybe_execute_fence_i(target) != ERROR_OK) return ERROR_FAIL; /* Issue the resume command, and then wait for the current hart to resume. */ - uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); + uint32_t dmcontrol; + if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_RESUMEREQ, 1); dmi_write(target, DMI_DMCONTROL, dmcontrol); + uint32_t dmstatus; for (size_t i = 0; i < 256; ++i) { usleep(10); - uint32_t dmstatus = dmi_read(target, DMI_DMSTATUS); + if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) + return ERROR_FAIL; if (get_field(dmstatus, DMI_DMSTATUS_ALLRESUMEACK) == 0) continue; if (step && get_field(dmstatus, DMI_DMSTATUS_ALLHALTED) == 0) @@ -2174,8 +2895,10 @@ static int riscv013_step_or_resume_current_hart(struct target *target, bool step return ERROR_OK; } - uint32_t dmstatus = dmi_read(target, DMI_DMSTATUS); - dmcontrol = dmi_read(target, DMI_DMCONTROL); + if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) + return ERROR_FAIL; + if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; LOG_ERROR("unable to resume hart %d", r->current_hartid); LOG_ERROR(" dmcontrol=0x%08x", dmcontrol); LOG_ERROR(" dmstatus =0x%08x", dmstatus); @@ -2193,9 +2916,10 @@ void riscv013_clear_abstract_error(struct target *target) { /* Wait for busy to go away. */ time_t start = time(NULL); - uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); + uint32_t abstractcs; + dmi_read(target, &abstractcs, DMI_ABSTRACTCS); while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) { - abstractcs = dmi_read(target, DMI_ABSTRACTCS); + dmi_read(target, &abstractcs, DMI_ABSTRACTCS); if (time(NULL) - start > riscv_command_timeout_sec) { LOG_ERROR("abstractcs.busy is not going low after %d seconds " @@ -2232,39 +2956,41 @@ int riscv013_test_compliance(struct target *target) { int total_tests = 0; int passed_tests = 0; - uint32_t dmcontrol_orig = dmi_read(target, DMI_DMCONTROL); + uint32_t dmcontrol_orig; + dmi_read(target, &dmcontrol_orig, DMI_DMCONTROL); uint32_t dmcontrol; uint32_t testvar; + uint32_t testvar_read; riscv_reg_t value; dmcontrol = set_field(dmcontrol_orig, hartsel_mask(target), RISCV_MAX_HARTS-1); dmi_write(target, DMI_DMCONTROL, dmcontrol); - dmcontrol = dmi_read(target, DMI_DMCONTROL); + dmi_read(target, &dmcontrol, DMI_DMCONTROL); COMPLIANCE_TEST(get_field(dmcontrol, hartsel_mask(target)) == (RISCV_MAX_HARTS-1), "DMCONTROL.hartsel should hold all the harts allowed by HARTSELLEN."); dmcontrol = set_field(dmcontrol_orig, hartsel_mask(target), 0); dmi_write(target, DMI_DMCONTROL, dmcontrol); - dmcontrol = dmi_read(target, DMI_DMCONTROL); + dmi_read(target, &dmcontrol, DMI_DMCONTROL); COMPLIANCE_TEST(get_field(dmcontrol, hartsel_mask(target)) == 0, "DMCONTROL.hartsel should hold Hart ID 0"); // hartreset dmcontrol = set_field(dmcontrol_orig, DMI_DMCONTROL_HARTRESET, 1); dmi_write(target, DMI_DMCONTROL, dmcontrol); - dmcontrol = dmi_read(target, DMI_DMCONTROL); + dmi_read(target, &dmcontrol, DMI_DMCONTROL); testvar = get_field(dmcontrol, DMI_DMCONTROL_HARTRESET); dmcontrol = set_field(dmcontrol_orig, DMI_DMCONTROL_HARTRESET, 1); dmi_write(target, DMI_DMCONTROL, dmcontrol); - dmcontrol = dmi_read(target, DMI_DMCONTROL); + dmi_read(target, &dmcontrol, DMI_DMCONTROL); COMPLIANCE_TEST(((testvar == 0) || (get_field(dmcontrol, DMI_DMCONTROL_HARTRESET)) == 0), "DMCONTROL.hartreset can be 0 or RW."); // hasel dmcontrol = set_field(dmcontrol_orig, DMI_DMCONTROL_HASEL, 1); dmi_write(target, DMI_DMCONTROL, dmcontrol); - dmcontrol = dmi_read(target, DMI_DMCONTROL); + dmi_read(target, &dmcontrol, DMI_DMCONTROL); testvar = get_field(dmcontrol, DMI_DMCONTROL_HASEL); dmcontrol = set_field(dmcontrol_orig, DMI_DMCONTROL_HASEL, 1); dmi_write(target, DMI_DMCONTROL, dmcontrol); - dmcontrol = dmi_read(target, DMI_DMCONTROL); + dmi_read(target, &dmcontrol, DMI_DMCONTROL); COMPLIANCE_TEST(((testvar == 0) || (get_field(dmcontrol, DMI_DMCONTROL_HASEL)) == 0), "DMCONTROL.hasel can be 0 or RW."); //TODO: test that hamask registers exist if hasel does. @@ -2272,26 +2998,29 @@ int riscv013_test_compliance(struct target *target) { riscv_halt_all_harts(target); // Writing haltreq should not cause any problems for a halted hart, but we // should be able to read and write it. - dmcontrol = dmi_read(target, DMI_DMCONTROL); + dmi_read(target, &dmcontrol, DMI_DMCONTROL); dmcontrol |= DMI_DMCONTROL_HALTREQ; dmi_write(target, DMI_DMCONTROL, dmcontrol); - COMPLIANCE_TEST(dmi_read(target, DMI_DMCONTROL) & DMI_DMCONTROL_HALTREQ, "DMCONTROL.haltreq should be R/W"); - uint32_t dmstatus; + dmi_read(target, &dmcontrol, DMI_DMCONTROL); + COMPLIANCE_TEST(dmcontrol & DMI_DMCONTROL_HALTREQ, "DMCONTROL.haltreq should be R/W"); + uint32_t dmstatus, dmstatus_read; do { - dmstatus = dmi_read(target, DMI_DMSTATUS); + dmi_read(target, &dmstatus, DMI_DMSTATUS); } while ((dmstatus & DMI_DMSTATUS_ALLHALTED) == 0); dmi_write(target, DMI_DMSTATUS, 0xffffffff); - COMPLIANCE_TEST(dmi_read(target, DMI_DMSTATUS) == dmstatus, "DMSTATUS is R/O"); + dmi_read(target, &dmstatus_read, DMI_DMSTATUS); + COMPLIANCE_TEST(dmstatus_read == dmstatus, "DMSTATUS is R/O"); // resumereq. This will resume the hart but this test is destructive anyway. dmcontrol &= ~DMI_DMCONTROL_HALTREQ; dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_RESUMEREQ, 1); dmi_write(target, DMI_DMCONTROL, dmcontrol); - COMPLIANCE_TEST(get_field(dmi_read(target, DMI_DMCONTROL), DMI_DMCONTROL_RESUMEREQ) == 1, "DMCONTROL.resumereq should be R/W"); + dmi_read(target, &dmcontrol, DMI_DMCONTROL); + COMPLIANCE_TEST(get_field(dmcontrol, DMI_DMCONTROL_RESUMEREQ) == 1, "DMCONTROL.resumereq should be R/W"); do { - dmstatus = dmi_read(target, DMI_DMSTATUS); + dmi_read(target, &dmstatus, DMI_DMSTATUS); } while (get_field(dmstatus, DMI_DMSTATUS_ALLRESUMEACK) == 0); // Halt the hart again because the target isn't aware that we resumed it. @@ -2299,20 +3028,22 @@ int riscv013_test_compliance(struct target *target) { dmcontrol |= DMI_DMCONTROL_HALTREQ; dmi_write(target, DMI_DMCONTROL, dmcontrol); do { - dmstatus = dmi_read(target, DMI_DMSTATUS); + dmi_read(target, &dmstatus, DMI_DMSTATUS); } while ((dmstatus & DMI_DMSTATUS_ALLHALTED) == 0); dmcontrol &= ~DMI_DMCONTROL_HALTREQ; dmi_write(target, DMI_DMCONTROL, dmcontrol); // Not clear that this read is required according to the spec. - dmi_read(target, DMI_DMSTATUS); + dmi_read(target, &dmstatus, DMI_DMSTATUS); // HARTINFO: Read-Only. This is per-hart, so need to adjust hartsel. for (int hartsel = 0; hartsel < riscv_count_harts(target); hartsel++){ riscv_set_current_hartid(target, hartsel); - uint32_t hartinfo = dmi_read(target, DMI_HARTINFO); - dmi_write (target, DMI_HARTINFO, ~hartinfo); - COMPLIANCE_TEST((dmi_read(target, DMI_HARTINFO) == hartinfo), "DMHARTINFO should be Read-Only."); + uint32_t hartinfo, hartinfo_read; + dmi_read(target, &hartinfo, DMI_HARTINFO); + dmi_write(target, DMI_HARTINFO, ~hartinfo); + dmi_read(target, &hartinfo_read, DMI_HARTINFO); + COMPLIANCE_TEST((hartinfo_read == hartinfo), "DMHARTINFO should be Read-Only."); uint32_t nscratch = get_field(hartinfo, DMI_HARTINFO_NSCRATCH); for (unsigned int d = 0; d < nscratch; d++) { @@ -2349,32 +3080,49 @@ int riscv013_test_compliance(struct target *target) { } - // HALTSUM - uint32_t expected_haltsum = 0; + // HALTSUM -- TODO: More than 32 harts + // TODO: HALTSUM2, HALTSUM3 + uint32_t expected_haltsum0 = 0; for (int i = 0; i < riscv_count_harts(target); i +=32){ - expected_haltsum |= (1 << (i / 32)); + expected_haltsum0 |= (1 << (i / 32)); } - COMPLIANCE_TEST(dmi_read(target, DMI_HALTSUM) == expected_haltsum, "HALTSUM should report all halted harts"); + dmi_read(target, &testvar_read, DMI_HALTSUM0); + COMPLIANCE_TEST(testvar_read == expected_haltsum0, "HALTSUM0 should report summary of 32 halted harts"); - dmi_write(target, DMI_HALTSUM, 0xffffffff); - COMPLIANCE_TEST(dmi_read(target, DMI_HALTSUM) == expected_haltsum, "HALTSUM is R/O"); + dmi_write(target, DMI_HALTSUM0, 0xffffffff); + dmi_read(target, &testvar_read, DMI_HALTSUM0); + COMPLIANCE_TEST(testvar_read == expected_haltsum0, "HALTSUM0 should be R/O"); - dmi_write(target, DMI_HALTSUM, 0x0); - COMPLIANCE_TEST(dmi_read(target, DMI_HALTSUM) == expected_haltsum, "HALTSUM is R/O"); + dmi_write(target, DMI_HALTSUM0, 0x0); + dmi_read(target, &testvar_read, DMI_HALTSUM0); + COMPLIANCE_TEST(testvar_read == expected_haltsum0, "HALTSUM0 should be R/O"); - for (int i = 0; i < riscv_count_harts(target); i +=32){ - uint32_t haltstat = dmi_read(target, 0x40 + (i / 32)); - uint32_t haltstat_expected = (((i + 1) * 32) <= riscv_count_harts(target)) ? 0xFFFFFFFFU : ((1U << (riscv_count_harts(target) % 32)) - 1); - COMPLIANCE_TEST(haltstat == haltstat_expected, "Halt Status Registers should report all halted harts."); + for (int i = 0; i < 32/*TODO: riscv_count_harts(target)*/; i +=32){ + //TODO: Set hartsel for i > 32 harts. + dmi_read(target, &testvar_read, DMI_HALTSUM1); + uint32_t haltsum1_expected = (((i + 1) * 32) <= riscv_count_harts(target)) ? 0xFFFFFFFFU : ((1U << (riscv_count_harts(target) % 32)) - 1); + COMPLIANCE_TEST(testvar_read == haltsum1_expected, "HALTSUM1 should report summary of 1024 halted harts"); + + // Just have to check this once + if (i == 0) { + dmi_write(target, DMI_HALTSUM1, 0xffffffff); + dmi_read(target, &testvar_read, DMI_HALTSUM1); + COMPLIANCE_TEST(testvar_read == haltsum1_expected, "HALTSUM1 should be R/O"); + + dmi_write(target, DMI_HALTSUM1, 0x0); + dmi_read(target, &testvar_read, DMI_HALTSUM1); + COMPLIANCE_TEST(testvar_read == haltsum1_expected, "HALTSUM1 should be R/O"); + } } - + // TODO: HAWINDOWSEL - + // TODO: HAWINDOW // ABSTRACTCS - uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); + uint32_t abstractcs; + dmi_read(target, &abstractcs, DMI_ABSTRACTCS); // Check that all reported Data Words are really R/W for (int invert = 0; invert < 2; invert++) { @@ -2386,7 +3134,8 @@ int riscv013_test_compliance(struct target *target) { for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i ++){ testvar = (i + 1) * 0x11111111; if (invert) {testvar = ~testvar;} - COMPLIANCE_TEST(dmi_read(target, DMI_DATA0 + i) == testvar, "All reported DATA words must be R/W"); + dmi_read(target, &testvar_read, DMI_DATA0 + i); + COMPLIANCE_TEST(testvar_read == testvar, "All reported DATA words must be R/W"); } } @@ -2400,7 +3149,8 @@ int riscv013_test_compliance(struct target *target) { for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i ++){ testvar = (i + 1) * 0x11111111; if (invert) {testvar = ~testvar;} - COMPLIANCE_TEST(dmi_read(target, DMI_PROGBUF0 + i) == testvar, "All reported PROGBUF words must be R/W"); + dmi_read(target, &testvar_read, DMI_PROGBUF0 + i); + COMPLIANCE_TEST(testvar_read == testvar, "All reported PROGBUF words must be R/W"); } } @@ -2410,13 +3160,17 @@ int riscv013_test_compliance(struct target *target) { // TODO: Unclear from the spec whether all these bits need to truly be R/W. // But at any rate, this is not legal and should cause an error. dmi_write(target, DMI_COMMAND, 0xAAAAAAAA); - COMPLIANCE_TEST(dmi_read(target, DMI_COMMAND) == 0xAAAAAAAA, "COMMAND register should be R/W"); - COMPLIANCE_TEST(get_field(dmi_read(target, DMI_ABSTRACTCS), DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, \ + dmi_read(target, &testvar_read, DMI_COMMAND); + COMPLIANCE_TEST(testvar_read == 0xAAAAAAAA, "COMMAND register should be R/W"); + dmi_read(target, &testvar_read, DMI_ABSTRACTCS); + COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, \ "Illegal COMMAND should result in UNSUPPORTED"); dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); dmi_write(target, DMI_COMMAND, 0x55555555); - COMPLIANCE_TEST(dmi_read(target, DMI_COMMAND) == 0x55555555, "COMMAND register should be R/W"); - COMPLIANCE_TEST(get_field(dmi_read(target, DMI_ABSTRACTCS), DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, \ + dmi_read(target, &testvar_read, DMI_COMMAND); + COMPLIANCE_TEST(testvar_read == 0x55555555, "COMMAND register should be R/W"); + dmi_read(target, &testvar_read, DMI_ABSTRACTCS); + COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, \ "Illegal COMMAND should result in UNSUPPORTED"); dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); @@ -2433,32 +3187,44 @@ int riscv013_test_compliance(struct target *target) { dmi_write(target, DMI_DATA0 + 1, i + 1); } dmi_write(target, DMI_COMMAND, command); - do { busy = get_field(dmi_read(target, DMI_ABSTRACTCS), DMI_ABSTRACTCS_BUSY);} while (busy); - COMPLIANCE_TEST(get_field(dmi_read(target, DMI_ABSTRACTCS), DMI_ABSTRACTCS_CMDERR) == 0, "GPR Writes should be supported."); + do { + dmi_read(target, &testvar_read, DMI_ABSTRACTCS); + busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY); + } while (busy); + dmi_read(target, &testvar_read, DMI_ABSTRACTCS); + COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == 0, "GPR Writes should be supported."); dmi_write(target, DMI_DATA0, 0xDEADBEEF); if (riscv_xlen(target) > 32) { dmi_write(target, DMI_DATA0 + 1, 0xDEADBEEF); } command = set_field(command, AC_ACCESS_REGISTER_WRITE, 0); dmi_write(target, DMI_COMMAND, command); - do { busy = get_field(dmi_read(target, DMI_ABSTRACTCS), DMI_ABSTRACTCS_BUSY);} while (busy); - COMPLIANCE_TEST(get_field(dmi_read(target, DMI_ABSTRACTCS), DMI_ABSTRACTCS_CMDERR) == 0, "GPR Reads should be supported."); - COMPLIANCE_TEST(dmi_read(target, DMI_DATA0) == i, "GPR Reads and writes should be supported."); + do { + dmi_read(target, &testvar_read, DMI_ABSTRACTCS); + busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY); + } while (busy); + dmi_read(target, &testvar_read, DMI_ABSTRACTCS); + COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == 0, "GPR Reads should be supported."); + dmi_read(target, &testvar_read, DMI_DATA0); + COMPLIANCE_TEST(testvar_read == i, "GPR Reads and writes should be supported."); if (riscv_xlen(target) > 32) { - COMPLIANCE_TEST(dmi_read(target, DMI_DATA0 + 1) == (i + 1), "GPR Reads and writes should be supported."); + dmi_read(target, &testvar_read, DMI_DATA0 + 1); + COMPLIANCE_TEST(testvar_read == (i + 1), "GPR Reads and writes should be supported."); } } // ABSTRACTAUTO // See which bits are actually writable dmi_write(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF); - uint32_t abstractauto = dmi_read(target, DMI_ABSTRACTAUTO); + uint32_t abstractauto; + dmi_read(target, &abstractauto, DMI_ABSTRACTAUTO); dmi_write(target, DMI_ABSTRACTAUTO, 0x0); if (abstractauto > 0) { testvar = 0; // TODO: This mechanism only works when you have a reasonable sized progbuf, which is not // a true compliance requirement. - COMPLIANCE_TEST(riscv_set_register(target, GDB_REGNO_S0, 0) == ERROR_OK, "Need to be able to write S0 to test ABSTRACTAUTO"); + uint32_t result = riscv_set_register(target, GDB_REGNO_S0, 0); + COMPLIANCE_TEST(result == ERROR_OK, "Need to be able to write S0 to test ABSTRACTAUTO"); struct riscv_program program; riscv_program_init(&program, target); // Also testing that WFI() is a NOP during debug mode. @@ -2469,20 +3235,26 @@ int riscv013_test_compliance(struct target *target) { riscv_program_exec(&program, target); testvar ++; dmi_write(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF); - abstractauto = dmi_read(target, DMI_ABSTRACTAUTO); + dmi_read(target, &abstractauto, DMI_ABSTRACTAUTO); uint32_t autoexec_data = get_field(abstractauto, DMI_ABSTRACTAUTO_AUTOEXECDATA); uint32_t autoexec_progbuf = get_field(abstractauto, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF); for (unsigned int i = 0; i < 12; i ++){ - dmi_read(target, DMI_DATA0 + i); - do { busy = get_field(dmi_read(target, DMI_ABSTRACTCS), DMI_ABSTRACTCS_BUSY);} while (busy); + dmi_read(target, &testvar_read, DMI_DATA0 + i); + do { + dmi_read(target, &testvar_read, DMI_ABSTRACTCS); + busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY); + } while (busy); if (autoexec_data & (1 << i)) { COMPLIANCE_TEST(i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT), "AUTOEXEC may be writable up to DATACOUNT bits."); testvar ++; } } for (unsigned int i = 0; i < 16; i ++){ - dmi_read(target, DMI_PROGBUF0 + i); - do { busy = get_field(dmi_read(target, DMI_ABSTRACTCS), DMI_ABSTRACTCS_BUSY);} while (busy); + dmi_read(target, &testvar_read, DMI_PROGBUF0 + i); + do { + dmi_read(target, &testvar_read, DMI_ABSTRACTCS); + busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY); + } while (busy); if (autoexec_progbuf & (1 << i)) { COMPLIANCE_TEST(i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE), "AUTOEXEC may be writable up to PROGBUFSIZE bits."); testvar ++; @@ -2524,7 +3296,7 @@ int riscv013_test_compliance(struct target *target) { if (riscv_xlen(target) > 32) { dpcmask |= (0xFFFFFFFFUL << 32); } - if (riscv_supports_extension(target, 'C')){ + if (riscv_supports_extension(target, riscv_current_hartid(target), 'C')){ dpcmask |= 0x2; } @@ -2557,33 +3329,38 @@ int riscv013_test_compliance(struct target *target) { } dmi_write(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF); - abstractauto = dmi_read(target, DMI_ABSTRACTAUTO); + dmi_read(target, &abstractauto, DMI_ABSTRACTAUTO); // Pulse reset. target->reset_halt = true; - dmcontrol = dmi_read(target, DMI_DMCONTROL); + dmi_read(target, &dmcontrol, DMI_DMCONTROL); riscv_set_current_hartid(target, 0); assert_reset(target); deassert_reset(target); // Verify that most stuff is not affected by ndmreset. - COMPLIANCE_TEST(dmi_read(target, DMI_COMMAND) == 0xFFFFFFFF, "NDMRESET should not affect DMI_COMMAND"); - COMPLIANCE_TEST(get_field(dmi_read(target, DMI_ABSTRACTCS), DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, "NDMRESET should not affect DMI_ABSTRACTCS"); - COMPLIANCE_TEST(dmi_read(target, DMI_ABSTRACTAUTO) == abstractauto, "NDMRESET should not affect DMI_ABSTRACTAUTO"); + dmi_read(target, &testvar_read, DMI_COMMAND); + COMPLIANCE_TEST(testvar_read == 0xFFFFFFFF, "NDMRESET should not affect DMI_COMMAND"); + dmi_read(target, &testvar_read, DMI_ABSTRACTCS); + COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, "NDMRESET should not affect DMI_ABSTRACTCS"); + dmi_read(target, &testvar_read, DMI_ABSTRACTAUTO); + COMPLIANCE_TEST(testvar_read == abstractauto, "NDMRESET should not affect DMI_ABSTRACTAUTO"); // Clean up to avoid future test failures dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); dmi_write(target, DMI_ABSTRACTAUTO, 0); - + for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i ++){ testvar = (i + 1) * 0x11111111; - COMPLIANCE_TEST(dmi_read(target, DMI_PROGBUF0 + i) == testvar, "PROGBUF words must not be affected by NDMRESET"); + dmi_read(target, &testvar_read, DMI_PROGBUF0 + i); + COMPLIANCE_TEST(testvar_read == testvar, "PROGBUF words must not be affected by NDMRESET"); } for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i ++){ testvar = (i + 1) * 0x11111111; - COMPLIANCE_TEST(dmi_read(target, DMI_DATA0 + i) == testvar, "DATA words must not be affected by NDMRESET"); + dmi_read(target, &testvar_read, DMI_DATA0 + i); + COMPLIANCE_TEST(testvar_read == testvar, "DATA words must not be affected by NDMRESET"); } // verify that DPC *is* affected by ndmreset. Since we don't know what it *should* be, @@ -2599,18 +3376,23 @@ int riscv013_test_compliance(struct target *target) { // Toggle dmactive dmi_write(target, DMI_DMCONTROL, 0); dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE); - COMPLIANCE_TEST(dmi_read(target, DMI_COMMAND) == 0, "DMI_COMMAND should reset to 0"); - COMPLIANCE_TEST(get_field(dmi_read(target, DMI_ABSTRACTCS), DMI_ABSTRACTCS_CMDERR) == 0, "ABSTRACTCS.cmderr should reset to 0"); - COMPLIANCE_TEST(dmi_read(target, DMI_ABSTRACTAUTO) == 0, "ABSTRACTAUTO should reset to 0"); + dmi_read(target, &testvar_read, DMI_COMMAND); + COMPLIANCE_TEST(testvar_read == 0, "DMI_COMMAND should reset to 0"); + dmi_read(target, &testvar_read, DMI_ABSTRACTCS); + COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == 0, "ABSTRACTCS.cmderr should reset to 0"); + dmi_read(target, &testvar_read, DMI_ABSTRACTAUTO); + COMPLIANCE_TEST(testvar_read == 0, "ABSTRACTAUTO should reset to 0"); for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i ++){ testvar = (i + 1) * 0x11111111; - COMPLIANCE_TEST(dmi_read(target, DMI_PROGBUF0 + i) == 0, "PROGBUF words should reset to 0"); + dmi_read(target, &testvar_read, DMI_PROGBUF0 + i); + COMPLIANCE_TEST(testvar_read == 0, "PROGBUF words should reset to 0"); } - + for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i ++){ testvar = (i + 1) * 0x11111111; - COMPLIANCE_TEST(dmi_read(target, DMI_DATA0 + i) == 0, "DATA words should reset to 0"); + dmi_read(target, &testvar_read, DMI_DATA0 + i); + COMPLIANCE_TEST(testvar_read == 0, "DATA words should reset to 0"); } //TODO: diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 2b5e89f9f..4d0a0b00e 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -188,6 +188,8 @@ int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC; bool riscv_use_scratch_ram; uint64_t riscv_scratch_ram_address; +bool riscv_prefer_sba; + /* In addition to the ones in the standard spec, we'll also expose additional * CSRs in this list. * The list is either NULL, or a series of ranges (inclusive), terminated with @@ -311,9 +313,12 @@ static int maybe_add_trigger_t1(struct target *target, unsigned hartid, tdata1 = set_field(tdata1, bpcontrol_r, trigger->read); tdata1 = set_field(tdata1, bpcontrol_w, trigger->write); tdata1 = set_field(tdata1, bpcontrol_x, trigger->execute); - tdata1 = set_field(tdata1, bpcontrol_u, !!(r->misa & (1 << ('U' - 'A')))); - tdata1 = set_field(tdata1, bpcontrol_s, !!(r->misa & (1 << ('S' - 'A')))); - tdata1 = set_field(tdata1, bpcontrol_h, !!(r->misa & (1 << ('H' - 'A')))); + tdata1 = set_field(tdata1, bpcontrol_u, + !!(r->misa[hartid] & (1 << ('U' - 'A')))); + tdata1 = set_field(tdata1, bpcontrol_s, + !!(r->misa[hartid] & (1 << ('S' - 'A')))); + tdata1 = set_field(tdata1, bpcontrol_h, + !!(r->misa[hartid] & (1 << ('H' - 'A')))); tdata1 |= bpcontrol_m; tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); /* exact match */ tdata1 = set_field(tdata1, bpcontrol_bpaction, 0); /* cause bp exception */ @@ -356,11 +361,11 @@ static int maybe_add_trigger_t2(struct target *target, unsigned hartid, MCONTROL_ACTION_DEBUG_MODE); tdata1 = set_field(tdata1, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL); tdata1 |= MCONTROL_M; - if (r->misa & (1 << ('H' - 'A'))) + if (r->misa[hartid] & (1 << ('H' - 'A'))) tdata1 |= MCONTROL_H; - if (r->misa & (1 << ('S' - 'A'))) + if (r->misa[hartid] & (1 << ('S' - 'A'))) tdata1 |= MCONTROL_S; - if (r->misa & (1 << ('U' - 'A'))) + if (r->misa[hartid] & (1 << ('U' - 'A'))) tdata1 |= MCONTROL_U; if (trigger->execute) @@ -640,6 +645,7 @@ static int old_or_new_riscv_step( int handle_breakpoints ){ RISCV_INFO(r); + LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); if (r->is_halted == NULL) return oldriscv_step(target, current, address, handle_breakpoints); else @@ -728,6 +734,7 @@ static int old_or_new_riscv_resume( int debug_execution ){ RISCV_INFO(r); + LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); if (r->is_halted == NULL) return oldriscv_resume(target, current, address, handle_breakpoints, debug_execution); else @@ -1027,6 +1034,9 @@ int riscv_openocd_poll(struct target *target) case RISCV_HALT_BREAKPOINT: target->debug_reason = DBG_REASON_BREAKPOINT; break; + case RISCV_HALT_TRIGGER: + target->debug_reason = DBG_REASON_WATCHPOINT; + break; case RISCV_HALT_INTERRUPT: target->debug_reason = DBG_REASON_DBGRQ; break; @@ -1077,13 +1087,53 @@ int riscv_openocd_resume( int current, target_addr_t address, int handle_breakpoints, - int debug_execution -) { - LOG_DEBUG("resuming all harts"); + int debug_execution) +{ + LOG_DEBUG("debug_reason=%d", target->debug_reason); if (!current) riscv_set_register(target, GDB_REGNO_PC, address); + if (target->debug_reason == DBG_REASON_WATCHPOINT) { + /* To be able to run off a trigger, disable all the triggers, step, and + * then resume as usual. */ + struct watchpoint *watchpoint = target->watchpoints; + bool trigger_temporarily_cleared[RISCV_MAX_HWBPS] = {0}; + + int i = 0; + int result = ERROR_OK; + while (watchpoint && result == ERROR_OK) { + LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->set); + trigger_temporarily_cleared[i] = watchpoint->set; + if (watchpoint->set) { + result = riscv_remove_watchpoint(target, watchpoint); + } + watchpoint = watchpoint->next; + i++; + } + + if (result == ERROR_OK) { + result = riscv_step_rtos_hart(target); + } + + watchpoint = target->watchpoints; + i = 0; + while (watchpoint) { + LOG_DEBUG("watchpoint %d: cleared=%d", i, trigger_temporarily_cleared[i]); + if (trigger_temporarily_cleared[i]) { + if (result == ERROR_OK) + result = riscv_add_watchpoint(target, watchpoint); + else + riscv_add_watchpoint(target, watchpoint); + } + watchpoint = watchpoint->next; + i++; + } + + if (result != ERROR_OK) + return result; + } + int out = riscv_resume_all_harts(target); if (out != ERROR_OK) { LOG_ERROR("unable to resume all harts"); @@ -1187,6 +1237,7 @@ COMMAND_HANDLER(riscv_set_scratch_ram) return ERROR_OK; } + // TODO: use COMMAND_PARSE_NUMBER long long unsigned int address; int result = sscanf(CMD_ARGV[0], "%llx", &address); if (result != (int) strlen(CMD_ARGV[0])) { @@ -1200,6 +1251,16 @@ COMMAND_HANDLER(riscv_set_scratch_ram) return ERROR_OK; } +COMMAND_HANDLER(riscv_set_prefer_sba) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_prefer_sba); + return ERROR_OK; +} + void parse_error(const char *string, char c, unsigned position) { char buf[position+2]; @@ -1282,6 +1343,113 @@ COMMAND_HANDLER(riscv_set_expose_csrs) return ERROR_OK; } +COMMAND_HANDLER(riscv_authdata_read) +{ + if (CMD_ARGC != 0) { + LOG_ERROR("Command takes no parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + if (!target) { + LOG_ERROR("target is NULL!"); + return ERROR_FAIL; + } + + RISCV_INFO(r); + if (!r) { + LOG_ERROR("riscv_info is NULL!"); + return ERROR_FAIL; + } + + if (r->authdata_read) { + uint32_t value; + if (r->authdata_read(target, &value) != ERROR_OK) + return ERROR_FAIL; + command_print(CMD_CTX, "0x%" PRIx32, value); + return ERROR_OK; + } else { + LOG_ERROR("authdata_read is not implemented for this target."); + return ERROR_FAIL; + } +} + +COMMAND_HANDLER(riscv_authdata_write) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 argument"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + uint32_t value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], value); + + if (r->authdata_write) { + return r->authdata_write(target, value); + } else { + LOG_ERROR("authdata_write is not implemented for this target."); + return ERROR_FAIL; + } +} + +COMMAND_HANDLER(riscv_dmi_read) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + if (!target) { + LOG_ERROR("target is NULL!"); + return ERROR_FAIL; + } + + RISCV_INFO(r); + if (!r) { + LOG_ERROR("riscv_info is NULL!"); + return ERROR_FAIL; + } + + if (r->dmi_read) { + uint32_t address, value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); + if (r->dmi_read(target, &value, address) != ERROR_OK) + return ERROR_FAIL; + command_print(CMD_CTX, "0x%" PRIx32, value); + return ERROR_OK; + } else { + LOG_ERROR("dmi_read is not implemented for this target."); + return ERROR_FAIL; + } +} + + +COMMAND_HANDLER(riscv_dmi_write) +{ + if (CMD_ARGC != 2) { + LOG_ERROR("Command takes exactly 2 arguments"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + uint32_t address, value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + + if (r->dmi_write) { + return r->dmi_write(target, address, value); + } else { + LOG_ERROR("dmi_write is not implemented for this target."); + return ERROR_FAIL; + } +} + static const struct command_registration riscv_exec_command_handlers[] = { { .name = "test_compliance", @@ -1311,15 +1479,51 @@ static const struct command_registration riscv_exec_command_handlers[] = { .usage = "riscv set_scratch_ram none|[address]", .help = "Set address of 16 bytes of scratch RAM the debugger can use, or 'none'." }, + { + .name = "set_prefer_sba", + .handler = riscv_set_prefer_sba, + .mode = COMMAND_ANY, + .usage = "riscv set_prefer_sba on|off", + .help = "When on, prefer to use System Bus Access to access memory. " + "When off, prefer to use the Program Buffer to access memory." + }, { .name = "expose_csrs", .handler = riscv_set_expose_csrs, .mode = COMMAND_ANY, - .usage = "riscv expose_csrs n0[-m0][,n0[-m0]]...", + .usage = "riscv expose_csrs n0[-m0][,n1[-m1]]...", .help = "Configure a list of inclusive ranges for CSRs to expose in " "addition to the standard ones. This must be executed before " "`init`." }, + { + .name = "authdata_read", + .handler = riscv_authdata_read, + .mode = COMMAND_ANY, + .usage = "riscv authdata_read", + .help = "Return the 32-bit value read from authdata." + }, + { + .name = "authdata_write", + .handler = riscv_authdata_write, + .mode = COMMAND_ANY, + .usage = "riscv authdata_write value", + .help = "Write the 32-bit value to authdata." + }, + { + .name = "dmi_read", + .handler = riscv_dmi_read, + .mode = COMMAND_ANY, + .usage = "riscv dmi_read address", + .help = "Perform a 32-bit DMI read at address, returning the value." + }, + { + .name = "dmi_write", + .handler = riscv_dmi_write, + .mode = COMMAND_ANY, + .usage = "riscv dmi_write address value", + .help = "Perform a 32-bit DMI write of value at address." + }, COMMAND_REGISTRATION_DONE }; @@ -1474,7 +1678,7 @@ int riscv_step_rtos_hart(struct target *target) return ERROR_OK; } -bool riscv_supports_extension(struct target *target, char letter) +bool riscv_supports_extension(struct target *target, int hartid, char letter) { RISCV_INFO(r); unsigned num; @@ -1484,7 +1688,7 @@ bool riscv_supports_extension(struct target *target, char letter) num = letter - 'A'; else return false; - return r->misa & (1 << num); + return r->misa[hartid] & (1 << num); } int riscv_xlen(const struct target *target) @@ -1628,18 +1832,6 @@ enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid) return r->halt_reason(target); } -int riscv_count_triggers(struct target *target) -{ - return riscv_count_triggers_of_hart(target, riscv_current_hartid(target)); -} - -int riscv_count_triggers_of_hart(struct target *target, int hartid) -{ - RISCV_INFO(r); - assert(hartid < riscv_count_harts(target)); - return r->trigger_count[hartid]; -} - size_t riscv_debug_buffer_size(struct target *target) { RISCV_INFO(r); @@ -1911,7 +2103,6 @@ int riscv_init_registers(struct target *target) * between). */ for (uint32_t number = 0; number < GDB_REGNO_COUNT; number++) { struct reg *r = &target->reg_cache->reg_list[number]; - r->caller_save = true; r->dirty = false; r->valid = false; r->exist = true; @@ -1923,6 +2114,7 @@ int riscv_init_registers(struct target *target) * target is in theory allowed to change XLEN on us. But I expect a lot * of other things to break in that case as well. */ if (number <= GDB_REGNO_XPR31) { + r->caller_save = true; switch (number) { case GDB_REGNO_ZERO: r->name = "zero"; @@ -2024,14 +2216,18 @@ int riscv_init_registers(struct target *target) r->group = "general"; r->feature = &feature_cpu; } else if (number == GDB_REGNO_PC) { + r->caller_save = true; sprintf(reg_name, "pc"); r->group = "general"; r->feature = &feature_cpu; } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - if (riscv_supports_extension(target, 'D')) { + r->caller_save = true; + if (riscv_supports_extension(target, riscv_current_hartid(target), + 'D')) { r->reg_data_type = &type_ieee_double; r->size = 64; - } else if (riscv_supports_extension(target, 'F')) { + } else if (riscv_supports_extension(target, + riscv_current_hartid(target), 'F')) { r->reg_data_type = &type_ieee_single; r->size = 32; } else { @@ -2162,7 +2358,8 @@ int riscv_init_registers(struct target *target) case CSR_FFLAGS: case CSR_FRM: case CSR_FCSR: - r->exist = riscv_supports_extension(target, 'F'); + r->exist = riscv_supports_extension(target, + riscv_current_hartid(target), 'F'); r->group = "float"; r->feature = &feature_fpu; break; @@ -2176,7 +2373,16 @@ int riscv_init_registers(struct target *target) case CSR_SCAUSE: case CSR_STVAL: case CSR_SATP: - r->exist = riscv_supports_extension(target, 'S'); + r->exist = riscv_supports_extension(target, + riscv_current_hartid(target), 'S'); + break; + case CSR_MEDELEG: + case CSR_MIDELEG: + /* "In systems with only M-mode, or with both M-mode and + * U-mode but without U-mode trap support, the medeleg and + * mideleg registers should not exist." */ + r->exist = riscv_supports_extension(target, riscv_current_hartid(target), 'S') || + riscv_supports_extension(target, riscv_current_hartid(target), 'N'); break; } diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 2ff087f9e..ebd4cd015 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -30,14 +30,13 @@ enum riscv_halt_reason { RISCV_HALT_INTERRUPT, RISCV_HALT_BREAKPOINT, RISCV_HALT_SINGLESTEP, + RISCV_HALT_TRIGGER, RISCV_HALT_UNKNOWN }; typedef struct { unsigned dtm_version; - riscv_reg_t misa; - struct command_context *cmd_ctx; void *version_specific; @@ -67,6 +66,7 @@ typedef struct { /* It's possible that each core has a different supported ISA set. */ int xlen[RISCV_MAX_HARTS]; + riscv_reg_t misa[RISCV_MAX_HARTS]; /* The number of triggers per hart. */ unsigned trigger_count[RISCV_MAX_HARTS]; @@ -110,7 +110,14 @@ typedef struct { void (*fill_dmi_read_u64)(struct target *target, char *buf, int a); void (*fill_dmi_nop_u64)(struct target *target, char *buf); + int (*authdata_read)(struct target *target, uint32_t *value); + int (*authdata_write)(struct target *target, uint32_t value); + + int (*dmi_read)(struct target *target, uint32_t *value, uint32_t address); + int (*dmi_write)(struct target *target, uint32_t address, uint32_t value); + int (*test_compliance)(struct target *target); + } riscv_info_t; /* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/ @@ -122,6 +129,8 @@ extern int riscv_reset_timeout_sec; extern bool riscv_use_scratch_ram; extern uint64_t riscv_scratch_ram_address; +extern bool riscv_prefer_sba; + /* Everything needs the RISC-V specific info structure, so here's a nice macro * that provides that. */ static inline riscv_info_t *riscv_info(const struct target *target) __attribute__((unused)); @@ -176,7 +185,7 @@ int riscv_resume_one_hart(struct target *target, int hartid); * then the only hart. */ int riscv_step_rtos_hart(struct target *target); -bool riscv_supports_extension(struct target *target, char letter); +bool riscv_supports_extension(struct target *target, int hartid, char letter); /* Returns XLEN for the given (or current) hart. */ int riscv_xlen(const struct target *target); @@ -218,11 +227,6 @@ int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value, bool riscv_is_halted(struct target *target); enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid); -/* Returns the number of triggers availiable to either the current hart or to - * the given hart. */ -int riscv_count_triggers(struct target *target); -int riscv_count_triggers_of_hart(struct target *target, int hartid); - /* These helper functions let the generic program interface get target-specific * information. */ size_t riscv_debug_buffer_size(struct target *target); diff --git a/src/target/startup.tcl b/src/target/startup.tcl index 9bbc6e32c..cf844e1f6 100644 --- a/src/target/startup.tcl +++ b/src/target/startup.tcl @@ -203,6 +203,7 @@ proc init_target_events {} { foreach t $targets { set_default_target_event $t gdb-flash-erase-start "reset init" set_default_target_event $t gdb-flash-write-end "reset halt" + set_default_target_event $t gdb-attach "halt" } } diff --git a/src/target/stm8.c b/src/target/stm8.c index 262497b0d..4556fd987 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -477,7 +477,8 @@ static int stm8_examine_debug_reason(struct target *target) uint8_t csr1, csr2; retval = stm8_read_dm_csrx(target, &csr1, &csr2); - LOG_DEBUG("csr1 = 0x%02X csr2 = 0x%02X", csr1, csr2); + if (retval == ERROR_OK) + LOG_DEBUG("csr1 = 0x%02X csr2 = 0x%02X", csr1, csr2); if ((target->debug_reason != DBG_REASON_DBGRQ) && (target->debug_reason != DBG_REASON_SINGLESTEP)) { diff --git a/src/target/target.c b/src/target/target.c index ce7782e3f..482dc74bd 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -54,6 +54,7 @@ #include "image.h" #include "rtos/rtos.h" #include "transport/transport.h" +#include "arm_cti.h" /* default halt wait timeout (ms) */ #define DEFAULT_HALT_TIMEOUT 5000 @@ -512,7 +513,9 @@ struct target *get_target_by_num(int num) struct target *get_current_target(struct command_context *cmd_ctx) { - struct target *target = get_target_by_num(cmd_ctx->current_target); + struct target *target = cmd_ctx->current_target_override + ? cmd_ctx->current_target_override + : cmd_ctx->current_target; if (target == NULL) { LOG_ERROR("BUG: current_target out of bounds"); @@ -810,8 +813,7 @@ done: } /** - * Downloads a target-specific native code algorithm to the target, - * executes and leaves it running. + * Executes a target-specific native code algorithm and leaves it running. * * @param target used to run the algorithm * @param arch_info target-specific description of the algorithm. @@ -884,12 +886,45 @@ done: } /** - * Executes a target-specific native code algorithm in the target. - * It differs from target_run_algorithm in that the algorithm is asynchronous. - * Because of this it requires an compliant algorithm: - * see contrib/loaders/flash/stm32f1x.S for example. + * Streams data to a circular buffer on target intended for consumption by code + * running asynchronously on target. + * + * This is intended for applications where target-specific native code runs + * on the target, receives data from the circular buffer, does something with + * it (most likely writing it to a flash memory), and advances the circular + * buffer pointer. + * + * This assumes that the helper algorithm has already been loaded to the target, + * but has not been started yet. Given memory and register parameters are passed + * to the algorithm. + * + * The buffer is defined by (buffer_start, buffer_size) arguments and has the + * following format: + * + * [buffer_start + 0, buffer_start + 4): + * Write Pointer address (aka head). Written and updated by this + * routine when new data is written to the circular buffer. + * [buffer_start + 4, buffer_start + 8): + * Read Pointer address (aka tail). Updated by code running on the + * target after it consumes data. + * [buffer_start + 8, buffer_start + buffer_size): + * Circular buffer contents. + * + * See contrib/loaders/flash/stm32f1x.S for an example. * * @param target used to run the algorithm + * @param buffer address on the host where data to be sent is located + * @param count number of blocks to send + * @param block_size size in bytes of each block + * @param num_mem_params count of memory-based params to pass to algorithm + * @param mem_params memory-based params to pass to algorithm + * @param num_reg_params count of register-based params to pass to algorithm + * @param reg_params memory-based params to pass to algorithm + * @param buffer_start address on the target of the circular buffer structure + * @param buffer_size size of the circular buffer structure + * @param entry_point address on the target to execute to start the algorithm + * @param exit_point address at which to set a breakpoint to catch the + * end of the algorithm; can be 0 if target triggers a breakpoint itself */ int target_run_flash_async_algorithm(struct target *target, @@ -1860,8 +1895,26 @@ static void target_destroy(struct target *target) if (target->type->deinit_target) target->type->deinit_target(target); + jtag_unregister_event_callback(jtag_enable_callback, target); + + struct target_event_action *teap = target->event_action; + while (teap) { + struct target_event_action *next = teap->next; + Jim_DecrRefCount(teap->interp, teap->body); + free(teap); + teap = next; + } + + target_free_all_working_areas(target); + /* Now we have none or only one working area marked as free */ + if (target->working_areas) { + free(target->working_areas->backup); + free(target->working_areas); + } + free(target->type); free(target->trace_info); + free(target->fileio_info); free(target->cmd_name); free(target); } @@ -2475,7 +2528,10 @@ static int find_target(struct command_context *cmd_ctx, const char *name) return ERROR_FAIL; } - cmd_ctx->current_target = target->target_number; + cmd_ctx->current_target = target; + if (cmd_ctx->current_target_override) + cmd_ctx->current_target_override = target; + return ERROR_OK; } @@ -2503,7 +2559,7 @@ COMMAND_HANDLER(handle_targets_command) else state = "tap-disabled"; - if (CMD_CTX->current_target == target->target_number) + if (CMD_CTX->current_target == target) marker = '*'; /* keep columns lined up to match the headers above */ @@ -2920,6 +2976,9 @@ COMMAND_HANDLER(handle_halt_command) LOG_DEBUG("-"); struct target *target = get_current_target(CMD_CTX); + + target->verbose_halt_msg = true; + int retval = target_halt(target); if (ERROR_OK != retval) return retval; @@ -4424,17 +4483,28 @@ void target_handle_event(struct target *target, enum target_event e) for (teap = target->event_action; teap != NULL; teap = teap->next) { if (teap->event == e) { - LOG_DEBUG("target: (%d) %s (%s) event: %d (%s) action: %s", + LOG_DEBUG("target(%d): %s (%s) event: %d (%s) action: %s", target->target_number, target_name(target), target_type_name(target), e, Jim_Nvp_value2name_simple(nvp_target_event, e)->name, Jim_GetString(teap->body, NULL)); + + /* Override current target by the target an event + * is issued from (lot of scripts need it). + * Return back to previous override as soon + * as the handler processing is done */ + struct command_context *cmd_ctx = current_command_context(teap->interp); + struct target *saved_target_override = cmd_ctx->current_target_override; + cmd_ctx->current_target_override = target; + if (Jim_EvalObj(teap->interp, teap->body) != JIM_OK) { Jim_MakeErrorMessage(teap->interp); command_print(NULL, "%s\n", Jim_GetString(Jim_GetResult(teap->interp), NULL)); } + + cmd_ctx->current_target_override = saved_target_override; } } } @@ -4464,7 +4534,6 @@ enum target_cfg_param { TCFG_COREID, TCFG_CHAIN_POSITION, TCFG_DBGBASE, - TCFG_CTIBASE, TCFG_RTOS, TCFG_DEFER_EXAMINE, }; @@ -4480,7 +4549,6 @@ static Jim_Nvp nvp_config_opts[] = { { .name = "-coreid", .value = TCFG_COREID }, { .name = "-chain-position", .value = TCFG_CHAIN_POSITION }, { .name = "-dbgbase", .value = TCFG_DBGBASE }, - { .name = "-ctibase", .value = TCFG_CTIBASE }, { .name = "-rtos", .value = TCFG_RTOS }, { .name = "-defer-examine", .value = TCFG_DEFER_EXAMINE }, { .name = NULL, .value = -1 } @@ -4717,6 +4785,13 @@ no_params: if (goi->isconfigure) { Jim_Obj *o_t; struct jtag_tap *tap; + + if (target->has_dap) { + Jim_SetResultString(goi->interp, + "target requires -dap parameter instead of -chain-position!", -1); + return JIM_ERR; + } + target_free_all_working_areas(target); e = Jim_GetOpt_Obj(goi, &o_t); if (e != JIM_OK) @@ -4724,8 +4799,8 @@ no_params: tap = jtag_tap_by_jim_obj(goi->interp, o_t); if (tap == NULL) return JIM_ERR; - /* make this exactly 1 or 0 */ target->tap = tap; + target->tap_configured = true; } else { if (goi->argc != 0) goto no_params; @@ -4747,20 +4822,6 @@ no_params: Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->dbgbase)); /* loop for more */ break; - case TCFG_CTIBASE: - if (goi->isconfigure) { - e = Jim_GetOpt_Wide(goi, &w); - if (e != JIM_OK) - return e; - target->ctibase = (uint32_t)w; - target->ctibase_set = true; - } else { - if (goi->argc != 0) - goto no_params; - } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->ctibase)); - /* loop for more */ - break; case TCFG_RTOS: /* RTOS */ { @@ -5512,7 +5573,7 @@ static int target_create(Jim_GetOptInfo *goi) target = calloc(1, sizeof(struct target)); /* set target number */ target->target_number = new_target_number(); - cmd_ctx->current_target = target->target_number; + cmd_ctx->current_target = target; /* allocate memory for each unique target type */ target->type = calloc(1, sizeof(struct target_type)); @@ -5538,7 +5599,7 @@ static int target_create(Jim_GetOptInfo *goi) target->next = NULL; target->arch_info = NULL; - target->display = 1; + target->verbose_halt_msg = true; target->halt_issued = false; @@ -5557,9 +5618,21 @@ static int target_create(Jim_GetOptInfo *goi) goi->isconfigure = 1; e = target_configure(goi, target); - if (target->tap == NULL) { - Jim_SetResultString(goi->interp, "-chain-position required when creating target", -1); - e = JIM_ERR; + if (e == JIM_OK) { + if (target->has_dap) { + if (!target->dap_configured) { + Jim_SetResultString(goi->interp, "-dap ?name? required when creating target", -1); + e = JIM_ERR; + } + } else { + if (!target->tap_configured) { + Jim_SetResultString(goi->interp, "-chain-position ?name? required when creating target", -1); + e = JIM_ERR; + } + } + /* tap must be set after target was configured */ + if (target->tap == NULL) + e = JIM_ERR; } if (e != JIM_OK) { @@ -5576,14 +5649,23 @@ static int target_create(Jim_GetOptInfo *goi) cp = Jim_GetString(new_cmd, NULL); target->cmd_name = strdup(cp); + if (target->type->target_create) { + e = (*(target->type->target_create))(target, goi->interp); + if (e != ERROR_OK) { + LOG_DEBUG("target_create failed"); + free(target->type); + free(target->cmd_name); + free(target); + return JIM_ERR; + } + } + /* create the target specific commands */ if (target->type->commands) { e = register_commands(cmd_ctx, NULL, target->type->commands); if (ERROR_OK != e) LOG_ERROR("unable to register '%s' commands", cp); } - if (target->type->target_create) - (*(target->type->target_create))(target, goi->interp); /* append to end of list */ { diff --git a/src/target/target.h b/src/target/target.h index 0096cae10..7a8a80f30 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -153,7 +153,7 @@ struct target { struct target_event_action *event_action; int reset_halt; /* attempt resetting the CPU into the halted mode? */ - uint32_t working_area; /* working area (initialised RAM). Evaluated + target_addr_t working_area; /* working area (initialised RAM). Evaluated * upon first allocation from virtual/physical address. */ bool working_area_virt_spec; /* virtual address specified? */ target_addr_t working_area_virt; /* virtual address */ @@ -176,20 +176,21 @@ struct target { void *private_config; /* pointer to target specific config data (for jim_configure hook) */ struct target *next; /* next target in list */ - int display; /* display async info in telnet session. Do not display + bool verbose_halt_msg; /* display async info in telnet session. Do not display * lots of halted/resumed info when stepping in debugger. */ bool halt_issued; /* did we transition to halted state? */ int64_t halt_issued_time; /* Note time when halt was issued */ + /* ARM v7/v8 targets with ADIv5 interface */ bool dbgbase_set; /* By default the debug base is not set */ uint32_t dbgbase; /* Really a Cortex-A specific option, but there is no * system in place to support target specific options * currently. */ + bool has_dap; /* set to true if target has ADIv5 support */ + bool dap_configured; /* set to true if ADIv5 DAP is configured */ + bool tap_configured; /* set to true if JTAG tap has been configured + * through -chain-position */ - bool ctibase_set; /* By default the debug base is not set */ - uint32_t ctibase; /* Really a Cortex-A specific option, but there is no - * system in place to support target specific options - * currently. */ struct rtos *rtos; /* Instance of Real Time Operating System support */ bool rtos_auto_detect; /* A flag that indicates that the RTOS has been specified as "auto" * and must be detected when symbols are offered */ diff --git a/src/transport/transport.h b/src/transport/transport.h index 6c57067a3..d0a77ddfb 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -19,6 +19,10 @@ #ifndef OPENOCD_TRANSPORT_TRANSPORT_H #define OPENOCD_TRANSPORT_TRANSPORT_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "helper/command.h" /** @@ -90,4 +94,19 @@ int allow_transports(struct command_context *ctx, const char * const *vector); bool transports_are_declared(void); +bool transport_is_jtag(void); +bool transport_is_swd(void); + +/* FIXME: ZY1000 test build on jenkins is configured with enabled hla adapters + * but jtag/hla/hla_*.c files are not compiled. To workaround the problem we assume hla + * is broken if BUILD_ZY1000 is set */ +#if BUILD_HLADAPTER && !BUILD_ZY1000 +bool transport_is_hla(void); +#else +static inline bool transport_is_hla(void) +{ + return false; +} +#endif + #endif /* OPENOCD_TRANSPORT_TRANSPORT_H */ diff --git a/tcl/board/avnet_ultrazed-eg.cfg b/tcl/board/avnet_ultrazed-eg.cfg new file mode 100644 index 000000000..a0ac5c6a7 --- /dev/null +++ b/tcl/board/avnet_ultrazed-eg.cfg @@ -0,0 +1,16 @@ +# +# AVNET UltraZED EG StarterKit +# UlraScale-EG plus IO Carrier with on-board digilent smt2 +# +source [find interface/ftdi/digilent_jtag_smt2_nc.cfg] +# jtag transport only +transport select jtag +# reset lines are not wired +reset_config none + +# slow default clock +adapter_khz 1000 + +set CHIPNAME uscale + +source [find target/xilinx_ultrascale.cfg] diff --git a/tcl/board/kasli.cfg b/tcl/board/kasli.cfg new file mode 100644 index 000000000..2c5e26853 --- /dev/null +++ b/tcl/board/kasli.cfg @@ -0,0 +1,15 @@ +interface ftdi +ftdi_device_desc "Quad RS232-HS" +ftdi_vid_pid 0x0403 0x6011 +ftdi_channel 0 +ftdi_layout_init 0x0008 0x000b +# ftdi_location 1:8 + +reset_config none +transport select jtag +adapter_khz 25000 + +source [find cpld/xilinx-xc7.cfg] +source [find cpld/jtagspi.cfg] +source [find fpga/xilinx-xadc.cfg] +source [find fpga/xilinx-dna.cfg] diff --git a/tcl/board/kc705.cfg b/tcl/board/kc705.cfg index 39f7fa39c..e032e9b21 100644 --- a/tcl/board/kc705.cfg +++ b/tcl/board/kc705.cfg @@ -3,6 +3,8 @@ source [find interface/ftdi/digilent-hs1.cfg] source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] +source [find fpga/xilinx-xadc.cfg] +source [find fpga/xilinx-dna.cfg] adapter_khz 25000 # example command to write bitstream, soft-cpu bios and runtime: diff --git a/tcl/board/kcu105.cfg b/tcl/board/kcu105.cfg new file mode 100644 index 000000000..c8daea652 --- /dev/null +++ b/tcl/board/kcu105.cfg @@ -0,0 +1,11 @@ +# xilinx ultrascale +# http://www.xilinx.com/support/documentation/user_guides/ug570-ultrascale-configuration.pdf + +source [find interface/ftdi/digilent_jtag_smt2_nc.cfg] + +set CHIP XCKU040 +source [find cpld/xilinx-xcu.cfg] + +source [find cpld/jtagspi.cfg] + +adapter_khz 25000 diff --git a/tcl/board/sayma_amc.cfg b/tcl/board/sayma_amc.cfg new file mode 100644 index 000000000..5d338ed8a --- /dev/null +++ b/tcl/board/sayma_amc.cfg @@ -0,0 +1,45 @@ +# Sayma AMC is an FPGA board for the µTCA AMC format +# The board is open hardware (CERN OHL) and the gateware and software +# running on it are open source (ARTIQ, LGPLv3+). +# +# https://github.com/m-labs/sinara/wiki/Sayma +# +# It contains a Xilinx Kintex Ultrascale 040 FPGA (xcku040). +# There is a SCANSTA112SM JTAG router on the board which is configured to +# automatically add devices to the JTAG svcan chain when they are added. +# Sayma AMC is usually combined with Sayma RTM (rear transition module) +# which features an Artix 7 FPGA. + +interface ftdi +ftdi_device_desc "Quad RS232-HS" +ftdi_vid_pid 0x0403 0x6011 +ftdi_channel 0 +# Use this to distinguish multiple boards by topology +#ftdi_location 5:1 +# sampling on falling edge generally seems to work and accelerates things but +# is not fully tested +#ftdi_tdo_sample_edge falling +# EN_USB_JTAG on ADBUS7: out, high +# USB_nTRST on ADBUS4: out, high, but R46 is DNP +ftdi_layout_init 0x0098 0x008b +#ftdi_layout_signal EN_USB -data 0x0080 +#ftdi_layout_signal nTRST -data 0x0010 +reset_config none + +adapter_khz 5000 + +transport select jtag + +# Add the RTM Artix to the chain. Note that this changes the PLD numbering. +# Unfortunately openocd TAPs can't be disabled after they have been added and +# before `init`. +#source [find cpld/xilinx-xc7.cfg] + +set CHIP XCKU040 +source [find cpld/xilinx-xcu.cfg] + +set XILINX_USER1 0x02 +set XILINX_USER2 0x03 +set JTAGSPI_IR $XILINX_USER1 +source [find cpld/jtagspi.cfg] +flash bank xcu.spi1 jtagspi 0 0 0 0 xcu.proxy $XILINX_USER2 diff --git a/tcl/board/steval-idb007v1.cfg b/tcl/board/steval-idb007v1.cfg new file mode 100644 index 000000000..24dbd1e9c --- /dev/null +++ b/tcl/board/steval-idb007v1.cfg @@ -0,0 +1,4 @@ +# This is an evaluation board with a single BlueNRG-1 chip. +# http://www.st.com/content/st_com/en/products/evaluation-tools/solution-evaluation-tools/communication-and-connectivity-solution-eval-boards/steval-idb008v1.html +set CHIPNAME bluenrg-1 +source [find target/bluenrg-x.cfg] diff --git a/tcl/board/steval-idb008v1.cfg b/tcl/board/steval-idb008v1.cfg new file mode 100644 index 000000000..3e9d0e5ee --- /dev/null +++ b/tcl/board/steval-idb008v1.cfg @@ -0,0 +1,4 @@ +# This is an evaluation board with a single BlueNRG-2 chip. +# http://www.st.com/content/st_com/en/products/evaluation-tools/solution-evaluation-tools/communication-and-connectivity-solution-eval-boards/steval-idb007v1.html +set CHIPNAME bluenrg-2 +source [find target/bluenrg-x.cfg] diff --git a/tcl/cpld/xilinx-xcu.cfg b/tcl/cpld/xilinx-xcu.cfg new file mode 100644 index 000000000..327059711 --- /dev/null +++ b/tcl/cpld/xilinx-xcu.cfg @@ -0,0 +1,72 @@ +# Xilinx Ultrascale (Kintex, Virtex, Zynq) +# https://www.xilinx.com/support/documentation/user_guides/ug570-ultrascale-configuration.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xcu +} + +# The cvarious chips in the Ultrascale family have different IR length. +# Set $CHIP before including this file to determine the device. +array set _XCU_DATA { + XCKU025 {0x03824093 6} + XCKU035 {0x03823093 6} + XCKU040 {0x03822093 6} + XCKU060 {0x03919093 6} + XCKU095 {0x03844093 6} + XCKU3P {0x04A63093 6} + XCKU5P {0x04A62093 6} + XCKU9P {0x0484A093 6} + XCKU11P {0x04A4E093 6} + XCKU13P {0x04A52093 6} + XCKU15P {0x04A56093 6} + XCVU065 {0x03939093 6} + XCVU080 {0x03843093 6} + XCVU095 {0x03842093 6} + XCVU3P {0x04B39093 6} + XCKU085 {0x0380F093 12} + XCKU115 {0x0390D093 12} + XCVU125 {0x0392D093 12} + XCVU5P {0x04B2B093 12} + XCVU7P {0x04B29093 12} + XCVU160 {0x03933093 18} + XCVU190 {0x03931093 18} + XCVU440 {0x0396D093 18} + XCVU9P {0x04B31093 18} + XCVU11P {0x04B49093 18} + XCVU13P {0x04B51093 24} +} + +if { ![info exists CHIP] } { + error "set CHIP to one of "[concat [array names _XCU_DATA]] +} + +if { ![llength [array names _XCU_DATA $CHIP]] } { + error "unknown CHIP: "$CHIP +} + +set _EXPID [lindex $_XCU_DATA($CHIP) 0] +set _IRLEN [lindex $_XCU_DATA($CHIP) 1] + +# the 4 top bits (28:31) are the die stepping/revisions. ignore it. +jtag newtap $_CHIPNAME tap -irlen $_IRLEN -ignore-version -expected-id $_EXPID + +pld device virtex2 $_CHIPNAME.tap 1 + +set XCU_JSHUTDOWN 0x0d +set XCU_JPROGRAM 0x0b +set XCU_JSTART 0x0c +set XCU_BYPASS 0x3f + +proc xcu_program {tap} { + global XCU_JSHUTDOWN XCU_JPROGRAM XCU_JSTART XCU_BYPASS + irscan $tap $XCU_JSHUTDOWN + irscan $tap $XCU_JPROGRAM + runtest 60000 + #JSTART prevents this from working... + #irscan $tap $XCU_JSTART + runtest 2000 + irscan $tap $XCU_BYPASS + runtest 2000 +} diff --git a/tcl/fpga/xilinx-dna.cfg b/tcl/fpga/xilinx-dna.cfg new file mode 100644 index 000000000..a1d5ba376 --- /dev/null +++ b/tcl/fpga/xilinx-dna.cfg @@ -0,0 +1,43 @@ +proc xilinx_dna_addr {chip} { + array set addrs { + Spartan6 0x30 + Series7 0x17 + } + return $addrs($chip) +} + +# Get the "Device DNA". +# Most Xilinx FPGA devices contain an embedded, unique device identifier. +# The identifier is nonvolatile, permanently programmed into +# the FPGA, and is unchangeable providing a great serial / tracking number. +# This function returns the DNA as a 64 bit integer with the 7 LSBs zeroed. +# This is compatible with the FUSE DNA which contains all 64 bits. +proc xilinx_get_dna {tap chip} { + set XC7_ISC_ENABLE 0x10 + set XC7_ISC_DISABLE 0x16 + set XC7_ISC_DNA [xilinx_dna_addr $chip] + + irscan $tap $XC7_ISC_ENABLE + runtest 64 + irscan $tap $XC7_ISC_DNA + scan [drscan $tap 32 0 32 0] "%08x %08x" hi lo + runtest 64 + irscan $tap $XC7_ISC_DISABLE + runtest 64 + # openocd interprets DR scans as LSB first, bit-reverse it + return [scan [string reverse [format "%032b%032bb0" $lo $hi]] "%i"] +} + +# Print out the "Device DNA" in the same format that impact uses. +proc xilinx_print_dna {dna} { + set dna [expr $dna >> 64 - 57] + echo [format "DNA = %057b (0x%016x)" $dna $dna] +} + +proc xc7_get_dna {tap} { + return [xilinx_get_dna $tap Series7] +} + +proc xc6s_get_dna {tap} { + return [xilinx_get_dna $tap Spartan6] +} diff --git a/tcl/fpga/xilinx-xadc.cfg b/tcl/fpga/xilinx-xadc.cfg new file mode 100644 index 000000000..38691045c --- /dev/null +++ b/tcl/fpga/xilinx-xadc.cfg @@ -0,0 +1,159 @@ +# Xilinx XADC support for 7 Series FPGAs +# +# The 7 Series FPGAs contain an on-chip 12 bit ADC that can probe die +# temperature, internal power supply rail voltages as well as external +# voltages. The XADC is available both from fabric as well as through the +# JTAG TAP. +# +# This code implements access throught the JTAG TAP. +# +# https://www.xilinx.com/support/documentation/user_guides/ug480_7Series_XADC.pdf + +# build a 32 bit DRP command for the XADC DR +proc xadc_cmd {cmd addr data} { + array set cmds { + NOP 0x00 + READ 0x01 + WRITE 0x02 + } + return [expr ($cmds($cmd) << 26) | ($addr << 16) | ($data << 0)] +} + +# XADC register addresses +# Some addresses (status registers 0-3) have special function when written to. +proc XADC {key} { + array set addrs { + TEMP 0x00 + LOCK 0x00 + VCCINT 0x01 + VCCAUX 0x02 + VAUXEN 0x02 + VPVN 0x03 + RESET 0x03 + VREFP 0x04 + VREFN 0x05 + VCCBRAM 0x06 + SUPAOFFS 0x08 + ADCAOFFS 0x09 + ADCAGAIN 0x0a + VCCPINT 0x0d + VCCPAUX 0x0e + VCCODDR 0x0f + VAUX0 0x10 + VAUX1 0x11 + VAUX2 0x12 + VAUX3 0x13 + VAUX4 0x14 + VAUX5 0x15 + VAUX6 0x16 + VAUX7 0x17 + VAUX8 0x18 + VAUX9 0x19 + VAUX10 0x1a + VAUX11 0x1b + VAUX12 0x1c + VAUX13 0x1d + VAUX14 0x1e + VAUX15 0x1f + SUPBOFFS 0x30 + ADCBOFFS 0x31 + ADCBGAIN 0x32 + FLAG 0x3f + CFG0 0x40 + CFG1 0x41 + CFG2 0x42 + SEQ0 0x48 + SEQ1 0x49 + SEQ2 0x4a + SEQ3 0x4b + SEQ4 0x4c + SEQ5 0x4d + SEQ6 0x4e + SEQ7 0x4f + ALARM0 0x50 + ALARM1 0x51 + ALARM2 0x52 + ALARM3 0x53 + ALARM4 0x54 + ALARM5 0x55 + ALARM6 0x56 + ALARM7 0x57 + ALARM8 0x58 + ALARM9 0x59 + ALARM10 0x5a + ALARM11 0x5b + ALARM12 0x5c + ALARM13 0x5d + ALARM14 0x5e + ALARM15 0x5f + } + return $addrs($key) +} + +# Select the XADC DR +proc xadc_select {tap} { + set XADC_IR 0x37 + irscan $tap $XADC_IR + runtest 10 +} + +# XADC transfer +proc xadc_xfer {tap cmd addr data} { + set ret [drscan $tap 32 [xadc_cmd $cmd $addr $data]] + runtest 10 + return [expr 0x$ret] +} + +# XADC register write +proc xadc_write {tap addr data} { + xadc_xfer $tap WRITE $addr $data +} + +# XADC register read, non-pipelined +proc xadc_read {tap addr} { + xadc_xfer $tap READ $addr 0 + return [xadc_xfer $tap NOP 0 0] +} + +# convert 16 bit register code from ADC measurement on +# external voltages (VAUX) to Volt +proc xadc_volt {code} { + return [expr $code * 1./(1 << 16)] +} + +# convert 16 bit temperature measurement to Celsius +proc xadc_temp {code} { + return [expr $code * 503.975/(1 << 16) - 273.15] +} + +# convert 16 bit suppply voltage measurement to Volt +proc xadc_sup {code} { + return [expr $code * 3./(1 << 16)] +} + +# perform a single channel measurement using default settings +proc xadc_single {tap ch} { + set cfg0 [xadc_read $tap [XADC CFG0]] + set cfg1 [xadc_read $tap [XADC CFG1]] + # set channel + xadc_write $tap [XADC CFG0] $cfg0 + # single channel, disable the sequencer + xadc_write $tap [XADC CFG1] 0x3000 + # leave some time for the conversion + runtest 100 + set ret [xadc_read $tap [XADC $ch]] + # restore CFG0/1 + xadc_write $tap [XADC CFG0] $cfg0 + xadc_write $tap [XADC CFG1] $cfg1 + return $ret +} + +# measure all internal voltages +proc xadc_report {tap} { + xadc_select $tap + echo "TEMP [format %.2f [xadc_temp [xadc_single $tap TEMP]]] C" + foreach ch [list VCCINT VCCAUX VCCBRAM VPVN VREFP VREFN \ + VCCPINT VCCPAUX VCCODDR] { + echo "$ch [format %.3f [xadc_sup [xadc_single $tap $ch]]] V" + } +} diff --git a/tcl/interface/altera-usb-blaster.cfg b/tcl/interface/altera-usb-blaster.cfg index f19abfebe..1bfef9dc4 100644 --- a/tcl/interface/altera-usb-blaster.cfg +++ b/tcl/interface/altera-usb-blaster.cfg @@ -5,6 +5,7 @@ # interface usb_blaster +usb_blaster_lowlevel_driver ftdi # These are already the defaults. # usb_blaster_vid_pid 0x09FB 0x6001 # usb_blaster_device_desc "USB-Blaster" diff --git a/tcl/interface/buspirate.cfg b/tcl/interface/buspirate.cfg index 2b68538bf..c2f3a83c4 100644 --- a/tcl/interface/buspirate.cfg +++ b/tcl/interface/buspirate.cfg @@ -15,7 +15,7 @@ buspirate_speed normal ;# or fast # voltage regulator Enabled = 1 Disabled = 0 #buspirate_vreg 0 -# pin mode normal or open-drain +# pin mode normal or open-drain (jtag only) #buspirate_mode normal # pullup state Enabled = 1 Disabled = 0 diff --git a/tcl/interface/ft232r.cfg b/tcl/interface/ft232r.cfg new file mode 100644 index 000000000..b4f71c8d4 --- /dev/null +++ b/tcl/interface/ft232r.cfg @@ -0,0 +1,2 @@ +interface ft232r +adapter_khz 1000 diff --git a/tcl/interface/ftdi/pipistrello.cfg b/tcl/interface/ftdi/pipistrello.cfg index b51405a2d..5ee5be5bb 100644 --- a/tcl/interface/ftdi/pipistrello.cfg +++ b/tcl/interface/ftdi/pipistrello.cfg @@ -10,4 +10,4 @@ ftdi_layout_init 0x0008 0x000b reset_config none # this generally works fast: the fpga can handle 30MHz, the spi flash can handle # 54MHz with simple read, no dummy cycles, and wait-for-write-completion -adapter_khz 30000 +adapter_khz 10000 diff --git a/tcl/target/1986Be1T.cfg b/tcl/target/1986Be1T.cfg index 7b0c35f08..ecb3f8ae1 100644 --- a/tcl/target/1986Be1T.cfg +++ b/tcl/target/1986Be1T.cfg @@ -34,9 +34,10 @@ if { [info exists CPUTAPID] } { } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # use AHB-Lite SRAM for work area $_TARGETNAME configure -work-area-phys 0x20100000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/adsp-sc58x.cfg b/tcl/target/adsp-sc58x.cfg index 369137ed9..e2b695215 100644 --- a/tcl/target/adsp-sc58x.cfg +++ b/tcl/target/adsp-sc58x.cfg @@ -27,9 +27,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_a -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_a -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -event examine-end { global _TARGETNAME diff --git a/tcl/target/aducm360.cfg b/tcl/target/aducm360.cfg index 785c18c59..ca4bc68de 100755 --- a/tcl/target/aducm360.cfg +++ b/tcl/target/aducm360.cfg @@ -32,7 +32,8 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x2ba01477 } -swd newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # SWD/JTAG speed adapter_khz 1000 @@ -41,7 +42,7 @@ adapter_khz 1000 ## Target configuration ## set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # allocate the working area $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/altera_fpgasoc.cfg b/tcl/target/altera_fpgasoc.cfg index 25fe1f493..1fbc5a375 100644 --- a/tcl/target/altera_fpgasoc.cfg +++ b/tcl/target/altera_fpgasoc.cfg @@ -14,7 +14,7 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x4ba00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x01 -irmask 0x0f \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID # Subsidiary TAP: fpga @@ -42,7 +42,8 @@ set _TARGETNAME1 $_CHIPNAME.cpu.0 set _TARGETNAME2 $_CHIPNAME.cpu.1 # A9 core 0 -target create $_TARGETNAME1 cortex_a -chain-position $_CHIPNAME.dap \ +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME1 cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x80110000 $_TARGETNAME1 configure -event reset-start { adapter_khz 1000 } @@ -51,7 +52,7 @@ $_TARGETNAME1 configure -event gdb-attach { halt } # A9 core 1 -#target create $_TARGETNAME2 cortex_a -chain-position $_CHIPNAME.dap \ +#target create $_TARGETNAME2 cortex_a -dap $_CHIPNAME.dap \ # -coreid 1 -dbgbase 0x80112000 #$_TARGETNAME2 configure -event reset-start { adapter_khz 1000 } diff --git a/tcl/target/am335x.cfg b/tcl/target/am335x.cfg index 3ca196b11..02d8c7e82 100644 --- a/tcl/target/am335x.cfg +++ b/tcl/target/am335x.cfg @@ -12,7 +12,7 @@ if { [info exists CHIPNAME] } { if { [info exists DEFAULT_TAPS] } { set _DEFAULT_TAPS "$DEFAULT_TAPS" } else { - set _DEFAULT_TAPS "$_CHIPNAME.dap" + set _DEFAULT_TAPS "$_CHIPNAME.tap" } # @@ -23,8 +23,9 @@ if { [info exists DAP_TAPID] } { } else { set _DAP_TAPID 0x4b6b902f } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable -jtag configure $_CHIPNAME.dap -event tap-enable "icepick_d_tapenable $_CHIPNAME.jrc 12 0" +jtag newtap $_CHIPNAME tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable +jtag configure $_CHIPNAME.tap -event tap-enable "icepick_d_tapenable $_CHIPNAME.jrc 12 0" +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap # # M3 DAP @@ -34,8 +35,9 @@ if { [info exists M3_DAP_TAPID] } { } else { set _M3_DAP_TAPID 0x4b6b902f } -jtag newtap $_CHIPNAME m3_dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_M3_DAP_TAPID -disable -jtag configure $_CHIPNAME.m3_dap -event tap-enable "icepick_d_tapenable $_CHIPNAME.jrc 11 0" +jtag newtap $_CHIPNAME m3_tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_M3_DAP_TAPID -disable +jtag configure $_CHIPNAME.m3_tap -event tap-enable "icepick_d_tapenable $_CHIPNAME.jrc 11 0" +dap create $_CHIPNAME.m3_dap -chain-position $_CHIPNAME.m3_tap # # ICEpick-D (JTAG route controller) @@ -66,13 +68,13 @@ proc enable_default_taps { taps } { # Cortex-M3 target # set _TARGETNAME_2 $_CHIPNAME.m3 -target create $_TARGETNAME_2 cortex_m -chain-position $_CHIPNAME.m3_dap +target create $_TARGETNAME_2 cortex_m -dap $_CHIPNAME.m3_dap # # Cortex-A8 target # set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap -dbgbase 0x80001000 +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap -dbgbase 0x80001000 # SRAM: 64K at 0x4030.0000; use the first 16K $_TARGETNAME configure -work-area-phys 0x40300000 -work-area-size 0x4000 diff --git a/tcl/target/am437x.cfg b/tcl/target/am437x.cfg index fe0ffff29..8ce0941df 100644 --- a/tcl/target/am437x.cfg +++ b/tcl/target/am437x.cfg @@ -458,6 +458,7 @@ if { [info exists M3_DAP_TAPID] } { } jtag newtap $_CHIPNAME $M3_MODULE -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_M3_DAP_TAPID -disable jtag configure $M3_NAME -event tap-enable "icepick_d_tapenable $JRC_NAME 11 0" +dap create $M3_NAME.dap -chain-position $M3_NAME # # DebugSS DAP @@ -469,6 +470,7 @@ if { [info exists DAP_TAPID] } { } jtag newtap $_CHIPNAME $DEBUGSS_MODULE -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable jtag configure $DEBUGSS_NAME -event tap-enable "icepick_d_tapenable $JRC_NAME 12 0" +dap create $DEBUGSS_NAME.dap -chain-position $DEBUGSS_NAME # # ICEpick-D (JTAG route controller) @@ -486,7 +488,7 @@ jtag configure $JRC_NAME -event post-reset "runtest 100" # # Cortex-A9 target # -target create $_TARGETNAME cortex_a -chain-position $DEBUGSS_NAME -coreid 0 -dbgbase 0x80000000 +target create $_TARGETNAME cortex_a -dap $DEBUGSS_NAME.dap -coreid 0 -dbgbase 0x80000000 # SRAM: 256K at 0x4030.0000 diff --git a/tcl/target/amdm37x.cfg b/tcl/target/amdm37x.cfg index c00dae921..5c4e3151d 100644 --- a/tcl/target/amdm37x.cfg +++ b/tcl/target/amdm37x.cfg @@ -86,8 +86,8 @@ source [find target/icepick.cfg] # Secondary TAP: DAP is closest to the TDO output # The TAP enable event also needs to be described -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -disable -jtag configure $_CHIPNAME.dap -event tap-enable \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -disable +jtag configure $_CHIPNAME.cpu -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 3" # These taps are only present in the DM37x series. @@ -141,7 +141,8 @@ jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.dap" # Create the CPU target to be used with GDB: Cortex-A8, using DAP set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap # The DM37x has 64K of SRAM starting at address 0x4020_0000. Allow the first # 16K to be used as a scratchpad for OpenOCD. diff --git a/tcl/target/armada370.cfg b/tcl/target/armada370.cfg index 40c779bdc..5b84637a2 100644 --- a/tcl/target/armada370.cfg +++ b/tcl/target/armada370.cfg @@ -16,10 +16,11 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x4ba00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap proc armada370_dbginit {target} { cortex_a dbginit diff --git a/tcl/target/at91sam3XXX.cfg b/tcl/target/at91sam3XXX.cfg index fca655d2c..e7dec4b3e 100644 --- a/tcl/target/at91sam3XXX.cfg +++ b/tcl/target/at91sam3XXX.cfg @@ -55,9 +55,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # 16K is plenty, the smallest chip has this much $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/at91sam3nXX.cfg b/tcl/target/at91sam3nXX.cfg index 19bd33a9e..3450c2626 100644 --- a/tcl/target/at91sam3nXX.cfg +++ b/tcl/target/at91sam3nXX.cfg @@ -18,9 +18,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian little -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap set _FLASHNAME $_CHIPNAME.flash flash bank flash0 at91sam3 0x00400000 0 0 0 $_TARGETNAME diff --git a/tcl/target/at91sam4XXX.cfg b/tcl/target/at91sam4XXX.cfg index ca801431a..ff7367040 100644 --- a/tcl/target/at91sam4XXX.cfg +++ b/tcl/target/at91sam4XXX.cfg @@ -35,9 +35,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # 16K is plenty, the smallest chip has this much $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/at91samdXX.cfg b/tcl/target/at91samdXX.cfg index 93a95c8eb..f0644d177 100644 --- a/tcl/target/at91samdXX.cfg +++ b/tcl/target/at91samdXX.cfg @@ -34,9 +34,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/atsamv.cfg b/tcl/target/atsamv.cfg index b6c484237..d1f8454d5 100644 --- a/tcl/target/atsamv.cfg +++ b/tcl/target/atsamv.cfg @@ -32,9 +32,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20400000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/bcm281xx.cfg b/tcl/target/bcm281xx.cfg index 224af7933..6432a2092 100644 --- a/tcl/target/bcm281xx.cfg +++ b/tcl/target/bcm281xx.cfg @@ -14,15 +14,17 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x4ba00477 } -jtag newtap $_CHIPNAME dap -expected-id $_DAP_TAPID -irlen 4 +jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 # Dual Cortex-A9 set _TARGETNAME0 $_CHIPNAME.cpu0 set _TARGETNAME1 $_CHIPNAME.cpu1 -target create $_TARGETNAME0 cortex_a -chain-position $_CHIPNAME.dap -coreid 0 -dbgbase 0x3fe10000 -target create $_TARGETNAME1 cortex_a -chain-position $_CHIPNAME.dap -coreid 1 -dbgbase 0x3fe12000 +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +target create $_TARGETNAME0 cortex_a -dap $_CHIPNAME.dap -coreid 0 -dbgbase 0x3fe10000 +target create $_TARGETNAME1 cortex_a -dap $_CHIPNAME.dap -coreid 1 -dbgbase 0x3fe12000 target smp $_TARGETNAME0 $_TARGETNAME1 $_TARGETNAME0 configure -event gdb-attach { diff --git a/tcl/target/bluenrg-x.cfg b/tcl/target/bluenrg-x.cfg new file mode 100644 index 000000000..b0dd61ae9 --- /dev/null +++ b/tcl/target/bluenrg-x.cfg @@ -0,0 +1,74 @@ +# +# bluenrg-1/2 devices support only SWD transports. +# + +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME bluenrg-1 +} + +set _ENDIAN little + +# Work-area is a space in RAM used for flash programming +# By default use 24kB-256bytes +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x5F00 +} + +adapter_khz 4000 + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x0bb11477 +} + +swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +set _TARGETNAME $_CHIPNAME.cpu +set WDOG_VALUE 0 +set WDOG_VALUE_SET 0 + +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x20000100 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +# flash size will be probed +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME bluenrg-x 0 0 0 0 $_TARGETNAME + +# In BlueNRG-X reset pin is actually a shutdown (power-off), so define reset as none +reset_config none + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +} + +$_TARGETNAME configure -event halted { + global WDOG_VALUE + global WDOG_VALUE_SET + # Stop watchdog during halt, if enabled + mem2array value 32 0x40700008 1 + set WDOG_VALUE [expr ($value(0))] + if [expr ($value(0) & (1 << 1))] { + set WDOG_VALUE_SET 1 + mww 0x40700008 [expr ($value(0) & 0xFFFFFFFD)] + } +} +$_TARGETNAME configure -event resumed { + global WDOG_VALUE + global WDOG_VALUE_SET + if [expr $WDOG_VALUE_SET] { + # Restore watchdog enable value after resume + mww 0x40700008 $WDOG_VALUE + set WDOG_VALUE_SET 0 + } +} diff --git a/tcl/target/cc26xx.cfg b/tcl/target/cc26xx.cfg index 1492e6a22..c3ac8470a 100755 --- a/tcl/target/cc26xx.cfg +++ b/tcl/target/cc26xx.cfg @@ -19,8 +19,8 @@ if { [info exists DAP_TAPID] } { } else { set _DAP_TAPID 0x4BA00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable -jtag configure $_CHIPNAME.dap -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable +jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" # # ICEpick-C (JTAG route controller) @@ -33,11 +33,12 @@ if { [info exists JRC_TAPID] } { jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version # A start sequence is needed to change from cJTAG (Compact JTAG) to # 4-pin JTAG before talking via JTAG commands -jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.dap" +jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.cpu" jtag configure $_CHIPNAME.jrc -event post-reset "ti_cjtag_to_4pin_jtag $_CHIPNAME.jrc" # # Cortex-M3 target # set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.dap +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap diff --git a/tcl/target/cc32xx.cfg b/tcl/target/cc32xx.cfg index 154bf9106..dfc4c17a8 100755 --- a/tcl/target/cc32xx.cfg +++ b/tcl/target/cc32xx.cfg @@ -26,10 +26,10 @@ if { [info exists DAP_TAPID] } { } if {[using_jtag]} { - jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable - jtag configure $_CHIPNAME.dap -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" + jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable + jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" } else { - swj_newdap $_CHIPNAME dap -expected-id $_DAP_TAPID + swj_newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID } # @@ -50,4 +50,5 @@ if {[using_jtag]} { # Cortex-M3 target # set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.dap +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap diff --git a/tcl/target/efm32.cfg b/tcl/target/efm32.cfg index 33610d5a8..e22ce5cba 100644 --- a/tcl/target/efm32.cfg +++ b/tcl/target/efm32.cfg @@ -1,5 +1,8 @@ # -# efm32 target +# Silicon Labs (formerly Energy Micro) EFM32 target +# +# Note: All EFM32 chips have SWD support, but only newer series 1 +# chips have JTAG support. # source [find target/swj-dp.tcl] @@ -21,15 +24,20 @@ if { [info exists WORKAREASIZE] } { if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { - set _CPUTAPID 0x2ba01477 + if { [using_jtag] } { + set _CPUTAPID 0x4ba00477 + } { + set _CPUTAPID 0x2ba01477 + } } -swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu adapter_khz 1000 set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x10000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/em357.cfg b/tcl/target/em357.cfg index 24ffb04f9..572007134 100644 --- a/tcl/target/em357.cfg +++ b/tcl/target/em357.cfg @@ -50,12 +50,13 @@ if { [info exists FLASHSIZE] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if { [using_jtag] } { swj_newdap $_CHIPNAME bs -irlen 4 -expected-id $_BSTAPID -ircapture 0xe -irmask 0xf } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian little -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/exynos5250.cfg b/tcl/target/exynos5250.cfg index 36783410b..d3aaa986d 100644 --- a/tcl/target/exynos5250.cfg +++ b/tcl/target/exynos5250.cfg @@ -17,7 +17,8 @@ if { [info exists CPUTAPID] } { jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu -target create ${_TARGETNAME}0 cortex_a -chain-position $_TARGETNAME -target create ${_TARGETNAME}1 cortex_a -chain-position $_TARGETNAME +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create ${_TARGETNAME}0 cortex_a -dap $_CHIPNAME.dap +target create ${_TARGETNAME}1 cortex_a -dap $_CHIPNAME.dap target smp ${_TARGETNAME}0 ${_TARGETNAME}1 diff --git a/tcl/target/fm3.cfg b/tcl/target/fm3.cfg index 78bbc945c..a0610ce17 100644 --- a/tcl/target/fm3.cfg +++ b/tcl/target/fm3.cfg @@ -31,9 +31,10 @@ if {[using_jtag]} { reset_config trst_only swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # MB9BF506 has 64kB of SRAM on its main system bus $_TARGETNAME configure -work-area-phys 0x1FFF8000 -work-area-size 0x10000 -work-area-backup 0 diff --git a/tcl/target/fm4.cfg b/tcl/target/fm4.cfg index e5d0f8d60..b79634d96 100644 --- a/tcl/target/fm4.cfg +++ b/tcl/target/fm4.cfg @@ -19,9 +19,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian little -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap adapter_khz 500 diff --git a/tcl/target/hi3798.cfg b/tcl/target/hi3798.cfg index 9eda15035..aa811d44d 100644 --- a/tcl/target/hi3798.cfg +++ b/tcl/target/hi3798.cfg @@ -16,8 +16,8 @@ if { [info exists DAP_TAPID] } { } # declare the one JTAG tap to access the DAP -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable - +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # declare the 4 main application cores set _TARGETNAME $_CHIPNAME.cpu set _smp_command "" @@ -30,8 +30,10 @@ set $_TARGETNAME.cti(3) 0x80320000 set _cores 4 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { + cti create cti$_core -dap $_CHIPNAME.dap -ctibase [set $_TARGETNAME.cti($_core)] -ap-num 0 + set _command "target create ${_TARGETNAME}$_core aarch64 \ - -chain-position $_CHIPNAME.dap -coreid $_core -ctibase [set $_TARGETNAME.cti($_core)]" + -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core" if { $_core != 0 } { # non-boot core examination may fail diff --git a/tcl/target/hi6220.cfg b/tcl/target/hi6220.cfg index 7daa3c118..c2feb0b36 100644 --- a/tcl/target/hi6220.cfg +++ b/tcl/target/hi6220.cfg @@ -16,7 +16,10 @@ if { [info exists DAP_TAPID] } { } # declare the one JTAG tap to access the DAP -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable +jtag newtap $_CHIPNAME tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version + +# create the DAP +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap # declare the 8 main application cores set _TARGETNAME $_CHIPNAME.cpu @@ -34,8 +37,10 @@ set $_TARGETNAME.cti(7) 0x801DB000 set _cores 8 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { + cti create cti$_core -dap $_CHIPNAME.dap -ctibase [set $_TARGETNAME.cti($_core)] -ap-num 0 + set _command "target create ${_TARGETNAME}$_core aarch64 \ - -chain-position $_CHIPNAME.dap -coreid $_core -ctibase [set $_TARGETNAME.cti($_core)]" + -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core" if { $_core != 0 } { # non-boot core examination may fail @@ -52,5 +57,10 @@ for { set _core 0 } { $_core < $_cores } { incr _core 1 } { eval $_smp_command +cti create cti.sys -dap $_CHIPNAME.dap -ap-num 0 -ctibase 0x80003000 + # declare the auxiliary Cortex-M3 core on AP #2 (runs mcuimage.bin) -target create ${_TARGETNAME}.m3 cortex_m -chain-position $_CHIPNAME.dap -ap-num 2 -defer-examine +target create ${_TARGETNAME}.m3 cortex_m -dap $_CHIPNAME.dap -ap-num 2 -defer-examine + +# declare the auxiliary Cortex-A7 core +target create ${_TARGETNAME}.a7 cortex_a -dap $_CHIPNAME.dap -dbgbase 0x80210000 -defer-examine diff --git a/tcl/target/icepick.cfg b/tcl/target/icepick.cfg index abd7b6a08..0f160bb10 100644 --- a/tcl/target/icepick.cfg +++ b/tcl/target/icepick.cfg @@ -63,7 +63,8 @@ proc icepick_c_router {jrc rw block register payload} { irscan $jrc [CONST IR_ROUTER] -endstate IRPAUSE # ROUTER instructions are 32 bits wide - set old_dr_value [drscan $jrc 32 $new_dr_value -endstate DRPAUSE] + set old_dr_value 0x[drscan $jrc 32 $new_dr_value -endstate DRPAUSE] +# echo "\tOld router value:\t0x[format %x $old_dr_value]" } # Configure the icepick control register @@ -109,15 +110,15 @@ proc icepick_c_tapenable {jrc port} { # jrc == TAP name for the ICEpick # coreid== core id number 0..15 (not same as port number!) -proc icepick_d_set_coreid {jrc coreid } { - icepick_c_router $jrc 1 0x6 $coreid 0x2008 +proc icepick_d_set_core_control {jrc coreid value } { + icepick_c_router $jrc 1 0x6 $coreid $value } # jrc == TAP name for the ICEpick # port == a port number, 0..15 # Follow the sequence described in # http://processors.wiki.ti.com/images/f/f6/Router_Scan_Sequence-ICEpick-D.pdf -proc icepick_d_tapenable {jrc port coreid} { +proc icepick_d_tapenable {jrc port coreid { value 0x2008 } } { # First CONNECT to the ICEPick icepick_c_connect $jrc icepick_c_setup $jrc @@ -125,8 +126,8 @@ proc icepick_d_tapenable {jrc port coreid} { # Select the port icepick_c_router $jrc 1 0x2 $port 0x2108 - # Set 4 bit core ID to the Cortex-A - icepick_d_set_coreid $jrc $coreid + # Set icepick core control for $coreid + icepick_d_set_core_control $jrc $coreid $value # Enter the bypass state irscan $jrc [CONST IF_BYPASS] -endstate RUN/IDLE diff --git a/tcl/target/imx51.cfg b/tcl/target/imx51.cfg index d10cf9f5d..22af2843e 100644 --- a/tcl/target/imx51.cfg +++ b/tcl/target/imx51.cfg @@ -13,11 +13,11 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x1ba00477 } -jtag newtap $_CHIPNAME DAP -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID # SDMA / no IDCODE -jtag newtap $_CHIPNAME SDMA -irlen 4 -ircapture 0x0 -irmask 0xf +jtag newtap $_CHIPNAME sdma -irlen 4 -ircapture 0x0 -irmask 0xf # SJC if { [info exists SJC_TAPID] } { @@ -26,15 +26,16 @@ if { [info exists SJC_TAPID] } { set _SJC_TAPID 0x0190c01d } -jtag newtap $_CHIPNAME SJC -irlen 5 -ircapture 0x1 -irmask 0x1f \ +jtag newtap $_CHIPNAME sjc -irlen 5 -ircapture 0x1 -irmask 0x1f \ -expected-id $_SJC_TAPID -ignore-version # GDB target: Cortex-A8, using DAP set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.DAP +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap # some TCK tycles are required to activate the DEBUG power domain -jtag configure $_CHIPNAME.SJC -event post-reset "runtest 100" +jtag configure $_CHIPNAME.sjc -event post-reset "runtest 100" proc imx51_dbginit {target} { # General Cortex-A8 debug initialisation diff --git a/tcl/target/imx53.cfg b/tcl/target/imx53.cfg index 5ad6473a8..84a85babb 100644 --- a/tcl/target/imx53.cfg +++ b/tcl/target/imx53.cfg @@ -13,11 +13,11 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x1ba00477 } -jtag newtap $_CHIPNAME DAP -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID # SDMA / no IDCODE -jtag newtap $_CHIPNAME SDMA -irlen 4 -ircapture 0x0 -irmask 0xf +jtag newtap $_CHIPNAME sdma -irlen 4 -ircapture 0x0 -irmask 0xf # SJC if { [info exists SJC_TAPID] } { @@ -26,15 +26,16 @@ if { [info exists SJC_TAPID] } { set _SJC_TAPID 0x0190d01d } -jtag newtap $_CHIPNAME SJC -irlen 5 -ircapture 0x1 -irmask 0x1f \ +jtag newtap $_CHIPNAME sjc -irlen 5 -ircapture 0x1 -irmask 0x1f \ -expected-id $_SJC_TAPID -ignore-version # GDB target: Cortex-A8, using DAP set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.DAP +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap # some TCK tycles are required to activate the DEBUG power domain -jtag configure $_CHIPNAME.SJC -event post-reset "runtest 100" +jtag configure $_CHIPNAME.sjc -event post-reset "runtest 100" proc imx53_dbginit {target} { # General Cortex-A8 debug initialisation diff --git a/tcl/target/imx6.cfg b/tcl/target/imx6.cfg index 4f7e98afd..5b59ecf86 100644 --- a/tcl/target/imx6.cfg +++ b/tcl/target/imx6.cfg @@ -13,7 +13,7 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x4ba00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x01 -irmask 0x0f \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID # SDMA / no IDCODE @@ -40,7 +40,8 @@ jtag newtap $_CHIPNAME sjc -irlen 5 -ircapture 0x01 -irmask 0x1f \ # core 2 - 0x82154000 # core 3 - 0x82156000 set _TARGETNAME $_CHIPNAME.cpu.0 -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap \ +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x82150000 # some TCK cycles are required to activate the DEBUG power domain diff --git a/tcl/target/imx7.cfg b/tcl/target/imx7.cfg index d16e95a27..f47dd7d0f 100644 --- a/tcl/target/imx7.cfg +++ b/tcl/target/imx7.cfg @@ -11,7 +11,7 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x5ba00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x01 -irmask 0x0f \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID # @@ -22,16 +22,19 @@ jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x01 -irmask 0x0f \ # core 0 - 0x80070000 # core 1 - 0x80072000 set _TARGETNAME $_CHIPNAME.cpu_a7 -target create $_TARGETNAME.0 cortex_a -chain-position $_CHIPNAME.dap \ + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +target create $_TARGETNAME.0 cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x80070000 -target create $_TARGETNAME.1 cortex_a -chain-position $_CHIPNAME.dap \ +target create $_TARGETNAME.1 cortex_a -dap $_CHIPNAME.dap \ -coreid 1 -dbgbase 0x80072000 -defer-examine # # Cortex-M4 target # set _TARGETNAME_2 $_CHIPNAME.cpu_m4 -target create $_TARGETNAME_2 cortex_m -chain-position $_CHIPNAME.dap -ap-num 4 \ +target create $_TARGETNAME_2 cortex_m -dap $_CHIPNAME.dap -ap-num 4 \ -defer-examine targets $_TARGETNAME.0 diff --git a/tcl/target/k1921vk01t.cfg b/tcl/target/k1921vk01t.cfg index 61b193e39..1a8402106 100755 --- a/tcl/target/k1921vk01t.cfg +++ b/tcl/target/k1921vk01t.cfg @@ -31,9 +31,10 @@ if { [info exists CPUTAPID] } { } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/ke0x.cfg b/tcl/target/ke0x.cfg index 1f1b1321e..8239400d0 100644 --- a/tcl/target/ke0x.cfg +++ b/tcl/target/ke0x.cfg @@ -25,9 +25,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/klx.cfg b/tcl/target/klx.cfg index 1a2ee6798..5d9286a69 100644 --- a/tcl/target/klx.cfg +++ b/tcl/target/klx.cfg @@ -26,9 +26,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 @@ -43,7 +44,19 @@ adapter_khz 1000 reset_config srst_nogate -if {![using_hla]} { +if {[using_hla]} { + echo "" + echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" + echo " Kinetis MCUs have a MDM-AP dedicated mainly to MCU security related functions." + echo " A high level adapter (like a ST-Link) you are currently using cannot access" + echo " the MDM-AP, so commands like 'mdm mass_erase' are not available in your" + echo " configuration. Also security locked state of the device will not be reported." + echo "" + echo " Be very careful as you can lock the device though there is no way to unlock" + echo " it without mass erase. Don't set write protection on the first block." + echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" + echo "" +} { # Detect secured MCU or boot lock-up in RESET/WDOG loop $_CHIPNAME.cpu configure -event examine-start { kinetis mdm check_security diff --git a/tcl/target/kx.cfg b/tcl/target/kx.cfg index 7b0351706..73ee62a79 100644 --- a/tcl/target/kx.cfg +++ b/tcl/target/kx.cfg @@ -30,9 +30,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 @@ -44,7 +45,20 @@ adapter_khz 1000 reset_config srst_nogate -if {![using_hla]} { +if {[using_hla]} { + echo "" + echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" + echo " Kinetis MCUs have a MDM-AP dedicated mainly to MCU security related functions." + echo " A high level adapter (like a ST-Link) you are currently using cannot access" + echo " the MDM-AP, so commands like 'mdm mass_erase' are not available in your" + echo " configuration. Also security locked state of the device will not be reported." + echo " Expect problems connecting to a blank device without boot ROM." + echo "" + echo " Be very careful as you can lock the device though there is no way to unlock" + echo " it without mass erase. Don't set write protection on the first block." + echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" + echo "" +} { # Detect secured MCU or boot lock-up in RESET/WDOG loop $_CHIPNAME.cpu configure -event examine-start { kinetis mdm check_security diff --git a/tcl/target/lpc1850.cfg b/tcl/target/lpc1850.cfg index a78140374..925a0498d 100644 --- a/tcl/target/lpc1850.cfg +++ b/tcl/target/lpc1850.cfg @@ -23,9 +23,10 @@ if { [info exists M3_JTAG_TAPID] } { } swj_newdap $_CHIPNAME m3 -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_M3_JTAG_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.m3 set _TARGETNAME $_CHIPNAME.m3 -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to diff --git a/tcl/target/lpc1xxx.cfg b/tcl/target/lpc1xxx.cfg index 9c10e9f93..701adf278 100644 --- a/tcl/target/lpc1xxx.cfg +++ b/tcl/target/lpc1xxx.cfg @@ -75,9 +75,10 @@ if { [info exists WORKAREASIZE] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap # The LPC11xx devices have 2/4/8kB of SRAM in the ARMv7-M "Code" area (at 0x10000000) # The LPC12xx devices have 4/8kB of SRAM in the ARMv7-M "Code" area (at 0x10000000) diff --git a/tcl/target/lpc4350.cfg b/tcl/target/lpc4350.cfg index 4e23ffb0d..2b728840e 100644 --- a/tcl/target/lpc4350.cfg +++ b/tcl/target/lpc4350.cfg @@ -43,12 +43,14 @@ if { [info exists M0_JTAG_TAPID] } { swj_newdap $_CHIPNAME m4 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M4_TAPID -target create $_CHIPNAME.m4 cortex_m -chain-position $_CHIPNAME.m4 +dap create $_CHIPNAME.m4.dap -chain-position $_CHIPNAME.m4 +target create $_CHIPNAME.m4 cortex_m -dap $_CHIPNAME.m4.dap if { [using_jtag] } { swj_newdap $_CHIPNAME m0 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M0_JTAG_TAPID - target create $_CHIPNAME.m0 cortex_m -chain-position $_CHIPNAME.m0 + dap create $_CHIPNAME.m0.dap -chain-position $_CHIPNAME.m0 + target create $_CHIPNAME.m0 cortex_m -dap $_CHIPNAME.m0.dap } # LPC4350 has 96+32 KB SRAM diff --git a/tcl/target/lpc4370.cfg b/tcl/target/lpc4370.cfg index 67bff0adc..1374ef275 100644 --- a/tcl/target/lpc4370.cfg +++ b/tcl/target/lpc4370.cfg @@ -47,8 +47,8 @@ if { [info exists M0_JTAG_TAPID] } { swj_newdap $_CHIPNAME m4 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M4_TAPID - -target create $_CHIPNAME.m4 cortex_m -chain-position $_CHIPNAME.m4 +dap create $_CHIPNAME.m4.dap -chain-position $_CHIPNAME.m4 +target create $_CHIPNAME.m4 cortex_m -dap $_CHIPNAME.m4.dap # LPC4370 has 96+32 KB contiguous SRAM if { [info exists WORKAREASIZE] } { @@ -65,8 +65,10 @@ if { [using_jtag] } { jtag newtap $_CHIPNAME m0sub -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M0_JTAG_TAPID - target create $_CHIPNAME.m0app cortex_m -chain-position $_CHIPNAME.m0app - target create $_CHIPNAME.m0sub cortex_m -chain-position $_CHIPNAME.m0sub + dap create $_CHIPNAME.m0app.dap -chain-position $_CHIPNAME.m0app + dap create $_CHIPNAME.m0sub.dap -chain-position $_CHIPNAME.m0sub + target create $_CHIPNAME.m0app cortex_m -dap $_CHIPNAME.m0app.dap + target create $_CHIPNAME.m0sub cortex_m -dap $_CHIPNAME.m0sub.dap # 32+8+32 KB SRAM $_CHIPNAME.m0app configure -work-area-phys 0x10080000 \ diff --git a/tcl/target/marvell/88f37x0.cfg b/tcl/target/marvell/88f37x0.cfg index dba7da21e..5e7513588 100644 --- a/tcl/target/marvell/88f37x0.cfg +++ b/tcl/target/marvell/88f37x0.cfg @@ -35,7 +35,8 @@ if { [info exists DAP_TAPID] } { } # declare the one JTAG tap to access the DAP -swj_newdap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # declare the main application cores set _TARGETNAME $_CHIPNAME.cpu @@ -43,9 +44,11 @@ set _smp_command "" for { set _core 0 } { $_core < $_cores } { incr _core 1 } { + cti create cti$_core -dap $_CHIPNAME.dap -ctibase [lindex $_ctis $_core] -ap-num 0 + set _command "target create ${_TARGETNAME}$_core aarch64 \ - -chain-position $_CHIPNAME.dap -coreid $_core \ - -ctibase [lindex $_ctis $_core]" + -dap $_CHIPNAME.dap -coreid $_core \ + -cti cti$_core" if { $_core != 0 } { # non-boot core examination may fail @@ -63,6 +66,6 @@ for { set _core 0 } { $_core < $_cores } { incr _core 1 } { eval $_smp_command # declare the auxiliary Cortex-M3 core on AP #3 -target create ${_TARGETNAME}.m3 cortex_m -chain-position $_CHIPNAME.dap -ap-num 3 -defer-examine +target create ${_TARGETNAME}.m3 cortex_m -dap $_CHIPNAME.dap -ap-num 3 -defer-examine targets ${_TARGETNAME}0 diff --git a/tcl/target/mdr32f9q2i.cfg b/tcl/target/mdr32f9q2i.cfg index 804ac1aef..67481024c 100644 --- a/tcl/target/mdr32f9q2i.cfg +++ b/tcl/target/mdr32f9q2i.cfg @@ -34,9 +34,10 @@ if { [info exists CPUTAPID] } { } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/nrf51.cfg b/tcl/target/nrf51.cfg index 280dd4ff3..4f2402033 100644 --- a/tcl/target/nrf51.cfg +++ b/tcl/target/nrf51.cfg @@ -31,9 +31,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/nrf52.cfg b/tcl/target/nrf52.cfg index e73017503..c29adbdd6 100644 --- a/tcl/target/nrf52.cfg +++ b/tcl/target/nrf52.cfg @@ -25,9 +25,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap adapter_khz 1000 diff --git a/tcl/target/numicro.cfg b/tcl/target/numicro.cfg index 13d965432..c42dfbc2f 100644 --- a/tcl/target/numicro.cfg +++ b/tcl/target/numicro.cfg @@ -28,8 +28,9 @@ if { [info exists WORKAREASIZE] } { # Debug Adapter Target Settings swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUDAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/omap3530.cfg b/tcl/target/omap3530.cfg index c2929d1c4..078d7f24d 100644 --- a/tcl/target/omap3530.cfg +++ b/tcl/target/omap3530.cfg @@ -20,9 +20,9 @@ if { [info exists DAP_TAPID] } { } else { set _DAP_TAPID 0x0b6d602f } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID -disable -jtag configure $_CHIPNAME.dap -event tap-enable \ +jtag configure $_CHIPNAME.cpu -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 3" # Primary TAP: ICEpick-C (JTAG route controller) and boundary scan @@ -36,7 +36,8 @@ jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f \ # GDB target: Cortex-A8, using DAP set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap # SRAM: 64K at 0x4020.0000; use the first 16K $_TARGETNAME configure -work-area-phys 0x40200000 -work-area-size 0x4000 diff --git a/tcl/target/omap4430.cfg b/tcl/target/omap4430.cfg index 6f3525aed..6e3e78d37 100644 --- a/tcl/target/omap4430.cfg +++ b/tcl/target/omap4430.cfg @@ -22,9 +22,9 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x3BA00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID -disable -jtag configure $_CHIPNAME.dap -event tap-enable \ +jtag configure $_CHIPNAME.cpu -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 9" @@ -37,14 +37,14 @@ if { [info exists M3_DAP_TAPID] } { set _M3_DAP_TAPID 0x4BA00477 } -jtag newtap $_CHIPNAME m31_dap -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME m31 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M3_DAP_TAPID -disable -jtag configure $_CHIPNAME.m31_dap -event tap-enable \ +jtag configure $_CHIPNAME.m31 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 5" -jtag newtap $_CHIPNAME m30_dap -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME m30 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M3_DAP_TAPID -disable -jtag configure $_CHIPNAME.m30_dap -event tap-enable \ +jtag configure $_CHIPNAME.m30 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 4" @@ -93,8 +93,9 @@ set _TARGETNAME $_CHIPNAME.cpu set _coreid 0 set _dbgbase [expr 0x80000000 | ($_coreid << 13)] echo "Using dbgbase = [format 0x%x $_dbgbase]" - -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap \ + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase $_dbgbase # SRAM: 56KiB at 0x4030.0000 @@ -104,15 +105,17 @@ $_TARGETNAME configure -work-area-phys 0x40300000 -work-area-size 0x1000 # # M3 targets, separate TAP/DAP for each core # -target create $_CHIPNAME.m30 cortex_m -chain-position $_CHIPNAME.m30_dap -target create $_CHIPNAME.m31 cortex_m -chain-position $_CHIPNAME.m31_dap +dap create $_CHIPNAME.m30_dap -chain-position $_CHIPNAME.m30 +dap create $_CHIPNAME.m31_dap -chain-position $_CHIPNAME.m31 +target create $_CHIPNAME.m30 cortex_m -dap $_CHIPNAME.m30_dap +target create $_CHIPNAME.m31 cortex_m -dap $_CHIPNAME.m31_dap # Once the JRC is up, enable our TAPs jtag configure $_CHIPNAME.jrc -event setup " - jtag tapenable $_CHIPNAME.dap - jtag tapenable $_CHIPNAME.m30_dap - jtag tapenable $_CHIPNAME.m31_dap + jtag tapenable $_CHIPNAME.cpu + jtag tapenable $_CHIPNAME.m30 + jtag tapenable $_CHIPNAME.m31 " # Assume SRST is unavailable (e.g. TI-14 JTAG), so we must assert reset @@ -124,4 +127,3 @@ $_CHIPNAME.m31 configure -event reset-assert { } # Soft breakpoints don't currently work due to broken cache handling gdb_breakpoint_override hard - diff --git a/tcl/target/omap4460.cfg b/tcl/target/omap4460.cfg index 9c40e62d0..218eb64e9 100644 --- a/tcl/target/omap4460.cfg +++ b/tcl/target/omap4460.cfg @@ -22,9 +22,9 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x3BA00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID -disable -jtag configure $_CHIPNAME.dap -event tap-enable \ +jtag configure $_CHIPNAME.cpu -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 9" @@ -37,14 +37,14 @@ if { [info exists M3_DAP_TAPID] } { set _M3_DAP_TAPID 0x4BA00477 } -jtag newtap $_CHIPNAME m31_dap -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME m31 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M3_DAP_TAPID -disable -jtag configure $_CHIPNAME.m31_dap -event tap-enable \ +jtag configure $_CHIPNAME.m31 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 5" -jtag newtap $_CHIPNAME m30_dap -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME m30 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M3_DAP_TAPID -disable -jtag configure $_CHIPNAME.m30_dap -event tap-enable \ +jtag configure $_CHIPNAME.m30 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 4" @@ -94,7 +94,8 @@ set _coreid 0 set _dbgbase [expr 0x80000000 | ($_coreid << 13)] echo "Using dbgbase = [format 0x%x $_dbgbase]" -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap \ +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase $_dbgbase # SRAM: 56KiB at 0x4030.0000 @@ -104,15 +105,17 @@ $_TARGETNAME configure -work-area-phys 0x40300000 -work-area-size 0x1000 # # M3 targets, separate TAP/DAP for each core # -target create $_CHIPNAME.m30 cortex_m -chain-position $_CHIPNAME.m30_dap -target create $_CHIPNAME.m31 cortex_m -chain-position $_CHIPNAME.m31_dap +dap create $_CHIPNAME.m30_dap -chain-position $_CHIPNAME.m30 +dap create $_CHIPNAME.m31_dap -chain-position $_CHIPNAME.m31 +target create $_CHIPNAME.m30 cortex_m -dap $_CHIPNAME.m30_dap +target create $_CHIPNAME.m31 cortex_m -dap $_CHIPNAME.m31_dap # Once the JRC is up, enable our TAPs jtag configure $_CHIPNAME.jrc -event setup " - jtag tapenable $_CHIPNAME.dap - jtag tapenable $_CHIPNAME.m30_dap - jtag tapenable $_CHIPNAME.m31_dap + jtag tapenable $_CHIPNAME.cpu + jtag tapenable $_CHIPNAME.m30 + jtag tapenable $_CHIPNAME.m31 " # Assume SRST is unavailable (e.g. TI-14 JTAG), so we must assert reset diff --git a/tcl/target/psoc4.cfg b/tcl/target/psoc4.cfg index d443b0144..eb51847ce 100644 --- a/tcl/target/psoc4.cfg +++ b/tcl/target/psoc4.cfg @@ -1,4 +1,4 @@ -# script for Cypress PSoC 41xx/42xx family +# script for Cypress PSoC 4 devices # # PSoC 4 devices support SWD transports only. @@ -26,9 +26,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 @@ -53,8 +54,14 @@ adapter_khz 1500 # set in time frame 400 usec delayed about 1 msec from reset. # # OpenOCD have no standard way how to set TEST_MODE in specified time frame. -# TEST_MODE flag is set before reset instead. It worked for tested chips -# despite it is not guaranteed by specification. +# As a workaround the TEST_MODE flag is set before reset instead. +# It worked for the oldest family PSoC4100/4200 even though it is not guaranteed +# by specification. +# +# Newer families like PSoC 4000, 4100M, 4200M, 4100L, 4200L and PSoC 4 BLE +# clear TEST_MODE flag during device reset so workaround is not possible. +# Use a KitProg adapter for theese devices or "reset halt" will not stop +# before executing user code. # # 3) SWD cannot be connected during system initialization after reset. # This might be a reason for unconnecting ST-Link v2 when deasserting reset. @@ -66,11 +73,34 @@ if {![using_hla]} { cortex_m reset_config sysresetreq } -proc ocd_process_reset_inner { MODE } { - if { 0 != [string compare psoc4.cpu [target names]] } { - return -code error "PSoC 4 reset can handle only one psoc4.cpu target"; +proc psoc4_get_family_id {} { + set err [catch "mem2array romtable_pid 32 0xF0000FE0 3"] + if { $err } { + return 0 } - set t psoc4.cpu + if { [expr $romtable_pid(0) & 0xffffff00 ] + || [expr $romtable_pid(1) & 0xffffff00 ] + || [expr $romtable_pid(2) & 0xffffff00 ] } { + echo "Unexpected data in ROMTABLE" + return 0 + } + set designer_id [expr (( $romtable_pid(1) & 0xf0 ) >> 4) | (( $romtable_pid(2) & 0xf ) << 4 ) ] + if { $designer_id != 0xb4 } { + echo [format "ROMTABLE Designer ID 0x%02x is not Cypress" $designer_id] + return 0 + } + set family_id [expr ( $romtable_pid(0) & 0xff ) | (( $romtable_pid(1) & 0xf ) << 8 ) ] + return $family_id +} + +proc ocd_process_reset_inner { MODE } { + global PSOC4_USE_ACQUIRE PSOC4_TEST_MODE_WORKAROUND + global _TARGETNAME + + if { 0 != [string compare $_TARGETNAME [target names]] } { + return -code error "PSoC 4 reset can handle only one $_TARGETNAME target"; + } + set t $_TARGETNAME # If this target must be halted... set halt -1 @@ -87,17 +117,42 @@ proc ocd_process_reset_inner { MODE } { return -code error "Invalid mode: $MODE, must be one of: halt, init, or run"; } + if { ! [info exists PSOC4_USE_ACQUIRE] } { + if { 0 == [string compare [adapter_name] kitprog ] } { + set PSOC4_USE_ACQUIRE 1 + } else { + set PSOC4_USE_ACQUIRE 0 + } + } + if { $PSOC4_USE_ACQUIRE } { + set PSOC4_TEST_MODE_WORKAROUND 0 + } elseif { ! [info exists PSOC4_TEST_MODE_WORKAROUND] } { + if { [psoc4_get_family_id] == 0x93 } { + set PSOC4_TEST_MODE_WORKAROUND 1 + } else { + set PSOC4_TEST_MODE_WORKAROUND 0 + } + } + #$t invoke-event reset-start $t invoke-event reset-assert-pre - set TEST_MODE 0x40030014 - if { $halt == 1 } { - mww $TEST_MODE 0x80000000 + if { $halt && $PSOC4_USE_ACQUIRE } { + catch { [adapter_name] acquire_psoc } + $t arp_examine } else { - mww $TEST_MODE 0 + if { $PSOC4_TEST_MODE_WORKAROUND } { + set TEST_MODE 0x40030014 + if { $halt == 1 } { + catch { mww $TEST_MODE 0x80000000 } + } else { + catch { mww $TEST_MODE 0 } + } + } + + $t arp_reset assert 0 } - $t arp_reset assert 0 $t invoke-event reset-assert-post $t invoke-event reset-deassert-pre if {![using_hla]} { # workaround ST-Link v2 fails and forcing reconnect @@ -127,7 +182,14 @@ proc ocd_process_reset_inner { MODE } { set pc [ocd_reg pc] regsub {pc[^:]*: } $pc "" pc if { $pc < 0x10000000 || $pc > 0x1000ffff } { - return -code error [format "TARGET: %s - Not halted in system ROM, use 'reset_config none'" $t] + set hint "" + set family_id [psoc4_get_family_id] + if { $family_id == 0x93 } { + set hint ", use 'reset_config none'" + } elseif { $family_id > 0x93 } { + set hint ", use a KitProg adapter" + } + return -code error [format "TARGET: %s - Not halted in system ROM%s" $t $hint] } # Set registers to reset vector values @@ -135,7 +197,9 @@ proc ocd_process_reset_inner { MODE } { reg pc [expr $value(1) & 0xfffffffe ] reg msp $value(0) - mww $TEST_MODE 0 + if { $PSOC4_TEST_MODE_WORKAROUND } { + catch { mww $TEST_MODE 0 } + } } #Pass 2 - if needed "init" diff --git a/tcl/target/psoc5lp.cfg b/tcl/target/psoc5lp.cfg index 1cdde4712..230ca0732 100644 --- a/tcl/target/psoc5lp.cfg +++ b/tcl/target/psoc5lp.cfg @@ -23,9 +23,10 @@ if { [using_jtag] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_DAP_ID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if {![using_hla]} { cortex_m reset_config sysresetreq diff --git a/tcl/target/psoc6.cfg b/tcl/target/psoc6.cfg new file mode 100644 index 000000000..ad9aba569 --- /dev/null +++ b/tcl/target/psoc6.cfg @@ -0,0 +1,135 @@ +# +# Configuration script for Cypress PSoC6 family of microcontrollers (CY8C6xxx) +# PSoC6 is a dual-core device with CM0+ and CM4 cores. Both cores share +# the same Flash/RAM/MMIO address space. +# + +source [find target/swj-dp.tcl] + +adapter_khz 1000 + +global _CHIPNAME +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME psoc6 +} + +global TARGET +set TARGET $_CHIPNAME.cpu + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +# Is CM0 Debugging enabled ? +global _ENABLE_CM0 +if { [info exists ENABLE_CM0] } { + set _ENABLE_CM0 $ENABLE_CM0 +} else { + set _ENABLE_CM0 1 +} + +# Is CM4 Debugging enabled ? +global _ENABLE_CM4 +if { [info exists ENABLE_CM4] } { + set _ENABLE_CM4 $ENABLE_CM4 +} else { + set _ENABLE_CM4 1 +} + +global _WORKAREASIZE_CM0 +if { [info exists WORKAREASIZE_CM0] } { + set _WORKAREASIZE_CM0 $WORKAREASIZE_CM0 +} else { + set _WORKAREASIZE_CM0 0x4000 +} + +global _WORKAREASIZE_CM4 +if { [info exists WORKAREASIZE_CM4] } { + set _WORKAREASIZE_CM4 $WORKAREASIZE_CM4 +} else { + set _WORKAREASIZE_CM4 0x4000 +} + +global _WORKAREAADDR_CM0 +if { [info exists WORKAREAADDR_CM0] } { + set _WORKAREAADDR_CM0 $WORKAREAADDR_CM0 +} else { + set _WORKAREAADDR_CM0 0x08000000 +} + +global _WORKAREAADDR_CM4 +if { [info exists WORKAREAADDR_CM4] } { + set _WORKAREAADDR_CM4 $WORKAREAADDR_CM4 +} else { + set _WORKAREAADDR_CM4 0x08000000 +} + +proc init_reset { mode } { + global RESET_MODE + set RESET_MODE $mode + + if {[using_jtag]} { + jtag arp_init-reset + } +} + +# Utility to make 'reset halt' work as reset;halt on a target +# It does not prevent running code after reset +proc psoc6_deassert_post { target } { + # PSoC6 cleared AP registers including TAR during reset + # Force examine to synchronize OpenOCD target status + $target arp_examine + + global RESET_MODE + if { $RESET_MODE ne "run" } { + $target arp_poll + $target arp_poll + set st [$target curstate] + if { $st eq "reset" } { + # we assume running state follows + # if reset accidentally halts, waiting is useless + catch { $target arp_waitstate running 100 } + set st [$target curstate] + } + if { $st eq "running" } { + echo "$target: Ran after reset and before halt..." + $target arp_halt + } + } +} + +if { $_ENABLE_CM0 } { + target create ${TARGET}.cm0 cortex_m -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 + ${TARGET}.cm0 configure -work-area-phys $_WORKAREAADDR_CM0 -work-area-size $_WORKAREASIZE_CM0 -work-area-backup 0 + + flash bank main_flash_cm0 psoc6 0x10000000 0 0 0 ${TARGET}.cm0 + flash bank work_flash_cm0 psoc6 0x14000000 0 0 0 ${TARGET}.cm0 + flash bank super_flash_user_cm0 psoc6 0x16000800 0 0 0 ${TARGET}.cm0 + flash bank super_flash_nar_cm0 psoc6 0x16001A00 0 0 0 ${TARGET}.cm0 + flash bank super_flash_key_cm0 psoc6 0x16005A00 0 0 0 ${TARGET}.cm0 + flash bank super_flash_toc2_cm0 psoc6 0x16007C00 0 0 0 ${TARGET}.cm0 + + ${TARGET}.cm0 cortex_m reset_config sysresetreq + ${TARGET}.cm0 configure -event reset-deassert-post "psoc6_deassert_post ${TARGET}.cm0" +} + +if { $_ENABLE_CM4 } { + target create ${TARGET}.cm4 cortex_m -dap $_CHIPNAME.dap -ap-num 2 -coreid 1 + ${TARGET}.cm4 configure -work-area-phys $_WORKAREAADDR_CM4 -work-area-size $_WORKAREASIZE_CM4 -work-area-backup 0 + + flash bank main_flash_cm4 psoc6 0x10000000 0 0 0 ${TARGET}.cm4 + flash bank work_flash_cm4 psoc6 0x14000000 0 0 0 ${TARGET}.cm4 + flash bank super_flash_user_cm4 psoc6 0x16000800 0 0 0 ${TARGET}.cm4 + flash bank super_flash_nar_cm4 psoc6 0x16001A00 0 0 0 ${TARGET}.cm4 + flash bank super_flash_key_cm4 psoc6 0x16005A00 0 0 0 ${TARGET}.cm4 + flash bank super_flash_toc2_cm4 psoc6 0x16007C00 0 0 0 ${TARGET}.cm4 + + ${TARGET}.cm4 cortex_m reset_config vectreset + ${TARGET}.cm4 configure -event reset-deassert-post "psoc6_deassert_post ${TARGET}.cm4" +} + +if { $_ENABLE_CM0 } { + # Use CM0+ by default on dual-core devices + targets ${TARGET}.cm0 +} diff --git a/tcl/target/renesas_s7g2.cfg b/tcl/target/renesas_s7g2.cfg index a09377b2d..78fb3e82f 100644 --- a/tcl/target/renesas_s7g2.cfg +++ b/tcl/target/renesas_s7g2.cfg @@ -29,9 +29,10 @@ if { [using_jtag] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE diff --git a/tcl/target/sim3x.cfg b/tcl/target/sim3x.cfg index f721f36c8..ed46a3b34 100755 --- a/tcl/target/sim3x.cfg +++ b/tcl/target/sim3x.cfg @@ -38,9 +38,10 @@ if { [info exists WORKAREASIZE] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE diff --git a/tcl/target/stellaris.cfg b/tcl/target/stellaris.cfg index 4fe99394a..7fffd2a7c 100644 --- a/tcl/target/stellaris.cfg +++ b/tcl/target/stellaris.cfg @@ -42,7 +42,8 @@ if { [info exists CPUTAPID] } { # ... even though SWD ignores all except TAPID, and # JTAG shouldn't need anything more then irlen. (and TAPID). swj_newdap $_CHIPNAME cpu -irlen 4 -irmask 0xf \ - -expected-id $_CPUTAPID -ignore-version + -expected-id $_CPUTAPID -ignore-version +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE @@ -52,7 +53,7 @@ if { [info exists WORKAREASIZE] } { } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap # 8K working area at base of ram, not backed up # diff --git a/tcl/target/stm32f0x.cfg b/tcl/target/stm32f0x.cfg index 2b48cfce3..b8c0de94c 100644 --- a/tcl/target/stm32f0x.cfg +++ b/tcl/target/stm32f0x.cfg @@ -32,9 +32,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32f1x.cfg b/tcl/target/stm32f1x.cfg index 5a4c2fa70..e0f6ede95 100644 --- a/tcl/target/stm32f1x.cfg +++ b/tcl/target/stm32f1x.cfg @@ -36,13 +36,14 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32f2x.cfg b/tcl/target/stm32f2x.cfg index 44955d455..80f9274d5 100644 --- a/tcl/target/stm32f2x.cfg +++ b/tcl/target/stm32f2x.cfg @@ -49,13 +49,14 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32f3x.cfg b/tcl/target/stm32f3x.cfg index 0c8919f1d..86e9f594e 100644 --- a/tcl/target/stm32f3x.cfg +++ b/tcl/target/stm32f3x.cfg @@ -49,13 +49,14 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32f4x.cfg b/tcl/target/stm32f4x.cfg index 7a0af9fba..73b1dc8ed 100644 --- a/tcl/target/stm32f4x.cfg +++ b/tcl/target/stm32f4x.cfg @@ -36,13 +36,14 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32f7x.cfg b/tcl/target/stm32f7x.cfg index 4065e2a07..dc310da44 100755 --- a/tcl/target/stm32f7x.cfg +++ b/tcl/target/stm32f7x.cfg @@ -36,13 +36,14 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg index 02dbed4a8..10477a5a7 100644 --- a/tcl/target/stm32h7x.cfg +++ b/tcl/target/stm32h7x.cfg @@ -34,13 +34,14 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { swj_newdap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32l0.cfg b/tcl/target/stm32l0.cfg index 417b282d3..ec5d5463e 100644 --- a/tcl/target/stm32l0.cfg +++ b/tcl/target/stm32l0.cfg @@ -37,9 +37,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32l1.cfg b/tcl/target/stm32l1.cfg index a8d6fdf25..054fa9b74 100644 --- a/tcl/target/stm32l1.cfg +++ b/tcl/target/stm32l1.cfg @@ -45,13 +45,14 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32l4x.cfg b/tcl/target/stm32l4x.cfg index ccee48e97..496b47a72 100644 --- a/tcl/target/stm32l4x.cfg +++ b/tcl/target/stm32l4x.cfg @@ -36,13 +36,14 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32w108xx.cfg b/tcl/target/stm32w108xx.cfg index d07afc414..3a83fd19e 100644 --- a/tcl/target/stm32w108xx.cfg +++ b/tcl/target/stm32w108xx.cfg @@ -37,6 +37,7 @@ if { [info exists CPUTAPID] } { set _ENDIAN little swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { if { [info exists BSTAPID] } { @@ -53,7 +54,7 @@ if {[using_jtag]} { # Set Target # set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/ti_msp432p4xx.cfg b/tcl/target/ti_msp432p4xx.cfg index 860086707..461b59547 100644 --- a/tcl/target/ti_msp432p4xx.cfg +++ b/tcl/target/ti_msp432p4xx.cfg @@ -31,9 +31,10 @@ if { [using_jtag] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_DAP_ID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE diff --git a/tcl/target/u8500.cfg b/tcl/target/u8500.cfg index 66fc075c2..7d8bfe375 100644 --- a/tcl/target/u8500.cfg +++ b/tcl/target/u8500.cfg @@ -167,11 +167,11 @@ if { [info exists CPUTAPID] } { } else { set _CPUTAPID 0x4ba00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0xe -irmask 0xf -expected-id $_CPUTAPID -disable -jtag configure $_CHIPNAME.dap -event tap-enable \ - "u8500_dapenable $_CHIPNAME.dap" -jtag configure $_CHIPNAME.dap -event tap-disable \ - "u8500_tapdisable $_CHIPNAME.dap 0xc0" +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0xe -irmask 0xf -expected-id $_CPUTAPID -disable +jtag configure $_CHIPNAME.cpu -event tap-enable \ + "u8500_dapenable $_CHIPNAME.cpu" +jtag configure $_CHIPNAME.cpu -event tap-disable \ + "u8500_tapdisable $_CHIPNAME.cpu 0xc0" #CLTAPC TAP JRC equivalent @@ -202,7 +202,9 @@ if { [info exists DAP_DBG2] } { set _DAP_DBG2 0x801AA000 } -target create $_TARGETNAME_1 cortex_a -chain-position $_CHIPNAME.dap -dbgbase $_DAP_DBG1 -coreid 0 -rtos linux +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +target create $_TARGETNAME_1 cortex_a -dap $_CHIPNAME.dap -dbgbase $_DAP_DBG1 -coreid 0 -rtos linux $_TARGETNAME_1 configure -event gdb-attach { halt @@ -217,7 +219,7 @@ global _TARGETNAME_2 set _TARGETNAME_2 $TARGETNAME_2 } -target create $_TARGETNAME_2 cortex_a -chain-position $_CHIPNAME.dap -dbgbase $_DAP_DBG2 -coreid 1 -rtos linux +target create $_TARGETNAME_2 cortex_a -dap $_CHIPNAME.dap -dbgbase $_DAP_DBG2 -coreid 1 -rtos linux $_TARGETNAME_2 configure -event gdb-attach { halt diff --git a/tcl/target/vybrid_vf6xx.cfg b/tcl/target/vybrid_vf6xx.cfg index 6ec4b35cd..a1202efb7 100644 --- a/tcl/target/vybrid_vf6xx.cfg +++ b/tcl/target/vybrid_vf6xx.cfg @@ -29,8 +29,9 @@ if { [using_jtag] } { source [find target/swj-dp.tcl] swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_A5_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create ${_TARGETNAME}0 cortex_a -chain-position $_CHIPNAME.cpu -dbgbase 0xc0088000 +target create ${_TARGETNAME}0 cortex_a -dap $_CHIPNAME.dap -dbgbase 0xc0088000 adapter_khz 1000 diff --git a/tcl/target/xilinx_ultrascale.cfg b/tcl/target/xilinx_ultrascale.cfg new file mode 100644 index 000000000..9056c976e --- /dev/null +++ b/tcl/target/xilinx_ultrascale.cfg @@ -0,0 +1,92 @@ +# +# target configuration for +# Xilinx UltraScale+ +# +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME uscale +} + +# +# DAP tap +# +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba00477 +} + +jtag newtap $_CHIPNAME tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap + +# +# PS tap +# +if { [info exists PS_TAPID] } { + set _PS_TAPID $PS_TAPID +} else { + set _PS_TAPID 0x04710093 +} + +set jtag_configured 0 + +jtag newtap $_CHIPNAME ps -irlen 12 -ircapture 0x1 -irmask 0x03 -expected-id $_PS_TAPID + +jtag configure $_CHIPNAME.ps -event setup { + global _CHIPNAME + global jtag_configured + + if { $jtag_configured == 0 } { + # add the DAP tap to the chain + # See https://forums.xilinx.com/t5/UltraScale-Architecture/JTAG-Chain-Configuration-for-Zynq-UltraScale-MPSoC/td-p/758924 + irscan $_CHIPNAME.ps 0x824 + drscan $_CHIPNAME.ps 32 0x00000003 + runtest 100 + + # setup event will be re-entered through jtag arp_init + # break the recursion + set jtag_configured 1 + # re-initialized the jtag chain + jtag arp_init + } +} + +set _TARGETNAME $_CHIPNAME.a53 +set _CTINAME $_CHIPNAME.cti +set _smp_command "" + +set DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} +set CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} +set _cores 4 + +for { set _core 0 } { $_core < $_cores } { incr _core } { + + cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 \ + -ctibase [lindex $CTIBASE $_core] + + set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ + -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core" + + if { $_core != 0 } { + # non-boot core examination may fail + set _command "$_command -defer-examine" + set _smp_command "$_smp_command $_TARGETNAME.$_core" + } else { + # uncomment when "hawt" rtos is merged + #set _command "$_command -rtos hawt" + set _smp_command "target smp $_TARGETNAME.$_core" + } + + eval $_command +} + +eval $_smp_command +targets $_TARGETNAME.0 + +proc core_up { args } { + global _TARGETNAME + foreach { core } [set args] { + $_TARGETNAME.$core arp_examine + } +} diff --git a/tcl/target/xmc1xxx.cfg b/tcl/target/xmc1xxx.cfg index d3123c437..e693b59db 100644 --- a/tcl/target/xmc1xxx.cfg +++ b/tcl/target/xmc1xxx.cfg @@ -20,9 +20,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_SWD_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian little -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE diff --git a/tcl/target/xmc4xxx.cfg b/tcl/target/xmc4xxx.cfg index bc0077799..e106d34e3 100644 --- a/tcl/target/xmc4xxx.cfg +++ b/tcl/target/xmc4xxx.cfg @@ -35,9 +35,10 @@ if { [using_jtag] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap # Work-area is a space in RAM used for flash programming # By default use 16 kB diff --git a/tcl/target/zynq_7000.cfg b/tcl/target/zynq_7000.cfg index 70a861625..07a6c8352 100644 --- a/tcl/target/zynq_7000.cfg +++ b/tcl/target/zynq_7000.cfg @@ -13,11 +13,13 @@ jtag newtap zynq_pl bs -irlen 6 -ircapture 0x1 -irmask 0x03 \ -expected-id 0x03727093 \ -expected-id 0x03736093 -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x4ba00477 +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x4ba00477 -target create ${_TARGETNAME}0 cortex_a -chain-position $_CHIPNAME.dap \ +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +target create ${_TARGETNAME}0 cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x80090000 -target create ${_TARGETNAME}1 cortex_a -chain-position $_CHIPNAME.dap \ +target create ${_TARGETNAME}1 cortex_a -dap $_CHIPNAME.dap \ -coreid 1 -dbgbase 0x80092000 target smp ${_TARGETNAME}0 ${_TARGETNAME}1