diff --git a/.github/workflows/checkpatch.yml b/.github/workflows/checkpatch.yml index c9ec78d59..06958c2f9 100644 --- a/.github/workflows/checkpatch.yml +++ b/.github/workflows/checkpatch.yml @@ -24,4 +24,5 @@ jobs: -x "a/src/jtag/drivers/libjaylink/*" \ -x "a/tools/git2cl/*" \ -x "a/.github/*" \ + -x "a/HACKING" \ | ./tools/scripts/checkpatch.pl --no-signoff - diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 69194d8eb..368c5794b 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -22,7 +22,7 @@ jobs: - run: ./bootstrap - name: Prepare libusb1 env: - LIBUSB1_VER: 1.0.24 + LIBUSB1_VER: 1.0.26 run: | mkdir -p $DL_DIR && cd $DL_DIR wget "https://github.com/libusb/libusb/releases/download/v${LIBUSB1_VER}/libusb-${LIBUSB1_VER}.tar.bz2" @@ -30,7 +30,7 @@ jobs: echo "LIBUSB1_SRC=$PWD/libusb-${LIBUSB1_VER}" >> $GITHUB_ENV - name: Prepare hidapi env: - HIDAPI_VER: 0.10.1 + HIDAPI_VER: 0.11.2 run: | mkdir -p $DL_DIR && cd $DL_DIR wget "https://github.com/libusb/hidapi/archive/hidapi-${HIDAPI_VER}.tar.gz" diff --git a/.gitignore b/.gitignore index 955ca3c2e..f5aa68a40 100644 --- a/.gitignore +++ b/.gitignore @@ -68,6 +68,7 @@ doxygen doxygen.log Doxyfile libtool +*-libtool Makefile !contrib/loaders/**/Makefile stamp-h1 diff --git a/HACKING b/HACKING index 1eeb1a284..5d110fb05 100644 --- a/HACKING +++ b/HACKING @@ -197,11 +197,11 @@ while(!done) { @endcode \note use "git add ." before commit to add new files. - Comment template, notice the short first line w/topic. The topic field - should identify the main part or subsystem the patch touches. Check - git log for examples. -@code -topic: Short comment + Commit message template, notice the short first line. + The field 'specify touched area' + should identify the main part or subsystem the patch touches. +@code{.unparsed} +specify touched area: short comment Longer comments over several lines, explaining (where applicable) the reason for the patch and the general idea the solution is based on, @@ -209,6 +209,32 @@ any major design decisions, etc... Signed-off-by: ... @endcode + Examples: +@code{.unparsed} +flash/nor/atsame5: add SAME59 support + +Add new device ID +@endcode +@code{.unparsed} +flash/nor: flash driver for XYZ123 + +Add new flash driver for internal flash of ... +@endcode +@code{.unparsed} +target/cortex_m: fix segmentation fault in cmd 'soft_reset_halt' + +soft_reset_halt command failed reproducibly under following conditions: ... +Test for NULL pointer and return error ... + +Reported-by: John Reporter +Fixes: 123456789abc ("target: the commit where the problem started") +BugLink: https://sourceforge.net/p/openocd/tickets/999/ +@endcode +@code{.unparsed} +doc: fix typos +@endcode + See "git log" for more examples. + -# Next you need to make sure that your patches are on top of the latest stuff on the server and that there are no conflicts: diff --git a/configure.ac b/configure.ac index 081e7744d..687fffab6 100644 --- a/configure.ac +++ b/configure.ac @@ -299,10 +299,14 @@ AS_CASE(["${host_cpu}"], AC_ARG_ENABLE([imx_gpio], AS_HELP_STRING([--enable-imx_gpio], [Enable building support for bitbanging on NXP IMX processors]), [build_imx_gpio=$enableval], [build_imx_gpio=no]) + AC_ARG_ENABLE([am335xgpio], + AS_HELP_STRING([--enable-am335xgpio], [Enable building support for bitbanging on AM335x (as found in Beaglebones)]), + [build_am335xgpio=$enableval], [build_am335xgpio=no]) ], [ build_bcm2835gpio=no build_imx_gpio=no + build_am335xgpio=no ]) AS_CASE(["${host_cpu}"], @@ -508,6 +512,13 @@ AS_IF([test "x$build_imx_gpio" = "xyes"], [ AC_DEFINE([BUILD_IMX_GPIO], [0], [0 if you don't want imx_gpio.]) ]) +AS_IF([test "x$build_am335xgpio" = "xyes"], [ + build_bitbang=yes + AC_DEFINE([BUILD_AM335XGPIO], [1], [1 if you want am335xgpio.]) +], [ + AC_DEFINE([BUILD_AM335XGPIO], [0], [0 if you don't want am335xgpio.]) +]) + AS_IF([test "x$parport_use_ppdev" = "xyes"], [ AC_DEFINE([PARPORT_USE_PPDEV], [1], [1 if you want parport to use ppdev.]) ], [ @@ -560,9 +571,9 @@ AS_IF([test "x$enable_buspirate" != "xno"], [ AS_IF([test "x$use_internal_jimtcl" = "xyes"], [ AS_IF([test -f "$srcdir/jimtcl/configure.ac"], [ AS_IF([test "x$use_internal_jimtcl_maintainer" = "xyes"], [ - jimtcl_config_options="--disable-install-jim --maintainer" + jimtcl_config_options="--disable-install-jim --with-ext=json --maintainer" ], [ - jimtcl_config_options="--disable-install-jim" + jimtcl_config_options="--disable-install-jim --with-ext=json" ]) AX_CONFIG_SUBDIR_OPTION([jimtcl], [$jimtcl_config_options]) ], [ @@ -712,6 +723,7 @@ AM_CONDITIONAL([EP93XX], [test "x$build_ep93xx" = "xyes"]) AM_CONDITIONAL([AT91RM9200], [test "x$build_at91rm9200" = "xyes"]) AM_CONDITIONAL([BCM2835GPIO], [test "x$build_bcm2835gpio" = "xyes"]) AM_CONDITIONAL([IMX_GPIO], [test "x$build_imx_gpio" = "xyes"]) +AM_CONDITIONAL([AM335XGPIO], [test "x$build_am335xgpio" = "xyes"]) AM_CONDITIONAL([BITBANG], [test "x$build_bitbang" = "xyes"]) AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes"]) AM_CONDITIONAL([VDEBUG], [test "x$build_vdebug" = "xyes"]) diff --git a/contrib/cross-build.sh b/contrib/cross-build.sh index 856551d78..2275f6896 100755 --- a/contrib/cross-build.sh +++ b/contrib/cross-build.sh @@ -154,7 +154,7 @@ if [ -d $CAPSTONE_SRC ] ; then sed -i '1s;^;prefix=/usr \ exec_prefix=${prefix} \ libdir=${exec_prefix}/lib \ -includedir=${prefix}/include\n\n;' $CAPSTONE_PC_FILE +includedir=${prefix}/include/capstone\n\n;' $CAPSTONE_PC_FILE fi diff --git a/doc/openocd.texi b/doc/openocd.texi index a5d561c13..99cae9a75 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -584,6 +584,9 @@ produced, PDF schematics are easily found and it is easy to make. @item @b{imx_gpio} @* A NXP i.MX-based board (e.g. Wandboard) using the GPIO pins (should work on any i.MX processor). +@item @b{am335xgpio} +@* A Texas Instruments AM335x-based board (e.g. BeagleBone Black) using the GPIO pins of the expansion headers. + @item @b{jtag_vpi} @* A JTAG driver acting as a client for the JTAG VPI server interface. @* Link: @url{http://github.com/fjullien/jtag_vpi} @@ -2120,6 +2123,15 @@ corresponding subsystems: @deffnx {Config Command} {pld init} @deffnx {Command} {tpiu init} @end deffn + +At last, @command{init} executes all the commands that are specified in +the TCL list @var{post_init_commands}. The commands are executed in the +same order they occupy in the list. If one of the commands fails, then +the error is propagated and OpenOCD fails too. +@example +lappend post_init_commands @{echo "OpenOCD successfully initialized."@} +lappend post_init_commands @{echo "Have fun with OpenOCD !"@} +@end example @end deffn @deffn {Config Command} {noinit} @@ -3342,11 +3354,180 @@ pinout. @end deffn +@deffn {Interface Driver} {am335xgpio} The AM335x SoC is present in BeagleBone +Black and BeagleBone Green single-board computers which expose some of the GPIOs +on the two expansion headers. + +For maximum performance the driver accesses memory-mapped GPIO peripheral +registers directly. The memory mapping requires read and write permission to +kernel memory; if /dev/gpiomem exists it will be used, otherwise /dev/mem will +be used. The driver restores the GPIO state on exit. + +All four GPIO ports are available. GPIOs numbered 0 to 31 are mapped to GPIO port +0, GPIO numbers 32 to 63 are mapped to GPIO port 1 and so on. + +See @file{interface/beaglebone-swd-native.cfg} for a sample configuration file. + +@deffn {Config Command} {am335xgpio jtag_nums} @var{tck} @var{tms} @var{tdi} @var{tdo} +Set JTAG transport GPIO numbers for TCK, TMS, TDI, and TDO (in that order). +Must be specified to enable JTAG transport. These pins can also be specified +individually. +@end deffn + +@deffn {Config Command} {am335xgpio tck_num} @var{tck} +Set TCK GPIO number. Must be specified to enable JTAG transport. Can also be +specified using the configuration command @command{am335xgpio jtag_nums}. +@end deffn + +@deffn {Config Command} {am335xgpio tms_num} @var{tms} +Set TMS GPIO number. Must be specified to enable JTAG transport. Can also be +specified using the configuration command @command{am335xgpio jtag_nums}. +@end deffn + +@deffn {Config Command} {am335xgpio tdo_num} @var{tdo} +Set TDO GPIO number. Must be specified to enable JTAG transport. Can also be +specified using the configuration command @command{am335xgpio jtag_nums}. +@end deffn + +@deffn {Config Command} {am335xgpio tdi_num} @var{tdi} +Set TDI GPIO number. Must be specified to enable JTAG transport. Can also be +specified using the configuration command @command{am335xgpio jtag_nums}. +@end deffn + +@deffn {Config Command} {am335xgpio swd_nums} @var{swclk} @var{swdio} +Set SWD transport GPIO numbers for SWCLK and SWDIO (in that order). Must be +specified to enable SWD transport. These pins can also be specified individually. +@end deffn + +@deffn {Config Command} {am335xgpio swclk_num} @var{swclk} +Set SWCLK GPIO number. Must be specified to enable SWD transport. Can also be +specified using the configuration command @command{am335xgpio swd_nums}. +@end deffn + +@deffn {Config Command} {am335xgpio swdio_num} @var{swdio} +Set SWDIO GPIO number. Must be specified to enable SWD transport. Can also be +specified using the configuration command @command{am335xgpio swd_nums}. +@end deffn + +@deffn {Config Command} {am335xgpio swdio_dir_num} @var{swdio_dir} +Set SWDIO direction control pin GPIO number. If specified, this pin can be used +to control the direction of an external buffer on the SWDIO pin. The direction +control state can be set with the command @command{am335xgpio +swdio_dir_output_state}. If not specified this feature is disabled. +@end deffn + +@deffn {Config Command} {am335xgpio swdio_dir_output_state} @var{output_state} +Set the state required for an external SWDIO buffer to be an output. Valid +values are @option{on} (default) and @option{off}. +@end deffn + +@deffn {Config Command} {am335xgpio srst_num} @var{srst} +Set SRST GPIO number. Must be specified to enable SRST. +@end deffn + +@deffn {Config Command} {am335xgpio trst_num} @var{trst} +Set TRST GPIO number. Must be specified to enable TRST. +@end deffn + +@deffn {Config Command} {am335xgpio led_num} @var{led} +Set activity LED GPIO number. If not specified an activity LED is not enabled. +@end deffn + +@deffn {Config Command} {am335xgpio led_on_state} @var{on_state} +Set required logic level for the LED to be on. Valid values are @option{on} +(default) and @option{off}. +@end deffn + +@deffn {Config Command} {am335xgpio speed_coeffs} @var{speed_coeff} @var{speed_offset} +Set SPEED_COEFF and SPEED_OFFSET for delay calculations. If unspecified +speed_coeff defaults to 600000 and speed_offset defaults to 575. +@end deffn + +@end deffn + + @deffn {Interface Driver} {linuxgpiod} Linux provides userspace access to GPIO through libgpiod since Linux kernel version v4.6. -The driver emulates either JTAG and SWD transport through bitbanging. +The driver emulates either JTAG or SWD transport through bitbanging. See @file{interface/dln-2-gpiod.cfg} for a sample config. + +@deffn {Config Command} {linuxgpiod gpiochip} @var{chip} +Set the GPIO chip number for all GPIOs used by linuxgpiod. If GPIOs use +different GPIO chips then the individual GPIO configuration commands (i.e., not +@command{linuxgpiod jtag_nums} or @command{linuxgpiod swd_nums}) can be used to +set chip numbers independently for each GPIO. +@end deffn + +@deffn {Config Command} {linuxgpiod jtag_nums} @var{tck} @var{tms} @var{tdi} @var{tdo} +Set JTAG transport GPIO numbers for TCK, TMS, TDI, and TDO (in that order). Must +be specified to enable JTAG transport. These pins can also be specified +individually. +@end deffn + +@deffn {Config Command} {linuxgpiod tck_num} [@var{chip}] @var{tck} +Set TCK GPIO number, and optionally TCK chip number. Must be specified to enable +JTAG transport. Can also be specified using the configuration command +@command{linuxgpiod jtag_nums}. +@end deffn + +@deffn {Config Command} {linuxgpiod tms_num} [@var{chip}] @var{tms} +Set TMS GPIO number, and optionally TMS chip number. Must be specified to enable +JTAG transport. Can also be specified using the configuration command +@command{linuxgpiod jtag_nums}. +@end deffn + +@deffn {Config Command} {linuxgpiod tdo_num} [@var{chip}] @var{tdo} +Set TDO GPIO number, and optionally TDO chip number. Must be specified to enable +JTAG transport. Can also be specified using the configuration command +@command{linuxgpiod jtag_nums}. +@end deffn + +@deffn {Config Command} {linuxgpiod tdi_num} [@var{chip}] @var{tdi} +Set TDI GPIO number, and optionally TDI chip number. Must be specified to enable +JTAG transport. Can also be specified using the configuration command +@command{linuxgpiod jtag_nums}. +@end deffn + +@deffn {Config Command} {linuxgpiod trst_num} [@var{chip}] @var{trst} +Set TRST GPIO number, and optionally TRST chip number. Must be specified to +enable TRST. +@end deffn + +@deffn {Config Command} {linuxgpiod swd_nums} @var{swclk} @var{swdio} +Set SWD transport GPIO numbers for SWCLK and SWDIO (in that order). Must be +specified to enable SWD transport. These pins can also be specified +individually. +@end deffn + +@deffn {Config Command} {linuxgpiod swclk_num} [@var{chip}] @var{swclk} +Set SWCLK GPIO number, and optionally SWCLK chip number. Must be specified to +enable SWD transport. Can also be specified using the configuration command +@command{linuxgpiod swd_nums}. +@end deffn + +@deffn {Config Command} {linuxgpiod swdio_num} [@var{chip}] @var{swdio} +Set SWDIO GPIO number, and optionally SWDIO chip number. Must be specified to +enable SWD transport. Can also be specified using the configuration command +@command{linuxgpiod swd_nums}. +@end deffn + +@deffn {Config Command} {linuxgpiod swdio_dir_num} [@var{chip}] @var{swdio_dir} +Set SWDIO direction control GPIO number, and optionally SWDIO direction control +chip number. If specified, this GPIO can be used to control the direction of an +external buffer connected to the SWDIO GPIO (set=output mode, clear=input mode). +@end deffn + +@deffn {Config Command} {linuxgpiod srst_num} [@var{chip}] @var{srst} +Set SRST GPIO number, and optionally SRST chip number. Must be specified to +enable SRST. +@end deffn + +@deffn {Config Command} {linuxgpiod led_num} [@var{chip}] @var{led} +Set activity LED GPIO number, and optionally activity LED chip number. If not +specified an activity LED is not enabled. +@end deffn + @end deffn @@ -4745,6 +4926,7 @@ compact Thumb2 instruction set. Supports also ARMv6-M and ARMv8-M cores The current implementation supports eSi-32xx cores. @item @code{esp32c2} -- this is an Espressif SoC with single RISC-V core. @item @code{esp32c3} -- this is an Espressif SoC with single RISC-V core. +@item @code{esp32s2} -- this is an Espressif SoC with single Xtensa core. @item @code{fa526} -- resembles arm920 (w/o Thumb). @item @code{feroceon} -- resembles arm926. @item @code{hla_target} -- a Cortex-M alternative to work with HL adapters like ST-Link. @@ -6449,7 +6631,7 @@ The AVR 8-bit microcontrollers from Atmel integrate flash memory. @end deffn @deffn {Flash Driver} {bluenrg-x} -STMicroelectronics BlueNRG-1, BlueNRG-2 and BlueNRG-LP Bluetooth low energy wireless system-on-chip. They include ARM Cortex-M0/M0+ core and internal flash memory. +STMicroelectronics BlueNRG-1, BlueNRG-2 and BlueNRG-LP/LPS Bluetooth low energy wireless system-on-chip. They include ARM Cortex-M0/M0+ core and internal flash memory. The driver automatically recognizes these chips using the chip identification registers, and autoconfigures itself. @@ -8464,18 +8646,19 @@ Close the OpenOCD server, disconnecting all clients (GDB, telnet, other). If option @option{error} is used, OpenOCD will return a non-zero exit code to the parent process. -Like any TCL commands, also @command{shutdown} can be redefined, e.g.: +If user types CTRL-C or kills OpenOCD, the command @command{shutdown} +will be automatically executed to cause OpenOCD to exit. + +It is possible to specify, in the TCL list @var{pre_shutdown_commands} , a +set of commands to be automatically executed before @command{shutdown} , e.g.: @example -# redefine shutdown -rename shutdown original_shutdown -proc shutdown @{@} @{ - puts "This is my implementation of shutdown" - # my own stuff before exit OpenOCD - original_shutdown -@} +lappend pre_shutdown_commands @{echo "Goodbye, my friend ..."@} +lappend pre_shutdown_commands @{echo "see you soon !"@} @end example -If user types CTRL-C or kills OpenOCD, either the command @command{shutdown} -or its replacement will be automatically executed before OpenOCD exits. +The commands in the list will be executed (in the same order they occupy +in the list) before OpenOCD exits. If one of the commands in the list +fails, then the remaining commands are not executed anymore while OpenOCD +will proceed to quit. @end deffn @anchor{debuglevel} @@ -9473,6 +9656,12 @@ is valid during the run of the event handlers and is accessible with this command. @end deffn +@deffn {Command} {arm semihosting_basedir} [dir] +@cindex ARM semihosting +Set the base directory for semihosting I/O, either an absolute path or a path relative to OpenOCD working directory. +Use "." for the current directory. +@end deffn + @section ARMv4 and ARMv5 Architecture @cindex ARMv4 @cindex ARMv5 @@ -10956,6 +11145,94 @@ STMicroelectronics, based on a proprietary 8-bit core architecture. OpenOCD supports debugging STM8 through the STMicroelectronics debug protocol SWIM, @pxref{swimtransport,,SWIM}. +@section Xtensa Architecture +Xtensa processors are based on a modular, highly flexible 32-bit RISC architecture +that can easily scale from a tiny, cache-less controller or task engine to a high-performance +SIMD/VLIW DSP provided by Cadence. +@url{https://www.cadence.com/en_US/home/tools/ip/tensilica-ip/tensilica-xtensa-controllers-and-extensible-processors.html}. + +OpenOCD supports generic Xtensa processors implementation which can be customized by +simply providing vendor-specific core configuration which controls every configurable +Xtensa architecture option, e.g. number of address registers, exceptions, reduced +size instructions support, memory banks configuration etc. Also OpenOCD supports SMP +configurations for Xtensa processors with any number of cores and allows to configure +their debug signals interconnection (so-called "break/stall networks") which control how +debug signals are distributed among cores. Xtensa "break networks" are compatible with +ARM's Cross Trigger Interface (CTI). For debugging code on Xtensa chips OpenOCD +uses JTAG protocol. Currently OpenOCD implements several Epsressif Xtensa-based chips of +@uref{https://www.espressif.com/en/products/socs, ESP32 family}. + +@subsection General Xtensa Commands + +@deffn {Command} {xtensa set_permissive} (0|1) +By default accessing memory beyond defined regions is forbidden. This commnd controls memory access address check. +When set to (1), skips access controls and address range check before read/write memory. +@end deffn + +@deffn {Command} {xtensa maskisr} (on|off) +Selects whether interrupts will be disabled during stepping over single instruction. The default configuration is (off). +@end deffn + +@deffn {Command} {xtensa smpbreak} [none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut] +Configures debug signals connection ("break network") for currently selected core. +@itemize @bullet +@item @code{none} - Core's "break/stall network" is disconnected. Core is not affected by any debug +signal from other cores. +@item @code{breakinout} - Core's "break network" is fully connected (break inputs and outputs are enabled). +Core will receive debug break signals from other cores and send such signals to them. For example when another core +is stopped due to breakpoint hit this core will be stopped too and vice versa. +@item @code{runstall} - Core's "stall network" is fully connected (stall inputs and outputs are enabled). +This feature is not well implemented and tested yet. +@item @code{BreakIn} - Core's "break-in" signal is enabled. +Core will receive debug break signals from other cores. For example when another core is +stopped due to breakpoint hit this core will be stopped too. +@item @code{BreakOut} - Core's "break-out" signal is enabled. +Core will send debug break signal to other cores. For example when this core is +stopped due to breakpoint hit other cores with enabled break-in signals will be stopped too. +@item @code{RunStallIn} - Core's "runstall-in" signal is enabled. +This feature is not well implemented and tested yet. +@item @code{DebugModeOut} - Core's "debugmode-out" signal is enabled. +This feature is not well implemented and tested yet. +@end itemize +@end deffn + +@deffn {Command} {xtensa perfmon_enable} [mask] [kernelcnt] [tracelevel] */ +COMMAND_HELPER(xtensa_cmd_perfmon_enable_do, struct xtensa *xtensa) +{ + struct xtensa_perfmon_config config = { + .mask = 0xffff, + .kernelcnt = 0, + .tracelevel = -1 /* use DEBUGLEVEL by default */ + }; + + if (CMD_ARGC < 2 || CMD_ARGC > 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + unsigned int counter_id = strtoul(CMD_ARGV[0], NULL, 0); + if (counter_id >= XTENSA_MAX_PERF_COUNTERS) { + command_print(CMD, "counter_id should be < %d", XTENSA_MAX_PERF_COUNTERS); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + config.select = strtoul(CMD_ARGV[1], NULL, 0); + if (config.select > XTENSA_MAX_PERF_SELECT) { + command_print(CMD, "select should be < %d", XTENSA_MAX_PERF_SELECT); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + if (CMD_ARGC >= 3) { + config.mask = strtoul(CMD_ARGV[2], NULL, 0); + if (config.mask > XTENSA_MAX_PERF_MASK) { + command_print(CMD, "mask should be < %d", XTENSA_MAX_PERF_MASK); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } + + if (CMD_ARGC >= 4) { + config.kernelcnt = strtoul(CMD_ARGV[3], NULL, 0); + if (config.kernelcnt > 1) { + command_print(CMD, "kernelcnt should be 0 or 1"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } + + if (CMD_ARGC >= 5) { + config.tracelevel = strtoul(CMD_ARGV[4], NULL, 0); + if (config.tracelevel > 7) { + command_print(CMD, "tracelevel should be <=7"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } + + if (config.tracelevel == -1) + config.tracelevel = xtensa->core_config->debug.irq_level; + + return xtensa_dm_perfmon_enable(&xtensa->dbg_mod, counter_id, &config); +} + +COMMAND_HANDLER(xtensa_cmd_perfmon_enable) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +/* perfmon_dump [counter_id] */ +COMMAND_HELPER(xtensa_cmd_perfmon_dump_do, struct xtensa *xtensa) +{ + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + int counter_id = -1; + if (CMD_ARGC == 1) { + counter_id = strtol(CMD_ARGV[0], NULL, 0); + if (counter_id > XTENSA_MAX_PERF_COUNTERS) { + command_print(CMD, "counter_id should be < %d", XTENSA_MAX_PERF_COUNTERS); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } + + unsigned int counter_start = (counter_id < 0) ? 0 : counter_id; + unsigned int counter_end = (counter_id < 0) ? XTENSA_MAX_PERF_COUNTERS : counter_id + 1; + for (unsigned int counter = counter_start; counter < counter_end; ++counter) { + char result_buf[128] = { 0 }; + size_t result_pos = snprintf(result_buf, sizeof(result_buf), "Counter %d: ", counter); + struct xtensa_perfmon_result result; + int res = xtensa_dm_perfmon_dump(&xtensa->dbg_mod, counter, &result); + if (res != ERROR_OK) + return res; + snprintf(result_buf + result_pos, sizeof(result_buf) - result_pos, + "%-12" PRIu64 "%s", + result.value, + result.overflow ? " (overflow)" : ""); + LOG_INFO("%s", result_buf); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(xtensa_cmd_perfmon_dump) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +COMMAND_HELPER(xtensa_cmd_mask_interrupts_do, struct xtensa *xtensa) +{ + int state = -1; + + if (CMD_ARGC < 1) { + const char *st; + state = xtensa->stepping_isr_mode; + if (state == XT_STEPPING_ISR_ON) + st = "OFF"; + else if (state == XT_STEPPING_ISR_OFF) + st = "ON"; + else + st = "UNKNOWN"; + command_print(CMD, "Current ISR step mode: %s", st); + return ERROR_OK; + } + /* Masking is ON -> interrupts during stepping are OFF, and vice versa */ + if (!strcasecmp(CMD_ARGV[0], "off")) + state = XT_STEPPING_ISR_ON; + else if (!strcasecmp(CMD_ARGV[0], "on")) + state = XT_STEPPING_ISR_OFF; + + if (state == -1) { + command_print(CMD, "Argument unknown. Please pick one of ON, OFF"); + return ERROR_FAIL; + } + xtensa->stepping_isr_mode = state; + return ERROR_OK; +} + +COMMAND_HANDLER(xtensa_cmd_mask_interrupts) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +COMMAND_HELPER(xtensa_cmd_smpbreak_do, struct target *target) +{ + int res = ERROR_OK; + uint32_t val = 0; + + if (CMD_ARGC >= 1) { + for (unsigned int i = 0; i < CMD_ARGC; i++) { + if (!strcasecmp(CMD_ARGV[0], "none")) { + val = 0; + } else if (!strcasecmp(CMD_ARGV[i], "BreakIn")) { + val |= OCDDCR_BREAKINEN; + } else if (!strcasecmp(CMD_ARGV[i], "BreakOut")) { + val |= OCDDCR_BREAKOUTEN; + } else if (!strcasecmp(CMD_ARGV[i], "RunStallIn")) { + val |= OCDDCR_RUNSTALLINEN; + } else if (!strcasecmp(CMD_ARGV[i], "DebugModeOut")) { + val |= OCDDCR_DEBUGMODEOUTEN; + } else if (!strcasecmp(CMD_ARGV[i], "BreakInOut")) { + val |= OCDDCR_BREAKINEN | OCDDCR_BREAKOUTEN; + } else if (!strcasecmp(CMD_ARGV[i], "RunStall")) { + val |= OCDDCR_RUNSTALLINEN | OCDDCR_DEBUGMODEOUTEN; + } else { + command_print(CMD, "Unknown arg %s", CMD_ARGV[i]); + command_print( + CMD, + "use either BreakInOut, None or RunStall as arguments, or any combination of BreakIn, BreakOut, RunStallIn and DebugModeOut."); + return ERROR_OK; + } + } + res = xtensa_smpbreak_set(target, val); + if (res != ERROR_OK) + command_print(CMD, "Failed to set smpbreak config %d", res); + } else { + struct xtensa *xtensa = target_to_xtensa(target); + res = xtensa_smpbreak_read(xtensa, &val); + if (res == ERROR_OK) { + command_print(CMD, "Current bits set:%s%s%s%s", + (val & OCDDCR_BREAKINEN) ? " BreakIn" : "", + (val & OCDDCR_BREAKOUTEN) ? " BreakOut" : "", + (val & OCDDCR_RUNSTALLINEN) ? " RunStallIn" : "", + (val & OCDDCR_DEBUGMODEOUTEN) ? " DebugModeOut" : "" + ); + } else { + command_print(CMD, "Failed to get smpbreak config %d", res); + } + } + return res; +} + +COMMAND_HANDLER(xtensa_cmd_smpbreak) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do, + get_current_target(CMD_CTX)); +} + +COMMAND_HELPER(xtensa_cmd_tracestart_do, struct xtensa *xtensa) +{ + struct xtensa_trace_status trace_status; + struct xtensa_trace_start_config cfg = { + .stoppc = 0, + .stopmask = XTENSA_STOPMASK_DISABLED, + .after = 0, + .after_is_words = false + }; + + /* Parse arguments */ + for (unsigned int i = 0; i < CMD_ARGC; i++) { + if ((!strcasecmp(CMD_ARGV[i], "pc")) && CMD_ARGC > i) { + char *e; + i++; + cfg.stoppc = strtol(CMD_ARGV[i], &e, 0); + cfg.stopmask = 0; + if (*e == '/') + cfg.stopmask = strtol(e, NULL, 0); + } else if ((!strcasecmp(CMD_ARGV[i], "after")) && CMD_ARGC > i) { + i++; + cfg.after = strtol(CMD_ARGV[i], NULL, 0); + } else if (!strcasecmp(CMD_ARGV[i], "ins")) { + cfg.after_is_words = 0; + } else if (!strcasecmp(CMD_ARGV[i], "words")) { + cfg.after_is_words = 1; + } else { + command_print(CMD, "Did not understand %s", CMD_ARGV[i]); + return ERROR_FAIL; + } + } + + int res = xtensa_dm_trace_status_read(&xtensa->dbg_mod, &trace_status); + if (res != ERROR_OK) + return res; + if (trace_status.stat & TRAXSTAT_TRACT) { + LOG_WARNING("Silently stop active tracing!"); + res = xtensa_dm_trace_stop(&xtensa->dbg_mod, false); + if (res != ERROR_OK) + return res; + } + + res = xtensa_dm_trace_start(&xtensa->dbg_mod, &cfg); + if (res != ERROR_OK) + return res; + + xtensa->trace_active = true; + command_print(CMD, "Trace started."); + return ERROR_OK; +} + +COMMAND_HANDLER(xtensa_cmd_tracestart) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +COMMAND_HELPER(xtensa_cmd_tracestop_do, struct xtensa *xtensa) +{ + struct xtensa_trace_status trace_status; + + int res = xtensa_dm_trace_status_read(&xtensa->dbg_mod, &trace_status); + if (res != ERROR_OK) + return res; + + if (!(trace_status.stat & TRAXSTAT_TRACT)) { + command_print(CMD, "No trace is currently active."); + return ERROR_FAIL; + } + + res = xtensa_dm_trace_stop(&xtensa->dbg_mod, true); + if (res != ERROR_OK) + return res; + + xtensa->trace_active = false; + command_print(CMD, "Trace stop triggered."); + return ERROR_OK; +} + +COMMAND_HANDLER(xtensa_cmd_tracestop) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +COMMAND_HELPER(xtensa_cmd_tracedump_do, struct xtensa *xtensa, const char *fname) +{ + struct xtensa_trace_config trace_config; + struct xtensa_trace_status trace_status; + uint32_t memsz, wmem; + + int res = xtensa_dm_trace_status_read(&xtensa->dbg_mod, &trace_status); + if (res != ERROR_OK) + return res; + + if (trace_status.stat & TRAXSTAT_TRACT) { + command_print(CMD, "Tracing is still active. Please stop it first."); + return ERROR_FAIL; + } + + res = xtensa_dm_trace_config_read(&xtensa->dbg_mod, &trace_config); + if (res != ERROR_OK) + return res; + + if (!(trace_config.ctrl & TRAXCTRL_TREN)) { + command_print(CMD, "No active trace found; nothing to dump."); + return ERROR_FAIL; + } + + memsz = trace_config.memaddr_end - trace_config.memaddr_start + 1; + LOG_INFO("Total trace memory: %d words", memsz); + if ((trace_config.addr & + ((TRAXADDR_TWRAP_MASK << TRAXADDR_TWRAP_SHIFT) | TRAXADDR_TWSAT)) == 0) { + /*Memory hasn't overwritten itself yet. */ + wmem = trace_config.addr & TRAXADDR_TADDR_MASK; + LOG_INFO("...but trace is only %d words", wmem); + if (wmem < memsz) + memsz = wmem; + } else { + if (trace_config.addr & TRAXADDR_TWSAT) { + LOG_INFO("Real trace is many times longer than that (overflow)"); + } else { + uint32_t trc_sz = (trace_config.addr >> TRAXADDR_TWRAP_SHIFT) & TRAXADDR_TWRAP_MASK; + trc_sz = (trc_sz * memsz) + (trace_config.addr & TRAXADDR_TADDR_MASK); + LOG_INFO("Real trace is %d words, but the start has been truncated.", trc_sz); + } + } + + uint8_t *tracemem = malloc(memsz * 4); + if (!tracemem) { + command_print(CMD, "Failed to alloc memory for trace data!"); + return ERROR_FAIL; + } + res = xtensa_dm_trace_data_read(&xtensa->dbg_mod, tracemem, memsz * 4); + if (res != ERROR_OK) { + free(tracemem); + return res; + } + + int f = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (f <= 0) { + free(tracemem); + command_print(CMD, "Unable to open file %s", fname); + return ERROR_FAIL; + } + if (write(f, tracemem, memsz * 4) != (int)memsz * 4) + command_print(CMD, "Unable to write to file %s", fname); + else + command_print(CMD, "Written %d bytes of trace data to %s", memsz * 4, fname); + close(f); + + bool is_all_zeroes = true; + for (unsigned int i = 0; i < memsz * 4; i++) { + if (tracemem[i] != 0) { + is_all_zeroes = false; + break; + } + } + free(tracemem); + if (is_all_zeroes) + command_print( + CMD, + "WARNING: File written is all zeroes. Are you sure you enabled trace memory?"); + + return ERROR_OK; +} + +COMMAND_HANDLER(xtensa_cmd_tracedump) +{ + if (CMD_ARGC != 1) { + command_print(CMD, "Command takes exactly 1 parameter.Need filename to dump to as output!"); + return ERROR_FAIL; + } + + return CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do, + target_to_xtensa(get_current_target(CMD_CTX)), CMD_ARGV[0]); +} + +const struct command_registration xtensa_command_handlers[] = { + { + .name = "set_permissive", + .handler = xtensa_cmd_permissive_mode, + .mode = COMMAND_ANY, + .help = "When set to 1, enable Xtensa permissive mode (less client-side checks)", + .usage = "[0|1]", + }, + { + .name = "maskisr", + .handler = xtensa_cmd_mask_interrupts, + .mode = COMMAND_ANY, + .help = "mask Xtensa interrupts at step", + .usage = "['on'|'off']", + }, + { + .name = "smpbreak", + .handler = xtensa_cmd_smpbreak, + .mode = COMMAND_ANY, + .help = "Set the way the CPU chains OCD breaks", + .usage = + "[none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut]", + }, + { + .name = "perfmon_enable", + .handler = xtensa_cmd_perfmon_enable, + .mode = COMMAND_EXEC, + .help = "Enable and start performance counter", + .usage = "