diff --git a/README b/README index 581082e6..f2d704b4 100644 --- a/README +++ b/README @@ -123,7 +123,7 @@ XScale, Intel Quark. Flash drivers ------------- -ADUC702x, AT91SAM, AVR, CFI, DSP5680xx, EFM32, EM357, FM3, FM4, Kinetis, +ADUC702x, AT91SAM, ATH79, AVR, CFI, DSP5680xx, EFM32, EM357, FM3, FM4, Kinetis, LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPCSPIFI, Marvell QSPI, Milandr, NIIET, NuMicro, PIC32mx, PSoC4, SiM3x, Stellaris, STM32, STMSMI, STR7x, STR9x, nRF51; NAND controllers of AT91SAM9, LPC3180, LPC32xx, diff --git a/configure.ac b/configure.ac index 2543eca3..c680bda7 100644 --- a/configure.ac +++ b/configure.ac @@ -129,6 +129,9 @@ m4_define([USB0_ADAPTERS], m4_define([HIDAPI_ADAPTERS], [[[cmsis_dap], [CMSIS-DAP Compliant Debugger], [CMSIS_DAP]]]) +m4_define([HIDAPI_USB1_ADAPTERS], + [[[kitprog], [Cypress KitProg Programmer], [KITPROG]]]) + m4_define([LIBFTDI_ADAPTERS], [[[usb_blaster], [Altera USB-Blaster Compatible], [USB_BLASTER]], [[presto], [ASIX Presto Adapter], [PRESTO]], @@ -243,6 +246,7 @@ AC_ARG_ADAPTERS([ USB_ADAPTERS, USB0_ADAPTERS, HIDAPI_ADAPTERS, + HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS, LIBJAYLINK_ADAPTERS ],[auto]) @@ -294,11 +298,15 @@ AS_CASE(["${host_cpu}"], AC_ARG_ENABLE([bcm2835gpio], AS_HELP_STRING([--enable-bcm2835gpio], [Enable building support for bitbanging on BCM2835 (as found in Raspberry Pi)]), [build_bcm2835gpio=$enableval], [build_bcm2835gpio=no]) + 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]) ], [ build_ep93xx=no build_at91rm9200=no build_bcm2835gpio=no + build_imx_gpio=no ]) AC_ARG_ENABLE([gw16012], @@ -339,6 +347,10 @@ AC_ARG_ENABLE([internal-libjaylink], [Disable building internal libjaylink]), [use_internal_libjaylink=$enableval], [use_internal_libjaylink=yes]) +AC_ARG_ENABLE([target64], + AS_HELP_STRING([--disable-target64], [Disable 64-bit target address]), + [build_target64=$enableval], [build_target64=yes]) + build_minidriver=no AC_MSG_CHECKING([whether to enable ZY1000 minidriver]) AS_IF([test "x$build_zy1000" = "xyes"], [ @@ -508,6 +520,13 @@ AS_IF([test "x$build_bcm2835gpio" = "xyes"], [ AC_DEFINE([BUILD_BCM2835GPIO], [0], [0 if you don't want bcm2835gpio.]) ]) +AS_IF([test "x$build_imx_gpio" = "xyes"], [ + build_bitbang=yes + AC_DEFINE([BUILD_IMX_GPIO], [1], [1 if you want imx_gpio.]) +], [ + AC_DEFINE([BUILD_IMX_GPIO], [0], [0 if you don't want imx_gpio.]) +]) + AS_IF([test "x$parport_use_ppdev" = "xyes"], [ AC_DEFINE([PARPORT_USE_PPDEV], [1], [1 if you want parport to use ppdev.]) ], [ @@ -572,6 +591,13 @@ AS_IF([test "x$build_sysfsgpio" = "xyes"], [ AC_DEFINE([BUILD_SYSFSGPIO], [0], [0 if you don't want SysfsGPIO driver.]) ]) +AS_IF([test "x$build_target64" = "xyes"], [ + AC_DEFINE([BUILD_TARGET64], [1], [1 if you want 64-bit addresses.]) +], [ + AC_DEFINE([BUILD_TARGET64], [0], [0 if you don't want 64-bit addresses.]) +]) + + PKG_CHECK_MODULES([LIBUSB1], [libusb-1.0], [ use_libusb1=yes AC_DEFINE([HAVE_LIBUSB1], [1], [Define if you have libusb-1.x]) @@ -627,6 +653,7 @@ PROCESS_ADAPTERS([USB1_ADAPTERS], ["x$use_libusb1" = "xyes"], [libusb-1.x]) PROCESS_ADAPTERS([USB_ADAPTERS], ["x$use_libusb1" = "xyes" -o "x$use_libusb0" = "xyes"], [libusb-1.x or libusb-0.1]) PROCESS_ADAPTERS([USB0_ADAPTERS], ["x$use_libusb0" = "xyes"], [libusb-0.1]) PROCESS_ADAPTERS([HIDAPI_ADAPTERS], ["x$use_hidapi" = "xyes"], [hidapi]) +PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libusb1" = "xyes"], [hidapi and libusb-1.x]) PROCESS_ADAPTERS([LIBFTDI_ADAPTERS], ["x$use_libftdi" = "xyes"], [libftdi]) PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_libusb1" = "xyes" -a "x$use_internal_libjaylink" = "xyes" -o "x$use_libjaylink" = "xyes"], [libusb-1.x or libjaylink-0.1]) @@ -670,6 +697,7 @@ AM_CONDITIONAL([ZY1000_MASTER], [test "x$build_zy1000_master" = "xyes"]) AM_CONDITIONAL([IOUTIL], [test "x$build_ioutil" = "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([BITBANG], [test "x$build_bitbang" = "xyes"]) AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes" -o "x$build_jtag_vpi" = "xyes"]) AM_CONDITIONAL([USB_BLASTER_DRIVER], [test "x$enable_usb_blaster" != "xno" -o "x$enable_usb_blaster_2" != "xno"]) @@ -689,6 +717,7 @@ AM_CONDITIONAL([BITQ], [test "x$build_bitq" = "xyes"]) AM_CONDITIONAL([USE_LIBFTDI], [test "x$use_libftdi" = "xyes"]) AM_CONDITIONAL([USE_HIDAPI], [test "x$use_hidapi" = "xyes"]) AM_CONDITIONAL([USE_LIBJAYLINK], [test "x$use_libjaylink" = "xyes"]) +AM_CONDITIONAL([TARGET64], [test "x$build_target64" = "xyes"]) AM_CONDITIONAL([MINIDRIVER], [test "x$build_minidriver" = "xyes"]) AM_CONDITIONAL([MINIDRIVER_DUMMY], [test "x$build_minidriver_dummy" = "xyes"]) @@ -756,7 +785,8 @@ echo echo OpenOCD configuration summary echo -------------------------------------------------- m4_foreach([adapter], [USB1_ADAPTERS, USB_ADAPTERS, USB0_ADAPTERS, - HIDAPI_ADAPTERS, LIBFTDI_ADAPTERS, LIBJAYLINK_ADAPTERS], + HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS, + LIBJAYLINK_ADAPTERS], [s=m4_format(["%-40s"], ADAPTER_DESC([adapter])) AS_CASE([$ADAPTER_VAR([adapter])], [auto], [ diff --git a/contrib/60-openocd.rules b/contrib/60-openocd.rules index 3da1f73e..da760f88 100644 --- a/contrib/60-openocd.rules +++ b/contrib/60-openocd.rules @@ -62,6 +62,12 @@ ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", MODE="660", GROUP="plugdev", # STLink v2-1 ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", MODE="660", GROUP="plugdev", TAG+="uaccess" +# Cypress KitProg in KitProg mode +ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="f139", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# Cypress KitProg in CMSIS-DAP mode +ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="f138", MODE="660", GROUP="plugdev", TAG+="uaccess" + # Hilscher NXHX Boards ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="660", GROUP="plugdev", TAG+="uaccess" @@ -122,6 +128,11 @@ ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="660", GROUP="plugdev", # TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="660", GROUP="plugdev", TAG+="uaccess" +# Ambiq Micro EVK and Debug boards. +ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6010", MODE="664", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6011", MODE="664", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="1106", MODE="664", GROUP="plugdev", TAG+="uaccess" + # Marvell Sheevaplug ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="660", GROUP="plugdev", TAG+="uaccess" diff --git a/contrib/loaders/flash/stm32lx.S b/contrib/loaders/flash/stm32lx.S index 88deed32..8f9fd0b2 100644 --- a/contrib/loaders/flash/stm32lx.S +++ b/contrib/loaders/flash/stm32lx.S @@ -8,6 +8,9 @@ * Copyright (C) 2011 Clement Burin des Roziers * * clement.burin-des-roziers@hikob.com * * * + * Copyright (C) 2017 Armin van der Togt * + * armin@otheruse.nl * + * * * 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 * @@ -28,7 +31,7 @@ // Build : arm-eabi-gcc -c stm32lx.S .text .syntax unified - .cpu cortex-m3 + .cpu cortex-m0 .thumb .thumb_func .global write @@ -39,24 +42,21 @@ r2 - count */ - // Set 0 to r3 - movs r3, #0 + // r2 = source + count * 4 + lsls r2, r2, #2 + adds r2, r1, r2 // Go to compare - b.n test_done - + b test_done write_word: - // Load one word from address in r0, increment by 4 - ldr.w ip, [r1], #4 - // Store the word to address in r1, increment by 4 - str.w ip, [r0], #4 - // Increment r3 - adds r3, #1 - + // load word from address in r1 and increase r1 by 4 + ldmia r1!, {r3} + // store word to address in r0 and increase r0 by 4 + stmia r0!, {r3} test_done: - // Compare r3 and r2 - cmp r3, r2 - // Loop if not zero - bcc.n write_word + // compare r1 and r2 + cmp r1, r2 + // loop if not equal + bne write_word // Set breakpoint to exit bkpt #0x00 diff --git a/doc/openocd.texi b/doc/openocd.texi index 45b341c4..59d2d4f1 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -595,6 +595,9 @@ produced, PDF schematics are easily found and it is easy to make. @item @b{bcm2835gpio} @* A BCM2835-based board (e.g. Raspberry Pi) using the GPIO pins of the expansion header. +@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{jtag_vpi} @* A JTAG driver acting as a client for the JTAG VPI server interface. @* Link: @url{http://github.com/fjullien/jtag_vpi} @@ -2742,6 +2745,62 @@ As a configuration command, it can be used only before 'init'. @end deffn @end deffn +@deffn {Interface Driver} {kitprog} +This driver is for Cypress Semiconductor's KitProg adapters. The KitProg is an +SWD-only adapter that is designed to be used with Cypress's PSoC and PRoC device +families, but it is possible to use it with some other devices. If you are using +this adapter with a PSoC or a PRoC, you may need to add +@command{kitprog_init_acquire_psoc} or @command{kitprog acquire_psoc} to your +configuration script. + +Note that this driver is for the proprietary KitProg protocol, not the CMSIS-DAP +mode introduced in firmware 2.14. If the KitProg is in CMSIS-DAP mode, it cannot +be used with this driver, and must either be used with the cmsis-dap driver or +switched back to KitProg mode. See the Cypress KitProg User Guide for +instructions on how to switch KitProg modes. + +Known limitations: +@itemize @bullet +@item The frequency of SWCLK cannot be configured, and varies between 1.6 MHz +and 2.7 MHz. +@item For firmware versions below 2.14, "JTAG to SWD" sequences are replaced by +"SWD line reset" in the driver. This is for two reasons. First, the KitProg does +not support sending arbitrary SWD sequences, and only firmware 2.14 and later +implement both "JTAG to SWD" and "SWD line reset" in firmware. Earlier firmware +versions only implement "SWD line reset". Second, due to a firmware quirk, an +SWD sequence must be sent after every target reset in order to re-establish +communications with the target. +@item Due in part to the limitation above, KitProg devices with firmware below +version 2.14 will need to use @command{kitprog_init_acquire_psoc} in order to +communicate with PSoC 5LP devices. This is because, assuming debug is not +disabled on the PSoC, the PSoC 5LP needs its JTAG interface switched to SWD +mode before communication can begin, but prior to firmware 2.14, "JTAG to SWD" +could only be sent with an acquisition sequence. +@end itemize + +@deffn {Config Command} {kitprog_init_acquire_psoc} +Indicate that a PSoC acquisition sequence needs to be run during adapter init. +Please be aware that the acquisition sequence hard-resets the target. +@end deffn + +@deffn {Config Command} {kitprog_serial} serial +Select a KitProg device by its @var{serial}. If left unspecified, the first +device detected by OpenOCD will be used. +@end deffn + +@deffn {Command} {kitprog acquire_psoc} +Run a PSoC acquisition sequence immediately. Typically, this should not be used +outside of the target-specific configuration scripts since it hard-resets the +target as a side-effect. +This is necessary for "reset halt" on some PSoC 4 series devices. +@end deffn + +@deffn {Command} {kitprog info} +Display various adapter information, such as the hardware version, firmware +version, and target voltage. +@end deffn +@end deffn + @deffn {Interface Driver} {parport} Supports PC parallel port bit-banging cables: Wigglers, PLD download cable, and more. @@ -2936,6 +2995,18 @@ pinout. @end deffn +@deffn {Interface Driver} {imx_gpio} +i.MX SoC is present in many community boards. Wandboard is an example +of the one which is most popular. + +This driver is mostly the same as bcm2835gpio. + +See @file{interface/imx-native.cfg} for a sample config and +pinout. + +@end deffn + + @deffn {Interface Driver} {openjtag} OpenJTAG compatible USB adapter. This defines some driver-specific commands: @@ -4004,6 +4075,7 @@ At this writing, the supported CPU types are: @item @code{cortex_a} -- this is an ARMv7 core with an MMU @item @code{cortex_m} -- this is an ARMv7 core, supporting only the compact Thumb2 instruction set. +@item @code{aarch64} -- this is an ARMv8-A core with an MMU @item @code{dragonite} -- resembles arm966e @item @code{dsp563xx} -- implements Freescale's 24-bit DSP. (Support for this is still incomplete.) @@ -4036,7 +4108,7 @@ The CPU name used by OpenOCD will reflect the CPU design that was licenced, not a vendor brand which incorporates that design. Name prefixes like arm7, arm9, arm11, and cortex reflect design generations; -while names like ARMv4, ARMv5, ARMv6, and ARMv7 +while names like ARMv4, ARMv5, ARMv6, ARMv7 and ARMv8 reflect an architecture version implemented by a CPU design. @anchor{targetconfiguration} @@ -4180,6 +4252,10 @@ access the target for debugging. @var{ap_number} is the numeric index of the DAP AP the target is connected to. 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. @end itemize @end deffn @@ -4651,9 +4727,10 @@ and write the contents to the binary @file{filename}. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {flash verify_bank} num filename offset +@deffn Command {flash verify_bank} num filename [offset] Compare the contents of the binary file @var{filename} with the contents of the -flash @var{num} starting at @var{offset}. Fails if the contents do not match. +flash bank @var{num} starting at @var{offset}. If @var{offset} is omitted, +start at the beginning of the flash bank. Fail if the contents do not match. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @@ -4922,6 +4999,45 @@ flash bank $_FLASHNAME mrvlqspi 0x0 0 0 0 $_TARGETNAME 0x46010000 @end deffn +@deffn {Flash Driver} ath79 +@cindex Atheros ath79 SPI driver +@cindex ath79 +Members of ATH79 SoC family from Atheros include a SPI interface with 3 +chip selects. +On reset a SPI flash connected to the first chip select (CS0) is made +directly read-accessible in the CPU address space (up to 16MBytes) +and is usually used to store the bootloader and operating system. +Normal OpenOCD commands like @command{mdw} can be used to display +the flash content while it is in memory-mapped mode (only the first +4MBytes are accessible without additional configuration on reset). + +The setup command only requires the @var{base} parameter in order +to identify the memory bank. The actual value for the base address +is not otherwise used by the driver. However the mapping is passed +to gdb. Thus for the memory mapped flash (chipselect CS0) the base +address should be the actual memory mapped base address. For unmapped +chipselects (CS1 and CS2) care should be taken to use a base address +that does not overlap with real memory regions. +Additional information, like flash size, are detected automatically. +An optional additional parameter sets the chipselect for the bank, +with the default CS0. +CS1 and CS2 require additional GPIO setup before they can be used +since the alternate function must be enabled on the GPIO pin +CS1/CS2 is routed to on the given SoC. + +@example +flash bank $_FLASHNAME ath79 0 0 0 0 $_TARGETNAME + +# When using multiple chipselects the base should be different for each, +# otherwise the write_image command is not able to distinguish the +# banks. +flash bank flash0 ath79 0x00000000 0 0 0 $_TARGETNAME cs0 +flash bank flash1 ath79 0x10000000 0 0 0 $_TARGETNAME cs1 +flash bank flash2 ath79 0x20000000 0 0 0 $_TARGETNAME cs2 +@end example + +@end deffn + @subsection Internal Flash (Microcontrollers) @deffn {Flash Driver} aduc702x @@ -7854,13 +7970,14 @@ coprocessor 14 register 7 itself) but all current ARM11 cores @emph{except the ARM1176} use the same six bits. @end deffn -@section ARMv7 Architecture +@section ARMv7 and ARMv8 Architecture @cindex ARMv7 +@cindex ARMv8 -@subsection ARMv7 Debug Access Port (DAP) specific commands +@subsection ARMv7 and ARMv8 Debug Access Port (DAP) specific commands @cindex Debug Access Port @cindex DAP -These commands are specific to ARM architecture v7 Debug Access Port (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. @@ -8114,6 +8231,29 @@ the peripherals. @xref{targetevents,,Target Events}. @end deffn +@subsection ARMv8-A specific commands +@cindex ARMv8-A +@cindex aarch64 + +@deffn Command {aarch64 cache_info} +Display information about target caches +@end deffn + +@deffn Command {aarch64 dbginit} +This command enables debugging by clearing the OS Lock and sticky power-down and reset +indications. It also establishes the expected, basic cross-trigger configuration the aarch64 +target code relies on. In a configuration file, the command would typically be called from a +@code{reset-end} or @code{reset-deassert-post} handler, to re-enable debugging after a system reset. +However, normally it is not necessary to use the command at all. +@end deffn + +@deffn Command {aarch64 smp_on|smp_off} +Enable and disable SMP handling. The state of SMP handling influences the way targets in an SMP group +are handled by the run control. With SMP handling enabled, issuing halt or resume to one core will trigger +halting or resuming of all cores in the group. The command @code{target smp} defines which targets are in the SMP +group. With SMP handling disabled, all targets need to be treated individually. +@end deffn + @section Intel Architecture Intel Quark X10xx is the first product in the Quark family of SoCs. It is an IA-32 diff --git a/setlocal.sh b/setlocal.sh index 6a22119c..3d5e6534 100755 --- a/setlocal.sh +++ b/setlocal.sh @@ -13,6 +13,11 @@ pkill openocd openocd -s $OPENOCD_SCRIPTS -f stm32"$1".cfg -c "stm_flash $2" } +function stm32_flsh_addr { +pkill openocd +openocd -s $OPENOCD_SCRIPTS -f stm32"$1".cfg -c "stm_flash_addr $2 $3" +} + function stm32_dbg { pkill openocd openocd -s $OPENOCD_SCRIPTS -f stm32"$1".cfg & diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 727e4f2f..5a992fee 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -15,6 +15,7 @@ NOR_DRIVERS = \ %D%/at91samd.c \ %D%/at91sam3.c \ %D%/at91sam7.c \ + %D%/ath79.c \ %D%/atsamv.c \ %D%/avrf.c \ %D%/cfi.c \ diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c index 94d5bfda..ff75b418 100644 --- a/src/flash/nor/at91sam4.c +++ b/src/flash/nor/at91sam4.c @@ -1340,6 +1340,74 @@ static const struct sam4_chip_details all_sam4_details[] = { } }, + /* atsamg55g19 */ + { + .chipid_cidr = 0x24470ae0, + .name = "atsamg55g19", + .total_flash_size = 512 * 1024, + .total_sram_size = 160 * 1024, + .n_gpnvms = 2, + .n_banks = 1, + + { +/* .bank[0] = */ + { + .probed = 0, + .pChip = NULL, + .pBank = NULL, + .bank_number = 0, + .base_address = FLASH_BANK_BASE_S, + .controller_address = 0x400e0a00, + .flash_wait_states = 5, + .present = 1, + .size_bytes = 512 * 1024, + .nsectors = 64, + .sector_size = 8192, + .page_size = 512, + }, +/* .bank[1] = */ + { + .present = 0, + .probed = 0, + .bank_number = 1, + }, + } + }, + + /* atsamg55j19 */ + { + .chipid_cidr = 0x24570ae0, + .name = "atsamg55j19", + .total_flash_size = 512 * 1024, + .total_sram_size = 160 * 1024, + .n_gpnvms = 2, + .n_banks = 1, + + { +/* .bank[0] = */ + { + .probed = 0, + .pChip = NULL, + .pBank = NULL, + .bank_number = 0, + .base_address = FLASH_BANK_BASE_S, + .controller_address = 0x400e0a00, + .flash_wait_states = 5, + .present = 1, + .size_bytes = 512 * 1024, + .nsectors = 64, + .sector_size = 8192, + .page_size = 512, + }, +/* .bank[1] = */ + { + .present = 0, + .probed = 0, + .bank_number = 1, + }, + } + }, + /* terminate */ { .chipid_cidr = 0, @@ -1917,6 +1985,8 @@ static const struct archnames { unsigned value; const char *name; } archnames[] { 0x42, "AT91x42 Series" }, { 0x43, "SAMG51 Series" }, + { 0x44, "SAMG55 Series (49-pin WLCSP)" }, + { 0x45, "SAMG55 Series (64-pin)" }, { 0x47, "SAMG53 Series" }, { 0x55, "AT91x55 Series" }, diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index 2673b0ee..f018e893 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -36,6 +36,7 @@ #define SAMD_DSU_STATUSA 1 /* DSU status register */ #define SAMD_DSU_DID 0x18 /* Device ID register */ +#define SAMD_DSU_CTRL_EXT 0x100 /* CTRL register, external access */ #define SAMD_NVMCTRL_CTRLA 0x00 /* NVM control A register */ #define SAMD_NVMCTRL_CTRLB 0x04 /* NVM control B register */ @@ -859,18 +860,23 @@ COMMAND_HANDLER(samd_handle_info_command) COMMAND_HANDLER(samd_handle_chip_erase_command) { struct target *target = get_current_target(CMD_CTX); + int res = ERROR_FAIL; if (target) { /* Enable access to the DSU by disabling the write protect bit */ target_write_u32(target, SAMD_PAC1, (1<<1)); + /* intentionally without error checking - not accessible on secured chip */ + /* Tell the DSU to perform a full chip erase. It takes about 240ms to * perform the erase. */ - target_write_u8(target, SAMD_DSU, (1<<4)); - - command_print(CMD_CTX, "chip erased"); + res = target_write_u8(target, SAMD_DSU + SAMD_DSU_CTRL_EXT, (1<<4)); + if (res == ERROR_OK) + command_print(CMD_CTX, "chip erase started"); + else + command_print(CMD_CTX, "write to DSU CTRL failed"); } - return ERROR_OK; + return res; } COMMAND_HANDLER(samd_handle_set_security_command) diff --git a/src/flash/nor/ath79.c b/src/flash/nor/ath79.c new file mode 100644 index 00000000..451e8436 --- /dev/null +++ b/src/flash/nor/ath79.c @@ -0,0 +1,901 @@ +/*************************************************************************** + * Copyright (C) 2015 by Tobias Diedrich * + * * + * * + * based on the stmsmi code written by Antonio Borneo * + * * + * * + * 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. * + * * + ***************************************************************************/ +/* + * Driver for the Atheros AR7xxx/AR9xxx SPI flash interface. + * + * Since no SPI mode register is present, presumably only + * SPI "mode 3" (CPOL=1 and CPHA=1) is supported. + * + * The SPI interface supports up to 3 chip selects, however the SPI flash + * used for booting the system must be connected to CS0. + * + * On boot, the first 4MiB of flash space are memory-mapped into the + * area bf000000 - bfffffff (4 copies), so the MIPS bootstrap + * vector bfc00000 is mapped to the beginning of the flash. + * + * By writing a 1 to the REMAP_DISABLE bit in the SPI_CONTROL register, + * the full area of 16MiB is mapped. + * + * By writing a 0 to the SPI_FUNCTION_SELECT register (write-only dword + * register @bf000000), memory mapping is disabled and the SPI registers + * are exposed to the CPU instead: + * bf000000 SPI_FUNCTION_SELECT + * bf000004 SPI_CONTROL + * bf000008 SPI_IO_CONTROL + * bf00000c SPI_READ_DATA + * + * When not memory-mapped, the SPI interface is essentially bitbanged + * using SPI_CONTROL and SPI_IO_CONTROL with the only hardware-assistance + * being the 32bit read-only shift-register SPI_READ_DATA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include "spi.h" +#include +#include +#include +#include +#include +#include + +#define BITS_PER_BYTE 8 + +#define ATH79_REG_FS 0 +#define ATH79_REG_CLOCK 4 +#define ATH79_REG_WRITE 8 +#define ATH79_REG_DATA 12 + +#define ATH79_SPI_CS_ALLHI 0x70000 +#define ATH79_SPI_CS0_HI 0x10000 +#define ATH79_SPI_CS1_HI 0x20000 +#define ATH79_SPI_CS2_HI 0x40000 +#define ATH79_SPI_CE_HI 0x00100 +#define ATH79_SPI_DO_HI 0x00001 + +#define ATH79_XFER_FINAL 0x00000001 +#define ATH79_XFER_PARTIAL 0x00000000 + +/* Timeout in ms */ +#define ATH79_MAX_TIMEOUT (3000) + +struct ath79_spi_ctx { + uint8_t *page_buf; + int pre_deselect; + int post_deselect; +}; + +struct ath79_flash_bank { + int probed; + int chipselect; + uint32_t io_base; + const struct flash_device *dev; + struct ath79_spi_ctx spi; +}; + +struct ath79_target { + char *name; + uint32_t tap_idcode; + uint32_t io_base; +}; + +static const struct ath79_target target_devices[] = { + /* name, tap_idcode, io_base */ + { "ATH79", 0x00000001, 0xbf000000 }, + { NULL, 0, 0 } +}; + +static const uint32_t ath79_chipselects[] = { + (~ATH79_SPI_CS0_HI & ATH79_SPI_CS_ALLHI), + (~ATH79_SPI_CS1_HI & ATH79_SPI_CS_ALLHI), + (~ATH79_SPI_CS2_HI & ATH79_SPI_CS_ALLHI), +}; + +static void ath79_pracc_addn(struct pracc_queue_info *ctx, + const uint32_t *instr, + int n) +{ + for (int i = 0; i < n; i++) + pracc_add(ctx, 0, instr[i]); +} + +static int ath79_spi_bitbang_codegen(struct ath79_flash_bank *ath79_info, + struct pracc_queue_info *ctx, + uint8_t *data, int len, + int partial_xfer) +{ + uint32_t cs_high = ATH79_SPI_CS_ALLHI; + uint32_t cs_low = ath79_chipselects[ath79_info->chipselect]; + uint32_t clock_high = cs_low | ATH79_SPI_CE_HI; + uint32_t clock_low = cs_low; + uint32_t pracc_out = 0; + uint32_t io_base = ath79_info->io_base; + + const uint32_t preamble1[] = { + /* $15 = MIPS32_PRACC_BASE_ADDR */ + MIPS32_LUI(0, 15, PRACC_UPPER_BASE_ADDR), + /* $1 = io_base */ + MIPS32_LUI(0, 1, UPPER16(io_base)), + }; + ath79_pracc_addn(ctx, preamble1, ARRAY_SIZE(preamble1)); + if (ath79_info->spi.pre_deselect) { + /* Clear deselect flag so we don't deselect again if + * this is a partial xfer. + */ + ath79_info->spi.pre_deselect = 0; + const uint32_t pre_deselect[] = { + /* [$1 + FS] = 1 (enable flash io register access) */ + MIPS32_LUI(0, 2, UPPER16(1)), + MIPS32_ORI(0, 2, 2, LOWER16(1)), + MIPS32_SW(0, 2, ATH79_REG_FS, 1), + /* deselect flash just in case */ + /* $2 = SPI_CS_DIS */ + MIPS32_LUI(0, 2, UPPER16(cs_high)), + MIPS32_ORI(0, 2, 2, LOWER16(cs_high)), + /* [$1 + WRITE] = $2 */ + MIPS32_SW(0, 2, ATH79_REG_WRITE, 1), + }; + ath79_pracc_addn(ctx, pre_deselect, ARRAY_SIZE(pre_deselect)); + } + const uint32_t preamble2[] = { + /* t0 = CLOCK_LOW + 0-bit */ + MIPS32_LUI(0, 8, UPPER16((clock_low + 0))), + MIPS32_ORI(0, 8, 8, LOWER16((clock_low + 0))), + /* t1 = CLOCK_LOW + 1-bit */ + MIPS32_LUI(0, 9, UPPER16((clock_low + 1))), + MIPS32_ORI(0, 9, 9, LOWER16((clock_low + 1))), + /* t2 = CLOCK_HIGH + 0-bit */ + MIPS32_LUI(0, 10, UPPER16((clock_high + 0))), + MIPS32_ORI(0, 10, 10, LOWER16((clock_high + 0))), + /* t3 = CLOCK_HIGH + 1-bit */ + MIPS32_LUI(0, 11, UPPER16((clock_high + 1))), + MIPS32_ORI(0, 11, 11, LOWER16((clock_high + 1))), + }; + ath79_pracc_addn(ctx, preamble2, ARRAY_SIZE(preamble2)); + + for (int i = 0; i < len; i++) { + uint8_t x = data[i]; + + /* Generate bitbang code for one byte, highest bit first .*/ + for (int j = BITS_PER_BYTE - 1; j >= 0; j--) { + int bit = ((x >> j) & 1); + + if (bit) { + /* [$1 + WRITE] = t1 */ + pracc_add(ctx, 0, + MIPS32_SW(0, 9, ATH79_REG_WRITE, 1)); + /* [$1 + WRITE] = t3 */ + pracc_add(ctx, 0, + MIPS32_SW(0, 11, ATH79_REG_WRITE, 1)); + } else { + /* [$1 + WRITE] = t0 */ + pracc_add(ctx, 0, + MIPS32_SW(0, 8, ATH79_REG_WRITE, 1)); + /* [$1 + WRITE] = t2 */ + pracc_add(ctx, 0, + MIPS32_SW(0, 10, ATH79_REG_WRITE, 1)); + } + } + if (i % 4 == 3) { + /* $3 = [$1 + DATA] */ + pracc_add(ctx, 0, MIPS32_LW(0, 3, ATH79_REG_DATA, 1)); + /* [OUTi] = $3 */ + pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + pracc_out, + MIPS32_SW(0, 3, PRACC_OUT_OFFSET + + pracc_out, 15)); + pracc_out += 4; + } + } + if (len & 3) { /* not a multiple of 4 bytes */ + /* $3 = [$1 + DATA] */ + pracc_add(ctx, 0, MIPS32_LW(0, 3, ATH79_REG_DATA, 1)); + /* [OUTi] = $3 */ + pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + pracc_out, + MIPS32_SW(0, 3, PRACC_OUT_OFFSET + pracc_out, 15)); + pracc_out += 4; + } + + if (ath79_info->spi.post_deselect && !partial_xfer) { + const uint32_t post_deselect[] = { + /* $2 = SPI_CS_DIS */ + MIPS32_LUI(0, 2, UPPER16(cs_high)), + MIPS32_ORI(0, 2, 2, LOWER16(cs_high)), + /* [$1 + WRITE] = $2 */ + MIPS32_SW(0, 2, ATH79_REG_WRITE, 1), + + /* [$1 + FS] = 0 (disable flash io register access) */ + MIPS32_XORI(0, 2, 2, 0), + MIPS32_SW(0, 2, ATH79_REG_FS, 1), + }; + ath79_pracc_addn(ctx, post_deselect, ARRAY_SIZE(post_deselect)); + } + + /* common pracc epilogue */ + /* jump to start */ + pracc_add(ctx, 0, MIPS32_B(0, NEG16(ctx->code_count + 1))); + /* restore $15 from DeSave */ + pracc_add(ctx, 0, MIPS32_MFC0(0, 15, 31, 0)); + + return pracc_out / 4; +} + +static int ath79_spi_bitbang_chunk(struct flash_bank *bank, + uint8_t *data, int len, int *transferred) +{ + struct target *target = bank->target; + struct ath79_flash_bank *ath79_info = bank->driver_priv; + struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; + int pracc_words; + + /* + * These constants must match the worst case in the above code + * generator function ath79_spi_bitbang_codegen. + */ + const int pracc_pre_post = 26; + const int pracc_loop_byte = 8 * 2 + 2; + + struct pracc_queue_info ctx = { + .ejtag_info = ejtag_info + }; + int max_len = (PRACC_MAX_INSTRUCTIONS - pracc_pre_post) / pracc_loop_byte; + int to_xfer = len > max_len ? max_len : len; + int partial_xfer = len != to_xfer; + int padded_len = (to_xfer + 3) & ~3; + uint32_t *out = malloc(padded_len); + + if (!out) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + *transferred = 0; + pracc_queue_init(&ctx); + + LOG_DEBUG("ath79_spi_bitbang_bytes(%p, %08x, %p, %d)", + target, ath79_info->io_base, data, len); + + LOG_DEBUG("max code %d => max len %d. to_xfer %d", + PRACC_MAX_INSTRUCTIONS, max_len, to_xfer); + + pracc_words = ath79_spi_bitbang_codegen( + ath79_info, &ctx, data, to_xfer, partial_xfer); + + LOG_DEBUG("Assembled %d instructions, %d stores", + ctx.code_count, ctx.store_count); + + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, out, 1); + if (ctx.retval != ERROR_OK) + goto exit; + + if (to_xfer & 3) { /* Not a multiple of 4 bytes. */ + /* + * Need to realign last word since we didn't shift the + * full 32 bits. + */ + int missed_bytes = 4 - (to_xfer & 3); + + out[pracc_words - 1] <<= BITS_PER_BYTE * missed_bytes; + } + + /* + * pracc reads return uint32_t in host endianness, convert to + * target endianness. + * Since we know the ATH79 target is big endian and the SPI + * shift register has the bytes in highest to lowest bit order, + * this will ensure correct memory byte order regardless of host + * endianness. + */ + target_buffer_set_u32_array(target, (uint8_t *)out, pracc_words, out); + + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { + for (int i = 0; i < to_xfer; i++) { + LOG_DEBUG("bitbang %02x => %02x", + data[i], ((uint8_t *)out)[i]); + } + } + memcpy(data, out, to_xfer); + *transferred = to_xfer; + +exit: + pracc_queue_free(&ctx); + free(out); + return ctx.retval; +} + +static void ath79_spi_bitbang_prepare(struct flash_bank *bank) +{ + struct ath79_flash_bank *ath79_info = bank->driver_priv; + + ath79_info->spi.pre_deselect = 1; +} + +static int ath79_spi_bitbang_bytes(struct flash_bank *bank, + uint8_t *data, int len, uint32_t flags) +{ + struct ath79_flash_bank *ath79_info = bank->driver_priv; + int retval; + int transferred; + + ath79_info->spi.post_deselect = !!(flags & ATH79_XFER_FINAL); + + do { + transferred = 0; + retval = ath79_spi_bitbang_chunk( + bank, data, len, &transferred); + if (retval != ERROR_OK) + return retval; + + data += transferred; + len -= transferred; + } while (len > 0); + + return ERROR_OK; +} + +FLASH_BANK_COMMAND_HANDLER(ath79_flash_bank_command) +{ + struct ath79_flash_bank *ath79_info; + int chipselect = 0; + + LOG_DEBUG("%s", __func__); + + if (CMD_ARGC < 6 || CMD_ARGC > 7) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (CMD_ARGC == 7) { + if (strcmp(CMD_ARGV[6], "cs0") == 0) + chipselect = 0; /* default */ + else if (strcmp(CMD_ARGV[6], "cs1") == 0) + chipselect = 1; + else if (strcmp(CMD_ARGV[6], "cs2") == 0) + chipselect = 2; + else { + LOG_ERROR("Unknown arg: %s", CMD_ARGV[6]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + } + + ath79_info = calloc(1, sizeof(struct ath79_flash_bank)); + if (!ath79_info) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + ath79_info->chipselect = chipselect; + bank->driver_priv = ath79_info; + + return ERROR_OK; +} + +/* Read the status register of the external SPI flash chip. */ +static int read_status_reg(struct flash_bank *bank, uint32_t *status) +{ + uint8_t spi_bytes[] = {SPIFLASH_READ_STATUS, 0}; + int retval; + + /* Send SPI command "read STATUS" */ + ath79_spi_bitbang_prepare(bank); + retval = ath79_spi_bitbang_bytes( + bank, spi_bytes, sizeof(spi_bytes), + ATH79_XFER_FINAL); + + *status = spi_bytes[1]; + + return retval; +} + +/* check for WIP (write in progress) bit in status register */ +/* timeout in ms */ +static int wait_till_ready(struct flash_bank *bank, int timeout) +{ + uint32_t status; + int retval; + long long endtime; + + endtime = timeval_ms() + timeout; + do { + /* read flash status register */ + retval = read_status_reg(bank, &status); + if (retval != ERROR_OK) + return retval; + + if ((status & SPIFLASH_BSY_BIT) == 0) + return ERROR_OK; + alive_sleep(1); + } while (timeval_ms() < endtime); + + LOG_ERROR("timeout"); + return ERROR_FAIL; +} + +/* Send "write enable" command to SPI flash chip. */ +static int ath79_write_enable(struct flash_bank *bank) +{ + uint32_t status; + int retval; + + uint8_t spi_bytes[] = {SPIFLASH_WRITE_ENABLE}; + + /* Send SPI command "write enable" */ + ath79_spi_bitbang_prepare(bank); + retval = ath79_spi_bitbang_bytes( + bank, spi_bytes, sizeof(spi_bytes), + ATH79_XFER_FINAL); + if (retval != ERROR_OK) + return retval; + + /* read flash status register */ + retval = read_status_reg(bank, &status); + if (retval != ERROR_OK) + return retval; + + /* Check write enabled */ + if ((status & SPIFLASH_WE_BIT) == 0) { + LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32, + status); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int erase_command(struct flash_bank *bank, int sector) +{ + struct ath79_flash_bank *ath79_info = bank->driver_priv; + uint32_t offset = bank->sectors[sector].offset; + + uint8_t spi_bytes[] = { + ath79_info->dev->erase_cmd, + offset >> 16, + offset >> 8, + offset + }; + + /* bitbang command */ + ath79_spi_bitbang_prepare(bank); + return ath79_spi_bitbang_bytes( + bank, spi_bytes, sizeof(spi_bytes), + ATH79_XFER_FINAL); +} + +static int ath79_erase_sector(struct flash_bank *bank, int sector) +{ + int retval = ath79_write_enable(bank); + + if (retval != ERROR_OK) + return retval; + + /* send SPI command "block erase" */ + retval = erase_command(bank, sector); + if (retval != ERROR_OK) + return retval; + + /* poll WIP for end of self timed Sector Erase cycle */ + return wait_till_ready(bank, ATH79_MAX_TIMEOUT); +} + +static int ath79_erase(struct flash_bank *bank, int first, int last) +{ + struct target *target = bank->target; + struct ath79_flash_bank *ath79_info = bank->driver_priv; + int retval = ERROR_OK; + int sector; + + LOG_DEBUG("%s: from sector %d to sector %d", __func__, first, last); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if ((first < 0) || (last < first) || (last >= bank->num_sectors)) { + LOG_ERROR("Flash sector invalid"); + return ERROR_FLASH_SECTOR_INVALID; + } + + if (!ath79_info->probed) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + for (sector = first; sector <= last; sector++) { + if (bank->sectors[sector].is_protected) { + LOG_ERROR("Flash sector %d protected", sector); + return ERROR_FAIL; + } + } + + for (sector = first; sector <= last; sector++) { + retval = ath79_erase_sector(bank, sector); + if (retval != ERROR_OK) + break; + keep_alive(); + } + + return retval; +} + +static int ath79_protect(struct flash_bank *bank, int set, + int first, int last) +{ + int sector; + + for (sector = first; sector <= last; sector++) + bank->sectors[sector].is_protected = set; + return ERROR_OK; +} + +static int ath79_write_page(struct flash_bank *bank, const uint8_t *buffer, + uint32_t address, uint32_t len) +{ + struct ath79_flash_bank *ath79_info = bank->driver_priv; + uint8_t spi_bytes[] = { + SPIFLASH_PAGE_PROGRAM, + address >> 16, + address >> 8, + address, + }; + int retval; + uint32_t i; + + if (address & 0xff) { + LOG_ERROR("ath79_write_page: unaligned write address: %08x", + address); + return ERROR_FAIL; + } + if (!ath79_info->spi.page_buf) { + LOG_ERROR("ath79_write_page: page buffer not initialized"); + return ERROR_FAIL; + } + if (len > ath79_info->dev->pagesize) { + LOG_ERROR("ath79_write_page: len bigger than page size %d: %d", + ath79_info->dev->pagesize, len); + return ERROR_FAIL; + } + + for (i = 0; i < len; i++) { + if (buffer[i] != 0xff) + break; + } + if (i == len) /* all 0xff, no need to program. */ + return ERROR_OK; + + LOG_INFO("writing %d bytes to flash page @0x%08x", len, address); + + memcpy(ath79_info->spi.page_buf, buffer, len); + + /* unlock writes */ + retval = ath79_write_enable(bank); + if (retval != ERROR_OK) + return retval; + + /* bitbang command */ + ath79_spi_bitbang_prepare(bank); + retval = ath79_spi_bitbang_bytes( + bank, spi_bytes, sizeof(spi_bytes), + ATH79_XFER_PARTIAL); + if (retval != ERROR_OK) + return retval; + + /* write data */ + return ath79_spi_bitbang_bytes( + bank, ath79_info->spi.page_buf, len, + ATH79_XFER_FINAL); +} + +static int ath79_write_buffer(struct flash_bank *bank, const uint8_t *buffer, + uint32_t address, uint32_t len) +{ + struct ath79_flash_bank *ath79_info = bank->driver_priv; + const uint32_t page_size = ath79_info->dev->pagesize; + int retval; + + LOG_DEBUG("%s: address=0x%08" PRIx32 " len=0x%08" PRIx32, + __func__, address, len); + + while (len > 0) { + int page_len = len > page_size ? page_size : len; + + retval = ath79_write_page( + bank, buffer, address, page_len); + if (retval != ERROR_OK) + return retval; + + buffer += page_size; + address += page_size; + len -= page_len; + } + + return ERROR_OK; +} + +static int ath79_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + int sector; + + LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, + __func__, offset, count); + + if (offset < bank->base || offset >= bank->base + bank->size) { + LOG_ERROR("Start address out of range"); + return ERROR_FAIL; + } + + offset -= bank->base; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > bank->size) { + LOG_WARNING("Write pasts end of flash. Extra data discarded."); + count = bank->size - offset; + } + + /* Check sector protection */ + for (sector = 0; sector < bank->num_sectors; sector++) { + /* Start offset in or before this sector? */ + /* End offset in or behind this sector? */ + struct flash_sector *bs = &bank->sectors[sector]; + + if ((offset < (bs->offset + bs->size)) && + ((offset + count - 1) >= bs->offset) && + bs->is_protected) { + LOG_ERROR("Flash sector %d protected", sector); + return ERROR_FAIL; + } + } + + return ath79_write_buffer(bank, buffer, offset, count); +} + +static int ath79_read_buffer(struct flash_bank *bank, uint8_t *buffer, + uint32_t address, uint32_t len) +{ + uint8_t spi_bytes[] = { + SPIFLASH_READ, + address >> 16, + address >> 8, + address, + }; + int retval; + + LOG_DEBUG("%s: address=0x%08" PRIx32 " len=0x%08" PRIx32, + __func__, address, len); + + if (address & 0xff) { + LOG_ERROR("ath79_read_buffer: unaligned read address: %08x", + address); + return ERROR_FAIL; + } + + LOG_INFO("reading %d bytes from flash @0x%08x", len, address); + + /* bitbang command */ + ath79_spi_bitbang_prepare(bank); + retval = ath79_spi_bitbang_bytes( + bank, spi_bytes, sizeof(spi_bytes), ATH79_XFER_PARTIAL); + if (retval != ERROR_OK) + return retval; + + /* read data */ + return ath79_spi_bitbang_bytes( + bank, buffer, len, ATH79_XFER_FINAL); +} + +static int ath79_read(struct flash_bank *bank, uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + + LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, + __func__, offset, count); + + if (offset < bank->base || offset >= bank->base + bank->size) { + LOG_ERROR("Start address out of range"); + return ERROR_FAIL; + } + + offset -= bank->base; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > bank->size) { + LOG_WARNING("Reads past end of flash. Extra data discarded."); + count = bank->size - offset; + } + + return ath79_read_buffer(bank, buffer, offset, count); +} + +/* Return ID of flash device */ +static int read_flash_id(struct flash_bank *bank, uint32_t *id) +{ + struct target *target = bank->target; + int retval; + uint8_t spi_bytes[] = {SPIFLASH_READ_ID, 0, 0, 0}; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* Send SPI command "read ID" */ + ath79_spi_bitbang_prepare(bank); + retval = ath79_spi_bitbang_bytes( + bank, spi_bytes, sizeof(spi_bytes), ATH79_XFER_FINAL); + if (retval != ERROR_OK) + return retval; + + *id = (spi_bytes[1] << 0) + | (spi_bytes[2] << 8) + | (spi_bytes[3] << 16); + + if (*id == 0xffffff) { + LOG_ERROR("No SPI flash found"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int ath79_probe(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct ath79_flash_bank *ath79_info = bank->driver_priv; + struct flash_sector *sectors; + uint32_t id = 0; /* silence uninitialized warning */ + const struct ath79_target *target_device; + int retval; + + if (ath79_info->probed) { + free(bank->sectors); + free(ath79_info->spi.page_buf); + } + ath79_info->probed = 0; + + for (target_device = target_devices; target_device->name; + ++target_device) + if (target_device->tap_idcode == target->tap->idcode) + break; + if (!target_device->name) { + LOG_ERROR("Device ID 0x%" PRIx32 " is not known", + target->tap->idcode); + return ERROR_FAIL; + } + + ath79_info->io_base = target_device->io_base; + + LOG_DEBUG("Found device %s at address 0x%" PRIx32, + target_device->name, bank->base); + + retval = read_flash_id(bank, &id); + if (retval != ERROR_OK) + return retval; + + ath79_info->dev = NULL; + for (const struct flash_device *p = flash_devices; p->name; p++) + if (p->device_id == id) { + ath79_info->dev = p; + break; + } + + if (!ath79_info->dev) { + LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id); + return ERROR_FAIL; + } + + LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")", + ath79_info->dev->name, ath79_info->dev->device_id); + + /* Set correct size value */ + bank->size = ath79_info->dev->size_in_bytes; + + /* create and fill sectors array */ + bank->num_sectors = + ath79_info->dev->size_in_bytes / ath79_info->dev->sectorsize; + sectors = calloc(1, sizeof(struct flash_sector) * bank->num_sectors); + if (!sectors) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + ath79_info->spi.page_buf = malloc(ath79_info->dev->pagesize); + if (!ath79_info->spi.page_buf) { + LOG_ERROR("not enough memory"); + free(sectors); + return ERROR_FAIL; + } + + for (int sector = 0; sector < bank->num_sectors; sector++) { + sectors[sector].offset = sector * ath79_info->dev->sectorsize; + sectors[sector].size = ath79_info->dev->sectorsize; + sectors[sector].is_erased = 0; + sectors[sector].is_protected = 1; + } + + bank->sectors = sectors; + ath79_info->probed = 1; + return ERROR_OK; +} + +static int ath79_auto_probe(struct flash_bank *bank) +{ + struct ath79_flash_bank *ath79_info = bank->driver_priv; + + if (ath79_info->probed) + return ERROR_OK; + return ath79_probe(bank); +} + +static int ath79_flash_blank_check(struct flash_bank *bank) +{ + /* Not implemented */ + return ERROR_OK; +} + +static int ath79_protect_check(struct flash_bank *bank) +{ + /* Not implemented */ + return ERROR_OK; +} + +static int get_ath79_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct ath79_flash_bank *ath79_info = bank->driver_priv; + + if (!ath79_info->probed) { + snprintf(buf, buf_size, + "\nATH79 flash bank not probed yet\n"); + return ERROR_OK; + } + + snprintf(buf, buf_size, "\nATH79 flash information:\n" + " Device \'%s\' (ID 0x%08" PRIx32 ")\n", + ath79_info->dev->name, ath79_info->dev->device_id); + + return ERROR_OK; +} + +struct flash_driver ath79_flash = { + .name = "ath79", + .flash_bank_command = ath79_flash_bank_command, + .erase = ath79_erase, + .protect = ath79_protect, + .write = ath79_write, + .read = ath79_read, + .probe = ath79_probe, + .auto_probe = ath79_auto_probe, + .erase_check = ath79_flash_blank_check, + .protect_check = ath79_protect_check, + .info = get_ath79_info, +}; diff --git a/src/flash/nor/avrf.c b/src/flash/nor/avrf.c index 627418c6..11cc3b2d 100644 --- a/src/flash/nor/avrf.c +++ b/src/flash/nor/avrf.c @@ -66,6 +66,7 @@ static const struct avrf_type avft_chips_info[] = { * eeprom_page_size, eeprom_page_num */ {"atmega128", 0x9702, 256, 512, 8, 512}, + {"atmega128rfa1", 0xa701, 128, 512, 8, 512}, {"at90can128", 0x9781, 256, 512, 8, 512}, {"at90usb128", 0x9782, 256, 512, 8, 512}, {"atmega164p", 0x940a, 128, 128, 4, 128}, diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c index f7d8a90f..ac0db827 100644 --- a/src/flash/nor/cfi.c +++ b/src/flash/nor/cfi.c @@ -1312,7 +1312,7 @@ static int cfi_intel_write_block(struct flash_bank *bank, const uint8_t *buffer, busy_pattern_val = cfi_command_val(bank, 0x80); error_pattern_val = cfi_command_val(bank, 0x7e); - LOG_DEBUG("Using target buffer at 0x%08" PRIx32 " and of size 0x%04" PRIx32, + LOG_DEBUG("Using target buffer at " TARGET_ADDR_FMT " and of size 0x%04" PRIx32, source->address, buffer_size); /* Programming main loop */ @@ -1424,50 +1424,50 @@ static int cfi_spansion_write_block_mips(struct flash_bank *bank, const uint8_t static const uint32_t mips_word_16_code[] = { /* start: */ - MIPS32_LHU(9, 0, 4), /* lhu $t1, ($a0) ; out = &saddr */ - MIPS32_ADDI(4, 4, 2), /* addi $a0, $a0, 2 ; saddr += 2 */ - MIPS32_SH(13, 0, 12), /* sh $t5, ($t4) ; *fl_unl_addr1 = fl_unl_cmd1 */ - MIPS32_SH(15, 0, 14), /* sh $t7, ($t6) ; *fl_unl_addr2 = fl_unl_cmd2 */ - MIPS32_SH(7, 0, 12), /* sh $a3, ($t4) ; *fl_unl_addr1 = fl_write_cmd */ - MIPS32_SH(9, 0, 5), /* sh $t1, ($a1) ; *daddr = out */ + MIPS32_LHU(0, 9, 0, 4), /* lhu $t1, ($a0) ; out = &saddr */ + MIPS32_ADDI(0, 4, 4, 2), /* addi $a0, $a0, 2 ; saddr += 2 */ + MIPS32_SH(0, 13, 0, 12), /* sh $t5, ($t4) ; *fl_unl_addr1 = fl_unl_cmd1 */ + MIPS32_SH(0, 15, 0, 14), /* sh $t7, ($t6) ; *fl_unl_addr2 = fl_unl_cmd2 */ + MIPS32_SH(0, 7, 0, 12), /* sh $a3, ($t4) ; *fl_unl_addr1 = fl_write_cmd */ + MIPS32_SH(0, 9, 0, 5), /* sh $t1, ($a1) ; *daddr = out */ MIPS32_NOP, /* nop */ /* busy: */ - MIPS32_LHU(10, 0, 5), /* lhu $t2, ($a1) ; temp1 = *daddr */ - MIPS32_XOR(11, 9, 10), /* xor $t3, $a0, $t2 ; temp2 = out ^ temp1; */ - MIPS32_AND(11, 8, 11), /* and $t3, $t0, $t3 ; temp2 = temp2 & DQ7mask */ - MIPS32_BNE(11, 8, 13), /* bne $t3, $t0, cont ; if (temp2 != DQ7mask) goto cont */ - MIPS32_NOP, /* nop */ - - MIPS32_SRL(10, 8, 2), /* srl $t2,$t0,2 ; temp1 = DQ7mask >> 2 */ - MIPS32_AND(11, 10, 11), /* and $t3, $t2, $t3 ; temp2 = temp2 & temp1 */ - MIPS32_BNE(11, 10, NEG16(8)), /* bne $t3, $t2, busy ; if (temp2 != temp1) goto busy */ - MIPS32_NOP, /* nop */ - - MIPS32_LHU(10, 0, 5), /* lhu $t2, ($a1) ; temp1 = *daddr */ - MIPS32_XOR(11, 9, 10), /* xor $t3, $a0, $t2 ; temp2 = out ^ temp1; */ - MIPS32_AND(11, 8, 11), /* and $t3, $t0, $t3 ; temp2 = temp2 & DQ7mask */ - MIPS32_BNE(11, 8, 4), /* bne $t3, $t0, cont ; if (temp2 != DQ7mask) goto cont */ + MIPS32_LHU(0, 10, 0, 5), /* lhu $t2, ($a1) ; temp1 = *daddr */ + MIPS32_XOR(0, 11, 9, 10), /* xor $t3, $a0, $t2 ; temp2 = out ^ temp1; */ + MIPS32_AND(0, 11, 8, 11), /* and $t3, $t0, $t3 ; temp2 = temp2 & DQ7mask */ + MIPS32_BNE(0, 11, 8, 13), /* bne $t3, $t0, cont ; if (temp2 != DQ7mask) goto cont */ + MIPS32_NOP, /* nop */ + + MIPS32_SRL(0, 10, 8, 2), /* srl $t2,$t0,2 ; temp1 = DQ7mask >> 2 */ + MIPS32_AND(0, 11, 10, 11), /* and $t3, $t2, $t3 ; temp2 = temp2 & temp1 */ + MIPS32_BNE(0, 11, 10, NEG16(8)), /* bne $t3, $t2, busy ; if (temp2 != temp1) goto busy */ + MIPS32_NOP, /* nop */ + + MIPS32_LHU(0, 10, 0, 5), /* lhu $t2, ($a1) ; temp1 = *daddr */ + MIPS32_XOR(0, 11, 9, 10), /* xor $t3, $a0, $t2 ; temp2 = out ^ temp1; */ + MIPS32_AND(0, 11, 8, 11), /* and $t3, $t0, $t3 ; temp2 = temp2 & DQ7mask */ + MIPS32_BNE(0, 11, 8, 4), /* bne $t3, $t0, cont ; if (temp2 != DQ7mask) goto cont */ MIPS32_NOP, /* nop */ - MIPS32_XOR(9, 9, 9), /* xor $t1, $t1, $t1 ; out = 0 */ - MIPS32_BEQ(9, 0, 11), /* beq $t1, $zero, done ; if (out == 0) goto done */ + MIPS32_XOR(0, 9, 9, 9), /* xor $t1, $t1, $t1 ; out = 0 */ + MIPS32_BEQ(0, 9, 0, 11), /* beq $t1, $zero, done ; if (out == 0) goto done */ MIPS32_NOP, /* nop */ /* cont: */ - MIPS32_ADDI(6, 6, NEG16(1)), /* addi, $a2, $a2, -1 ; numwrites-- */ - MIPS32_BNE(6, 0, 5), /* bne $a2, $zero, cont2 ; if (numwrite != 0) goto cont2 */ + MIPS32_ADDI(0, 6, 6, NEG16(1)), /* addi, $a2, $a2, -1 ; numwrites-- */ + MIPS32_BNE(0, 6, 0, 5), /* bne $a2, $zero, cont2 ; if (numwrite != 0) goto cont2 */ MIPS32_NOP, /* nop */ - MIPS32_LUI(9, 0), /* lui $t1, 0 */ - MIPS32_ORI(9, 9, 0x80), /* ori $t1, $t1, 0x80 ; out = 0x80 */ + MIPS32_LUI(0, 9, 0), /* lui $t1, 0 */ + MIPS32_ORI(0, 9, 9, 0x80), /* ori $t1, $t1, 0x80 ; out = 0x80 */ - MIPS32_B(4), /* b done ; goto done */ + MIPS32_B(0, 4), /* b done ; goto done */ MIPS32_NOP, /* nop */ /* cont2: */ - MIPS32_ADDI(5, 5, 2), /* addi $a0, $a0, 2 ; daddr += 2 */ - MIPS32_B(NEG16(33)), /* b start ; goto start */ + MIPS32_ADDI(0, 5, 5, 2), /* addi $a0, $a0, 2 ; daddr += 2 */ + MIPS32_B(0, NEG16(33)), /* b start ; goto start */ MIPS32_NOP, /* nop */ /* done: */ - MIPS32_SDBBP, /* sdbbp ; break(); */ + MIPS32_SDBBP(0), /* sdbbp ; break(); */ }; mips32_info.common_magic = MIPS32_COMMON_MAGIC; diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 56a5cb24..4ad1d92b 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -28,6 +28,7 @@ extern struct flash_driver at91sam4_flash; extern struct flash_driver at91sam4l_flash; extern struct flash_driver at91sam7_flash; 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 cfi_flash; @@ -80,6 +81,7 @@ static struct flash_driver *flash_drivers[] = { &at91sam4l_flash, &at91sam7_flash, &at91samd_flash, + &ath79_flash, &atsamv_flash, &avr_flash, &cfi_flash, diff --git a/src/flash/nor/em357.c b/src/flash/nor/em357.c index 15015626..a11743b5 100644 --- a/src/flash/nor/em357.c +++ b/src/flash/nor/em357.c @@ -702,6 +702,11 @@ static int em357_probe(struct flash_bank *bank) num_pages = 128; page_size = 2048; break; + case 0x80000: + /* 512k -- 256 2k pages */ + num_pages = 256; + page_size = 2048; + break; default: LOG_WARNING("No size specified for em357 flash driver, assuming 192k!"); num_pages = 96; diff --git a/src/flash/nor/fm4.c b/src/flash/nor/fm4.c index c348c1d6..c8fe8b66 100644 --- a/src/flash/nor/fm4.c +++ b/src/flash/nor/fm4.c @@ -272,7 +272,7 @@ static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t halfwords = MIN(halfword_count, data_workarea->size / 2); uint32_t addr = bank->base + offset; - LOG_DEBUG("copying %" PRId32 " bytes to SRAM 0x%08" PRIx32, + LOG_DEBUG("copying %" PRId32 " bytes to SRAM 0x%08" TARGET_PRIxADDR, MIN(halfwords * 2, byte_count), data_workarea->address); retval = target_write_buffer(target, data_workarea->address, diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index 49a6e272..7e9bbdef 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -1371,7 +1371,7 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, if (!(kinfo->flash_support & FS_PROGRAM_SECTOR)) { /* fallback to longword write */ fallback = 1; - LOG_WARNING("This device supports Program Longword execution only."); + LOG_INFO("This device supports Program Longword execution only."); } else { result = kinetis_make_ram_ready(bank->target); if (result != ERROR_OK) { diff --git a/src/flash/nor/lpc2000.c b/src/flash/nor/lpc2000.c index 190684af..9da5da2c 100644 --- a/src/flash/nor/lpc2000.c +++ b/src/flash/nor/lpc2000.c @@ -688,7 +688,7 @@ static int lpc2000_iap_working_area_init(struct flash_bank *bank, struct working int retval = target_write_memory(target, (*iap_working_area)->address, 4, 2, jump_gate); if (retval != ERROR_OK) { - LOG_ERROR("Write memory at address 0x%8.8" PRIx32 " failed (check work_area definition)", + LOG_ERROR("Write memory at address 0x%8.8" TARGET_PRIxADDR " failed (check work_area definition)", (*iap_working_area)->address); target_free_working_area(target, *iap_working_area); } diff --git a/src/flash/nor/lpcspifi.c b/src/flash/nor/lpcspifi.c index 4eb6cc38..943c151e 100644 --- a/src/flash/nor/lpcspifi.c +++ b/src/flash/nor/lpcspifi.c @@ -186,7 +186,7 @@ static int lpcspifi_set_hw_mode(struct flash_bank *bank) return retval; } - LOG_DEBUG("Writing algorithm to working area at 0x%08" PRIx32, + LOG_DEBUG("Writing algorithm to working area at 0x%08" TARGET_PRIxADDR, spifi_init_algorithm->address); /* Write algorithm to working area */ retval = target_write_buffer(target, diff --git a/src/flash/nor/nrf51.c b/src/flash/nor/nrf51.c index a41bc059..7b7acf47 100644 --- a/src/flash/nor/nrf51.c +++ b/src/flash/nor/nrf51.c @@ -291,6 +291,13 @@ static const struct nrf51_device_spec nrf51_known_devices_table[] = { .build_code = "A0", .flash_size_kb = 256, }, + { + .hwid = 0x008F, + .part = "51822", + .variant = "QFAA", + .build_code = "H1", + .flash_size_kb = 256, + }, /* nRF51422 Devices (IC rev 1). */ { @@ -690,14 +697,15 @@ static int nrf51_probe(struct flash_bank *bank) /* Note the register name is misleading, * NRF51_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */ - res = target_read_u32(chip->target, NRF51_FICR_CODESIZE, - (uint32_t *) &bank->num_sectors); + uint32_t num_sectors; + res = target_read_u32(chip->target, NRF51_FICR_CODESIZE, &num_sectors); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code memory size"); return res; } - bank->size = bank->num_sectors * chip->code_page_size; + bank->num_sectors = num_sectors; + bank->size = num_sectors * chip->code_page_size; if (spec && bank->size / 1024 != spec->flash_size_kb) LOG_WARNING("Chip's reported Flash capacity does not match expected one"); diff --git a/src/flash/nor/pic32mx.c b/src/flash/nor/pic32mx.c index de212ed3..1f148fd7 100644 --- a/src/flash/nor/pic32mx.c +++ b/src/flash/nor/pic32mx.c @@ -879,7 +879,6 @@ COMMAND_HANDLER(pic32mx_handle_pgm_word_command) COMMAND_HANDLER(pic32mx_handle_unlock_command) { - uint32_t mchip_cmd; struct target *target = NULL; struct mips_m4k_common *mips_m4k; struct mips_ejtag *ejtag_info; @@ -904,7 +903,7 @@ COMMAND_HANDLER(pic32mx_handle_unlock_command) mips_ejtag_set_instr(ejtag_info, MTAP_COMMAND); /* first check status of device */ - mchip_cmd = MCHP_STATUS; + uint8_t mchip_cmd = MCHP_STATUS; mips_ejtag_drscan_8(ejtag_info, &mchip_cmd); if (mchip_cmd & (1 << 7)) { /* device is not locked */ diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 762df74d..fa0c48b4 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -27,18 +27,22 @@ /* STM32L4xxx series for reference. * - * RM0351 - * http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00083560.pdf + * RM0351 (STM32L4x5/STM32L4x6) + * http://www.st.com/resource/en/reference_manual/dm00083560.pdf * - * STM32L476RG Datasheet (for erase timing) - * http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/DM00108832.pdf + * RM0394 (STM32L43x/44x/45x/46x) + * http://www.st.com/resource/en/reference_manual/dm00151940.pdf * + * STM32L476RG Datasheet (for erase timing) + * http://www.st.com/resource/en/datasheet/stm32l476rg.pdf * - * The device has normally two banks, but on 512 and 256 kiB devices an - * option byte is available to map all sectors to the first bank. + * The RM0351 devices have normally two banks, but on 512 and 256 kiB devices + * an option byte is available to map all sectors to the first bank. * Both STM32 banks are treated as one OpenOCD bank, as other STM32 devices * handlers do! * + * RM0394 devices have a single bank only. + * */ /* Erase time can be as high as 25ms, 10x this and assume it's toast... */ @@ -614,9 +618,13 @@ static int stm32l4_probe(struct flash_bank *bank) /* set max flash size depending on family */ switch (device_id & 0xfff) { + case 0x461: case 0x415: max_flash_size_in_kb = 1024; break; + case 0x462: + max_flash_size_in_kb = 512; + break; case 0x435: max_flash_size_in_kb = 256; break; @@ -716,12 +724,20 @@ static int get_stm32l4_info(struct flash_bank *bank, char *buf, int buf_size) const char *device_str; switch (device_id) { + case 0x461: + device_str = "STM32L496/4A6"; + break; + case 0x415: - device_str = "STM32L4xx"; + device_str = "STM32L475/476/486"; + break; + + case 0x462: + device_str = "STM32L45x/46x"; break; case 0x435: - device_str = "STM32L43x"; + device_str = "STM32L43x/44x"; break; default: diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index 0b392334..e4f499d3 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -105,6 +105,7 @@ static int stm32lx_lock(struct flash_bank *bank); static int stm32lx_unlock(struct flash_bank *bank); static int stm32lx_mass_erase(struct flash_bank *bank); static int stm32lx_wait_until_bsy_clear_timeout(struct flash_bank *bank, int timeout); +static int stm32lx_update_part_info(struct flash_bank *bank, uint16_t flash_size_in_kb); struct stm32lx_rev { uint16_t rev; @@ -132,7 +133,7 @@ struct stm32lx_flash_bank { uint32_t user_bank_size; uint32_t flash_base; - const struct stm32lx_part_info *part_info; + struct stm32lx_part_info part_info; }; static const struct stm32lx_rev stm32_416_revs[] = { @@ -245,7 +246,7 @@ static const struct stm32lx_part_info stm32lx_parts[] = { .page_size = 256, .pages_per_sector = 16, .max_flash_size_kb = 512, - .first_bank_size_kb = 256, + .first_bank_size_kb = 0, /* determined in runtime */ .has_dual_banks = true, .flash_base = 0x40023C00, .fsize_base = 0x1FF800CC, @@ -258,8 +259,8 @@ static const struct stm32lx_part_info stm32lx_parts[] = { .page_size = 128, .pages_per_sector = 32, .max_flash_size_kb = 192, - .first_bank_size_kb = 128, - .has_dual_banks = true, + .first_bank_size_kb = 0, /* determined in runtime */ + .has_dual_banks = false, /* determined in runtime */ .flash_base = 0x40022000, .fsize_base = 0x1FF8007C, }, @@ -436,7 +437,7 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; - uint32_t hp_nb = stm32lx_info->part_info->page_size / 2; + uint32_t hp_nb = stm32lx_info->part_info.page_size / 2; uint32_t buffer_size = 16384; struct working_area *write_algorithm; struct working_area *source; @@ -450,19 +451,7 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff /* see contib/loaders/flash/stm32lx.S for src */ static const uint8_t stm32lx_flash_write_code[] = { - /* write_word: */ - 0x00, 0x23, /* movs r3, #0 */ - 0x04, 0xe0, /* b test_done */ - - /* write_word: */ - 0x51, 0xf8, 0x04, 0xcb, /* ldr ip, [r1], #4 */ - 0x40, 0xf8, 0x04, 0xcb, /* str ip, [r0], #4 */ - 0x01, 0x33, /* adds r3, #1 */ - - /* test_done: */ - 0x93, 0x42, /* cmp r3, r2 */ - 0xf8, 0xd3, /* bcc write_word */ - 0x00, 0xbe, /* bkpt 0 */ + 0x92, 0x00, 0x8A, 0x18, 0x01, 0xE0, 0x08, 0xC9, 0x08, 0xC0, 0x91, 0x42, 0xFB, 0xD1, 0x00, 0xBE }; /* Make sure we're performing a half-page aligned write. */ @@ -495,7 +484,7 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff else buffer_size /= 2; - if (buffer_size <= stm32lx_info->part_info->page_size) { + if (buffer_size <= stm32lx_info->part_info.page_size) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); @@ -588,7 +577,7 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff * is reduced by 50% using this slower method. */ - LOG_WARNING("couldn't use loader, falling back to page memory writes"); + LOG_WARNING("Couldn't use loader, falling back to page memory writes"); while (count > 0) { uint32_t this_count; @@ -629,7 +618,7 @@ static int stm32lx_write(struct flash_bank *bank, const uint8_t *buffer, struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; - uint32_t hp_nb = stm32lx_info->part_info->page_size / 2; + uint32_t hp_nb = stm32lx_info->part_info.page_size / 2; uint32_t halfpages_number; uint32_t bytes_remaining = 0; uint32_t address = bank->base + offset; @@ -759,9 +748,9 @@ static int stm32lx_probe(struct flash_bank *bank) uint32_t device_id; uint32_t base_address = FLASH_BANK0_ADDRESS; uint32_t second_bank_base; + unsigned int n; stm32lx_info->probed = 0; - stm32lx_info->part_info = NULL; int retval = stm32lx_read_id_code(bank->target, &device_id); if (retval != ERROR_OK) @@ -771,22 +760,24 @@ static int stm32lx_probe(struct flash_bank *bank) LOG_DEBUG("device id = 0x%08" PRIx32 "", device_id); - for (unsigned int n = 0; n < ARRAY_SIZE(stm32lx_parts); n++) { - if ((device_id & 0xfff) == stm32lx_parts[n].id) - stm32lx_info->part_info = &stm32lx_parts[n]; + for (n = 0; n < ARRAY_SIZE(stm32lx_parts); n++) { + if ((device_id & 0xfff) == stm32lx_parts[n].id) { + stm32lx_info->part_info = stm32lx_parts[n]; + break; + } } - if (!stm32lx_info->part_info) { + if (n == ARRAY_SIZE(stm32lx_parts)) { LOG_WARNING("Cannot identify target as a STM32L family."); return ERROR_FAIL; } else { - LOG_INFO("Device: %s", stm32lx_info->part_info->device_str); + LOG_INFO("Device: %s", stm32lx_info->part_info.device_str); } - stm32lx_info->flash_base = stm32lx_info->part_info->flash_base; + stm32lx_info->flash_base = stm32lx_info->part_info.flash_base; /* Get the flash size from target. */ - retval = target_read_u16(target, stm32lx_info->part_info->fsize_base, + retval = target_read_u16(target, stm32lx_info->part_info.fsize_base, &flash_size_in_kb); /* 0x436 devices report their flash size as a 0 or 1 code indicating 384K @@ -803,29 +794,34 @@ static int stm32lx_probe(struct flash_bank *bank) * default to max target family */ if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) { LOG_WARNING("STM32L flash size failed, probe inaccurate - assuming %dk flash", - stm32lx_info->part_info->max_flash_size_kb); - flash_size_in_kb = stm32lx_info->part_info->max_flash_size_kb; - } else if (flash_size_in_kb > stm32lx_info->part_info->max_flash_size_kb) { + stm32lx_info->part_info.max_flash_size_kb); + flash_size_in_kb = stm32lx_info->part_info.max_flash_size_kb; + } else if (flash_size_in_kb > stm32lx_info->part_info.max_flash_size_kb) { LOG_WARNING("STM32L probed flash size assumed incorrect since FLASH_SIZE=%dk > %dk, - assuming %dk flash", - flash_size_in_kb, stm32lx_info->part_info->max_flash_size_kb, - stm32lx_info->part_info->max_flash_size_kb); - flash_size_in_kb = stm32lx_info->part_info->max_flash_size_kb; + flash_size_in_kb, stm32lx_info->part_info.max_flash_size_kb, + stm32lx_info->part_info.max_flash_size_kb); + flash_size_in_kb = stm32lx_info->part_info.max_flash_size_kb; } - if (stm32lx_info->part_info->has_dual_banks) { + /* Overwrite default dual-bank configuration */ + retval = stm32lx_update_part_info(bank, flash_size_in_kb); + if (retval != ERROR_OK) + return ERROR_FAIL; + + if (stm32lx_info->part_info.has_dual_banks) { /* Use the configured base address to determine if this is the first or second flash bank. * Verify that the base address is reasonably correct and determine the flash bank size */ second_bank_base = base_address + - stm32lx_info->part_info->first_bank_size_kb * 1024; + stm32lx_info->part_info.first_bank_size_kb * 1024; if (bank->base == second_bank_base || !bank->base) { /* This is the second bank */ base_address = second_bank_base; flash_size_in_kb = flash_size_in_kb - - stm32lx_info->part_info->first_bank_size_kb; + stm32lx_info->part_info.first_bank_size_kb; } else if (bank->base == base_address) { /* This is the first bank */ - flash_size_in_kb = stm32lx_info->part_info->first_bank_size_kb; + flash_size_in_kb = stm32lx_info->part_info.first_bank_size_kb; } else { LOG_WARNING("STM32L flash bank base address config is incorrect." " 0x%" PRIx32 " but should rather be 0x%" PRIx32 " or 0x%" PRIx32, @@ -888,6 +884,9 @@ static int stm32lx_auto_probe(struct flash_bank *bank) static int stm32lx_get_info(struct flash_bank *bank, char *buf, int buf_size) { struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; + const struct stm32lx_part_info *info = &stm32lx_info->part_info; + uint16_t rev_id = stm32lx_info->idcode >> 16; + const char *rev_str = NULL; if (!stm32lx_info->probed) { int retval = stm32lx_probe(bank); @@ -898,32 +897,21 @@ static int stm32lx_get_info(struct flash_bank *bank, char *buf, int buf_size) } } - const struct stm32lx_part_info *info = stm32lx_info->part_info; - - if (info) { - const char *rev_str = NULL; - uint16_t rev_id = stm32lx_info->idcode >> 16; + for (unsigned int i = 0; i < info->num_revs; i++) + if (rev_id == info->revs[i].rev) + rev_str = info->revs[i].str; - for (unsigned int i = 0; i < info->num_revs; i++) - if (rev_id == info->revs[i].rev) - rev_str = info->revs[i].str; - - if (rev_str != NULL) { - snprintf(buf, buf_size, - "%s - Rev: %s", - stm32lx_info->part_info->device_str, rev_str); - } else { - snprintf(buf, buf_size, - "%s - Rev: unknown (0x%04x)", - stm32lx_info->part_info->device_str, rev_id); - } - - return ERROR_OK; + if (rev_str != NULL) { + snprintf(buf, buf_size, + "%s - Rev: %s", + info->device_str, rev_str); } else { - snprintf(buf, buf_size, "Cannot identify target as a STM32Lx"); - - return ERROR_FAIL; + snprintf(buf, buf_size, + "%s - Rev: unknown (0x%04x)", + info->device_str, rev_id); } + + return ERROR_OK; } static const struct command_registration stm32lx_exec_command_handlers[] = { @@ -1132,7 +1120,7 @@ static int stm32lx_erase_sector(struct flash_bank *bank, int sector) if (retval != ERROR_OK) return retval; - for (int page = 0; page < (int)stm32lx_info->part_info->pages_per_sector; + for (int page = 0; page < (int)stm32lx_info->part_info.pages_per_sector; page++) { reg32 = FLASH_PECR__PROG | FLASH_PECR__ERASE; retval = target_write_u32(target, @@ -1145,7 +1133,7 @@ static int stm32lx_erase_sector(struct flash_bank *bank, int sector) return retval; uint32_t addr = bank->base + bank->sectors[sector].offset + (page - * stm32lx_info->part_info->page_size); + * stm32lx_info->part_info.page_size); retval = target_write_u32(target, addr, 0x0); if (retval != ERROR_OK) return retval; @@ -1369,3 +1357,22 @@ static int stm32lx_mass_erase(struct flash_bank *bank) return ERROR_OK; } + +static int stm32lx_update_part_info(struct flash_bank *bank, uint16_t flash_size_in_kb) +{ + struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; + + switch (stm32lx_info->part_info.id) { + case 0x447: /* STM32L0xx (Cat.5) devices */ + if (flash_size_in_kb == 192 || flash_size_in_kb == 128) { + stm32lx_info->part_info.first_bank_size_kb = flash_size_in_kb / 2; + stm32lx_info->part_info.has_dual_banks = true; + } + break; + case 0x437: /* STM32L1xx (Cat.5/Cat.6) */ + stm32lx_info->part_info.first_bank_size_kb = flash_size_in_kb / 2; + break; + } + + return ERROR_OK; +} diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index 0b72a123..b93d1269 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -297,8 +297,8 @@ static int flash_check_sector_parameters(struct command_context *cmd_ctx, } if (!(last <= (num_sectors - 1))) { - command_print(cmd_ctx, "ERROR: last sector must be <= %d", - (int) num_sectors - 1); + command_print(cmd_ctx, "ERROR: last sector must be <= %" PRIu32, + num_sectors - 1); return ERROR_FAIL; } @@ -380,10 +380,9 @@ COMMAND_HANDLER(handle_flash_protect_command) retval = flash_driver_protect(p, set, first, last); if (retval == ERROR_OK) { - command_print(CMD_CTX, "%s protection for sectors %i " - "through %i on flash bank %d", - (set) ? "set" : "cleared", (int) first, - (int) last, p->bank_number); + command_print(CMD_CTX, "%s protection for sectors %" PRIu32 + " through %" PRIu32 " on flash bank %d", + (set) ? "set" : "cleared", first, last, p->bank_number); } return retval; @@ -690,9 +689,9 @@ COMMAND_HANDLER(handle_flash_read_bank_command) } if (duration_measure(&bench) == ERROR_OK) - command_print(CMD_CTX, "wrote %ld bytes to file %s from flash bank %u" + command_print(CMD_CTX, "wrote %zd bytes to file %s from flash bank %u" " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)", - (long)written, CMD_ARGV[1], p->bank_number, offset, + written, CMD_ARGV[1], p->bank_number, offset, duration_elapsed(&bench), duration_kbps(&bench, written)); return retval; @@ -708,7 +707,7 @@ COMMAND_HANDLER(handle_flash_verify_bank_command) size_t filesize; int differ; - if (CMD_ARGC != 3) + if (CMD_ARGC < 2 || CMD_ARGC > 3) return ERROR_COMMAND_SYNTAX_ERROR; struct duration bench; @@ -719,7 +718,16 @@ COMMAND_HANDLER(handle_flash_verify_bank_command) if (ERROR_OK != retval) return retval; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset); + offset = 0; + + if (CMD_ARGC > 2) + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset); + + if (offset > p->size) { + LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank", + offset); + return ERROR_COMMAND_ARGUMENT_INVALID; + } retval = fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY); if (retval != ERROR_OK) { @@ -770,9 +778,9 @@ COMMAND_HANDLER(handle_flash_verify_bank_command) } if (duration_measure(&bench) == ERROR_OK) - command_print(CMD_CTX, "read %ld bytes from file %s and flash bank %u" + command_print(CMD_CTX, "read %zd bytes from file %s and flash bank %u" " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)", - (long)read_cnt, CMD_ARGV[1], p->bank_number, offset, + read_cnt, CMD_ARGV[1], p->bank_number, offset, duration_elapsed(&bench), duration_kbps(&bench, read_cnt)); differ = memcmp(buffer_file, buffer_flash, read_cnt); @@ -927,10 +935,10 @@ static const struct command_registration flash_exec_command_handlers[] = { .name = "verify_bank", .handler = handle_flash_verify_bank_command, .mode = COMMAND_EXEC, - .usage = "bank_id filename offset", - .help = "Read binary data from flash bank and file, " - "starting at specified byte offset from the " - "beginning of the bank. Compare the contents.", + .usage = "bank_id filename [offset]", + .help = "Compare the contents of a file with the contents of the " + "flash bank. Allow optional offset from beginning of the bank " + "(defaults to zero).", }, { .name = "protect", diff --git a/src/flash/nor/xmc1xxx.c b/src/flash/nor/xmc1xxx.c index bb2ec127..0a76b216 100644 --- a/src/flash/nor/xmc1xxx.c +++ b/src/flash/nor/xmc1xxx.c @@ -305,7 +305,7 @@ static int xmc1xxx_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t blocks = MIN(block_count, data_workarea->size / NVM_BLOCK_SIZE); uint32_t addr = bank->base + offset; - LOG_DEBUG("copying %" PRId32 " bytes to SRAM 0x%08" PRIx32, + LOG_DEBUG("copying %" PRId32 " bytes to SRAM 0x%08" TARGET_PRIxADDR, MIN(blocks * NVM_BLOCK_SIZE, byte_count), data_workarea->address); diff --git a/src/helper/command.c b/src/helper/command.c index fc4aac72..5deaee85 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -1410,6 +1410,8 @@ DEFINE_PARSE_ULONGLONG(_u32, uint32_t, 0, UINT32_MAX) DEFINE_PARSE_ULONGLONG(_u16, uint16_t, 0, UINT16_MAX) DEFINE_PARSE_ULONGLONG(_u8, uint8_t, 0, UINT8_MAX) +DEFINE_PARSE_ULONGLONG(_target_addr, target_addr_t, 0, TARGET_ADDR_MAX) + #define DEFINE_PARSE_LONGLONG(name, type, min, max) \ DEFINE_PARSE_WRAPPER(name, type, min, max, long long, _llong) DEFINE_PARSE_LONGLONG(_int, int, n < INT_MIN, INT_MAX) diff --git a/src/helper/command.h b/src/helper/command.h index 5c396601..bd24156e 100644 --- a/src/helper/command.h +++ b/src/helper/command.h @@ -357,10 +357,13 @@ DECLARE_PARSE_WRAPPER(_u16, uint16_t); DECLARE_PARSE_WRAPPER(_u8, uint8_t); DECLARE_PARSE_WRAPPER(_int, int); +DECLARE_PARSE_WRAPPER(_s64, int64_t); DECLARE_PARSE_WRAPPER(_s32, int32_t); DECLARE_PARSE_WRAPPER(_s16, int16_t); DECLARE_PARSE_WRAPPER(_s8, int8_t); +DECLARE_PARSE_WRAPPER(_target_addr, target_addr_t); + /** * @brief parses the string @a in into @a out as a @a type, or prints * a command error and passes the error code to the caller. If an error @@ -382,6 +385,9 @@ DECLARE_PARSE_WRAPPER(_s8, int8_t); } \ } while (0) +#define COMMAND_PARSE_ADDRESS(in, out) \ + COMMAND_PARSE_NUMBER(target_addr, in, out) + /** * Parse the string @c as a binary parameter, storing the boolean value * in @c out. The strings @c on and @c off are used to match different diff --git a/src/helper/log.c b/src/helper/log.c index e7af803c..891613d3 100644 --- a/src/helper/log.c +++ b/src/helper/log.c @@ -251,9 +251,15 @@ COMMAND_HANDLER(handle_log_output_command) { if (CMD_ARGC == 1) { FILE *file = fopen(CMD_ARGV[0], "w"); - - if (file) - log_output = file; + if (file == NULL) { + LOG_ERROR("failed to open output log '%s'", CMD_ARGV[0]); + return ERROR_FAIL; + } + if (log_output != stderr && log_output != NULL) { + /* Close previous log file, if it was open and wasn't stderr. */ + fclose(log_output); + } + log_output = file; } return ERROR_OK; diff --git a/src/helper/options.c b/src/helper/options.c index 409abeeb..1cfa5537 100644 --- a/src/helper/options.c +++ b/src/helper/options.c @@ -267,8 +267,10 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[]) case 'd': /* --debug | -d */ { char *command = alloc_printf("debug_level %s", optarg ? optarg : "3"); - command_run_line(cmd_ctx, command); + int retval = command_run_line(cmd_ctx, command); free(command); + if (retval != ERROR_OK) + return retval; break; } case 'l': /* --log_output | -l */ @@ -289,16 +291,26 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[]) LOG_WARNING("deprecated option: -p/--pipe. Use '-c \"gdb_port pipe; " "log_output openocd.log\"' instead."); break; + default: /* '?' */ + /* getopt will emit an error message, all we have to do is bail. */ + return ERROR_FAIL; } } + if (optind < argc) { + /* Catch extra arguments on the command line. */ + LOG_OUTPUT("Unexpected command line argument: %s\n", argv[optind]); + return ERROR_FAIL; + } + if (help_flag) { LOG_OUTPUT("Open On-Chip Debugger\nLicensed under GNU GPL v2\n"); LOG_OUTPUT("--help | -h\tdisplay this help\n"); LOG_OUTPUT("--version | -v\tdisplay OpenOCD version\n"); LOG_OUTPUT("--file | -f\tuse configuration file \n"); LOG_OUTPUT("--search | -s\tdir to search for config files and scripts\n"); - LOG_OUTPUT("--debug | -d\tset debug level <0-3>\n"); + LOG_OUTPUT("--debug | -d\tset debug level to 3\n"); + LOG_OUTPUT(" | -d\tset debug level to \n"); LOG_OUTPUT("--log_output | -l\tredirect log output to file \n"); LOG_OUTPUT("--command | -c\trun \n"); exit(-1); diff --git a/src/helper/types.h b/src/helper/types.h index 1854ba85..58c9e724 100644 --- a/src/helper/types.h +++ b/src/helper/types.h @@ -296,14 +296,21 @@ static inline int parity_u32(uint32_t x) */ #if !defined(_STDINT_H) -#define PRIx32 "x" #define PRId32 "d" -#define SCNx32 "x" #define PRIi32 "i" +#define PRIo32 "o" #define PRIu32 "u" +#define PRIx32 "x" +#define PRIX32 "X" +#define SCNx32 "x" #define PRId8 PRId32 #define SCNx64 "llx" +#define PRId64 "lld" +#define PRIi64 "lli" +#define PRIo64 "llo" +#define PRIu64 "llu" #define PRIx64 "llx" +#define PRIX64 "llX" typedef CYG_ADDRWORD intptr_t; typedef int64_t intmax_t; @@ -337,4 +344,23 @@ typedef uint64_t uintmax_t; #endif +#if BUILD_TARGET64 +typedef uint64_t target_addr_t; +#define TARGET_ADDR_MAX UINT64_MAX +#define TARGET_PRIdADDR PRId64 +#define TARGET_PRIuADDR PRIu64 +#define TARGET_PRIoADDR PRIo64 +#define TARGET_PRIxADDR PRIx64 +#define TARGET_PRIXADDR PRIX64 +#else +typedef uint32_t target_addr_t; +#define TARGET_ADDR_MAX UINT32_MAX +#define TARGET_PRIdADDR PRId32 +#define TARGET_PRIuADDR PRIu32 +#define TARGET_PRIoADDR PRIo32 +#define TARGET_PRIxADDR PRIx32 +#define TARGET_PRIXADDR PRIX32 +#endif +#define TARGET_ADDR_FMT "0x%8.8" TARGET_PRIxADDR + #endif /* OPENOCD_HELPER_TYPES_H */ diff --git a/src/jtag/aice/aice_pipe.c b/src/jtag/aice/aice_pipe.c index 18ad40ea..bdc8c090 100644 --- a/src/jtag/aice/aice_pipe.c +++ b/src/jtag/aice/aice_pipe.c @@ -786,8 +786,8 @@ static int aice_pipe_memory_mode(uint32_t coreid, enum nds_memory_select mem_sel return ERROR_FAIL; } -static int aice_pipe_read_tlb(uint32_t coreid, uint32_t virtual_address, - uint32_t *physical_address) +static int aice_pipe_read_tlb(uint32_t coreid, target_addr_t virtual_address, + target_addr_t *physical_address) { char line[AICE_PIPE_MAXLINE]; char command[AICE_PIPE_MAXLINE]; diff --git a/src/jtag/aice/aice_port.h b/src/jtag/aice/aice_port.h index 4568ce12..d3d6a1a2 100644 --- a/src/jtag/aice/aice_port.h +++ b/src/jtag/aice/aice_port.h @@ -180,7 +180,7 @@ struct aice_port_api_s { int (*memory_mode)(uint32_t coreid, enum nds_memory_select mem_select); /** */ - int (*read_tlb)(uint32_t coreid, uint32_t virtual_address, uint32_t *physical_address); + int (*read_tlb)(uint32_t coreid, target_addr_t virtual_address, target_addr_t *physical_address); /** */ int (*cache_ctl)(uint32_t coreid, uint32_t subtype, uint32_t address); diff --git a/src/jtag/aice/aice_usb.c b/src/jtag/aice/aice_usb.c index b27f7200..50468f37 100644 --- a/src/jtag/aice/aice_usb.c +++ b/src/jtag/aice/aice_usb.c @@ -2135,10 +2135,16 @@ static int aice_usb_open(struct aice_port_param_s *param) /* usb_set_configuration required under win32 */ jtag_libusb_set_configuration(devh, 0); + jtag_libusb_claim_interface(devh, 0); unsigned int aice_read_ep; unsigned int aice_write_ep; - jtag_libusb_choose_interface(devh, &aice_read_ep, &aice_write_ep, -1, -1, -1); +#ifdef HAVE_LIBUSB1 + jtag_libusb_choose_interface(devh, &aice_read_ep, &aice_write_ep, -1, -1, -1, LIBUSB_TRANSFER_TYPE_BULK); +#else + jtag_libusb_choose_interface(devh, &aice_read_ep, &aice_write_ep, -1, -1, -1, USB_ENDPOINT_TYPE_BULK); +#endif + LOG_DEBUG("aice_read_ep=0x%x, aice_write_ep=0x%x", aice_read_ep, aice_write_ep); aice_handler.usb_read_ep = aice_read_ep; aice_handler.usb_write_ep = aice_write_ep; @@ -3424,10 +3430,10 @@ static int aice_usb_memory_mode(uint32_t coreid, enum nds_memory_select mem_sele return ERROR_OK; } -static int aice_usb_read_tlb(uint32_t coreid, uint32_t virtual_address, - uint32_t *physical_address) +static int aice_usb_read_tlb(uint32_t coreid, target_addr_t virtual_address, + target_addr_t *physical_address) { - LOG_DEBUG("aice_usb_read_tlb, virtual address: 0x%08" PRIx32, virtual_address); + LOG_DEBUG("aice_usb_read_tlb, virtual address: 0x%08" TARGET_PRIxADDR, virtual_address); uint32_t instructions[4]; uint32_t probe_result; diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index e4114126..3e5974da 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -144,14 +144,19 @@ endif if BCM2835GPIO DRIVERFILES += %D%/bcm2835gpio.c endif - if OPENJTAG DRIVERFILES += %D%/openjtag.c endif - if CMSIS_DAP DRIVERFILES += %D%/cmsis_dap_usb.c endif +if IMX_GPIO +DRIVERFILES += %D%/imx_gpio.c +endif + +if KITPROG +DRIVERFILES += %D%/kitprog.c +endif DRIVERHEADERS = \ %D%/bitbang.h \ diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c index dd37522a..86f79687 100644 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ b/src/jtag/drivers/cmsis_dap_usb.c @@ -821,7 +821,13 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq) return ERROR_FAIL; } - return cmsis_dap_cmd_DAP_SWJ_Sequence(s_len, s); + retval = cmsis_dap_cmd_DAP_SWJ_Sequence(s_len, s); + if (retval != ERROR_OK) + return retval; + + /* Atmel EDBG needs renew clock setting after SWJ_Sequence + * otherwise default frequency is used */ + return cmsis_dap_cmd_DAP_SWJ_Clock(jtag_get_speed_khz()); } static int cmsis_dap_swd_open(void) @@ -1493,13 +1499,11 @@ static int cmsis_dap_execute_queue(void) static int cmsis_dap_speed(int speed) { - if (speed > DAP_MAX_CLOCK) { - LOG_INFO("reduce speed request: %dkHz to %dkHz maximum", speed, DAP_MAX_CLOCK); - speed = DAP_MAX_CLOCK; - } + if (speed > DAP_MAX_CLOCK) + LOG_INFO("High speed (adapter_khz %d) may be limited by adapter firmware.", speed); if (speed == 0) { - LOG_INFO("RTCK not supported"); + LOG_ERROR("RTCK not supported. Set nonzero adapter_khz."); return ERROR_JTAG_NOT_IMPLEMENTED; } diff --git a/src/jtag/drivers/imx_gpio.c b/src/jtag/drivers/imx_gpio.c new file mode 100644 index 00000000..f33d1097 --- /dev/null +++ b/src/jtag/drivers/imx_gpio.c @@ -0,0 +1,552 @@ +/*************************************************************************** + * Copyright (C) 2017 by Grzegorz Kostka, kostka.grzegorz@gmail.com * + * * + * Based on bcm2835gpio.c * + * * + * 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 "bitbang.h" + +#include + +#define IMX_GPIO_BASE 0x0209c000 +#define IMX_GPIO_SIZE 0x00004000 +#define IMX_GPIO_REGS_COUNT 8 + +static uint32_t imx_gpio_peri_base = IMX_GPIO_BASE; + +struct imx_gpio_regs { + uint32_t dr; + uint32_t gdir; + uint32_t psr; + uint32_t icr1; + uint32_t icr2; + uint32_t imr; + uint32_t isr; + uint32_t edge_sel; +} __attribute__((aligned(IMX_GPIO_SIZE))); + +static int dev_mem_fd; +static volatile struct imx_gpio_regs *pio_base; + +/* GPIO setup functions */ +static inline bool gpio_mode_get(int g) +{ + return pio_base[g / 32].gdir >> (g & 0x1F) & 1; +} + +static inline void gpio_mode_input_set(int g) +{ + pio_base[g / 32].gdir &= ~(1u << (g & 0x1F)); +} + +static inline void gpio_mode_output_set(int g) +{ + pio_base[g / 32].gdir |= (1u << (g & 0x1F)); +} + +static inline void gpio_mode_set(int g, int m) +{ + (m) ? gpio_mode_output_set(g) : gpio_mode_input_set(g); +} + +static inline void gpio_set(int g) +{ + pio_base[g / 32].dr |= (1u << (g & 0x1F)); +} + +static inline void gpio_clear(int g) +{ + pio_base[g / 32].dr &= ~(1u << (g & 0x1F)); +} + +static inline bool gpio_level(int g) +{ + return pio_base[g / 32].dr >> (g & 0x1F) & 1; +} + +static int imx_gpio_read(void); +static void imx_gpio_write(int tck, int tms, int tdi); +static void imx_gpio_reset(int trst, int srst); + +static int imx_gpio_swdio_read(void); +static void imx_gpio_swdio_drive(bool is_output); + +static int imx_gpio_init(void); +static int imx_gpio_quit(void); + +static struct bitbang_interface imx_gpio_bitbang = { + .read = imx_gpio_read, + .write = imx_gpio_write, + .reset = imx_gpio_reset, + .swdio_read = imx_gpio_swdio_read, + .swdio_drive = imx_gpio_swdio_drive, + .blink = NULL +}; + +/* GPIO numbers for each signal. Negative values are invalid */ +static int tck_gpio = -1; +static int tck_gpio_mode; +static int tms_gpio = -1; +static int tms_gpio_mode; +static int tdi_gpio = -1; +static int tdi_gpio_mode; +static int tdo_gpio = -1; +static int tdo_gpio_mode; +static int trst_gpio = -1; +static int trst_gpio_mode; +static int srst_gpio = -1; +static int srst_gpio_mode; +static int swclk_gpio = -1; +static int swclk_gpio_mode; +static int swdio_gpio = -1; +static int swdio_gpio_mode; + +/* Transition delay coefficients. Tuned for IMX6UL 528MHz. Adjusted + * experimentally for:10kHz, 100Khz, 500KHz. Speeds above 800Khz are impossible + * to reach via memory mapped method (at least for IMX6UL@528MHz). + * Measured mmap raw GPIO toggling speed on IMX6UL@528MHz: 1.3MHz. + */ +static int speed_coeff = 50000; +static int speed_offset = 100; +static unsigned int jtag_delay; + +static int imx_gpio_read(void) +{ + return gpio_level(tdo_gpio); +} + +static void imx_gpio_write(int tck, int tms, int tdi) +{ + tms ? gpio_set(tms_gpio) : gpio_clear(tms_gpio); + tdi ? gpio_set(tdi_gpio) : gpio_clear(tdi_gpio); + tck ? gpio_set(tck_gpio) : gpio_clear(tck_gpio); + + for (unsigned int i = 0; i < jtag_delay; i++) + asm volatile (""); +} + +static void imx_gpio_swd_write(int tck, int tms, int tdi) +{ + tdi ? gpio_set(swdio_gpio) : gpio_clear(swdio_gpio); + tck ? gpio_set(swclk_gpio) : gpio_clear(swclk_gpio); + + for (unsigned int i = 0; i < jtag_delay; i++) + asm volatile (""); +} + +/* (1) assert or (0) deassert reset lines */ +static void imx_gpio_reset(int trst, int srst) +{ + if (trst_gpio != -1) + trst ? gpio_set(trst_gpio) : gpio_clear(trst_gpio); + + if (srst_gpio != -1) + srst ? gpio_set(srst_gpio) : gpio_clear(srst_gpio); +} + +static void imx_gpio_swdio_drive(bool is_output) +{ + if (is_output) + gpio_mode_output_set(swdio_gpio); + else + gpio_mode_input_set(swdio_gpio); +} + +static int imx_gpio_swdio_read(void) +{ + return gpio_level(swdio_gpio); +} + +static int imx_gpio_khz(int khz, int *jtag_speed) +{ + if (!khz) { + LOG_DEBUG("RCLK not supported"); + return ERROR_FAIL; + } + *jtag_speed = speed_coeff/khz - speed_offset; + if (*jtag_speed < 0) + *jtag_speed = 0; + return ERROR_OK; +} + +static int imx_gpio_speed_div(int speed, int *khz) +{ + *khz = speed_coeff/(speed + speed_offset); + return ERROR_OK; +} + +static int imx_gpio_speed(int speed) +{ + jtag_delay = speed; + return ERROR_OK; +} + +static int is_gpio_valid(int gpio) +{ + return gpio >= 0 && gpio < 32 * IMX_GPIO_REGS_COUNT; +} + +COMMAND_HANDLER(imx_gpio_handle_jtag_gpionums) +{ + if (CMD_ARGC == 4) { + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tms_gpio); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], tdi_gpio); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], tdo_gpio); + } else if (CMD_ARGC != 0) { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + command_print(CMD_CTX, + "imx_gpio GPIO config: tck = %d, tms = %d, tdi = %d, tdo = %d", + tck_gpio, tms_gpio, tdi_gpio, tdo_gpio); + + return ERROR_OK; +} + +COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tck) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio); + + command_print(CMD_CTX, "imx_gpio GPIO config: tck = %d", tck_gpio); + return ERROR_OK; +} + +COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tms) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio); + + command_print(CMD_CTX, "imx_gpio GPIO config: tms = %d", tms_gpio); + return ERROR_OK; +} + +COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tdo) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio); + + command_print(CMD_CTX, "imx_gpio GPIO config: tdo = %d", tdo_gpio); + return ERROR_OK; +} + +COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tdi) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio); + + command_print(CMD_CTX, "imx_gpio GPIO config: tdi = %d", tdi_gpio); + return ERROR_OK; +} + +COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_srst) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio); + + command_print(CMD_CTX, "imx_gpio GPIO config: srst = %d", srst_gpio); + return ERROR_OK; +} + +COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_trst) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio); + + command_print(CMD_CTX, "imx_gpio GPIO config: trst = %d", trst_gpio); + return ERROR_OK; +} + +COMMAND_HANDLER(imx_gpio_handle_swd_gpionums) +{ + if (CMD_ARGC == 2) { + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], swdio_gpio); + } else if (CMD_ARGC != 0) { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + command_print(CMD_CTX, + "imx_gpio GPIO nums: swclk = %d, swdio = %d", + swclk_gpio, swdio_gpio); + + return ERROR_OK; +} + +COMMAND_HANDLER(imx_gpio_handle_swd_gpionum_swclk) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio); + + command_print(CMD_CTX, "imx_gpio num: swclk = %d", swclk_gpio); + return ERROR_OK; +} + +COMMAND_HANDLER(imx_gpio_handle_swd_gpionum_swdio) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio); + + command_print(CMD_CTX, "imx_gpio num: swdio = %d", swdio_gpio); + return ERROR_OK; +} + +COMMAND_HANDLER(imx_gpio_handle_speed_coeffs) +{ + if (CMD_ARGC == 2) { + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], speed_coeff); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], speed_offset); + } + return ERROR_OK; +} + +COMMAND_HANDLER(imx_gpio_handle_peripheral_base) +{ + if (CMD_ARGC == 1) + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], imx_gpio_peri_base); + return ERROR_OK; +} + +static const struct command_registration imx_gpio_command_handlers[] = { + { + .name = "imx_gpio_jtag_nums", + .handler = &imx_gpio_handle_jtag_gpionums, + .mode = COMMAND_CONFIG, + .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)", + .usage = "(tck tms tdi tdo)* ", + }, + { + .name = "imx_gpio_tck_num", + .handler = &imx_gpio_handle_jtag_gpionum_tck, + .mode = COMMAND_CONFIG, + .help = "gpio number for tck.", + }, + { + .name = "imx_gpio_tms_num", + .handler = &imx_gpio_handle_jtag_gpionum_tms, + .mode = COMMAND_CONFIG, + .help = "gpio number for tms.", + }, + { + .name = "imx_gpio_tdo_num", + .handler = &imx_gpio_handle_jtag_gpionum_tdo, + .mode = COMMAND_CONFIG, + .help = "gpio number for tdo.", + }, + { + .name = "imx_gpio_tdi_num", + .handler = &imx_gpio_handle_jtag_gpionum_tdi, + .mode = COMMAND_CONFIG, + .help = "gpio number for tdi.", + }, + { + .name = "imx_gpio_swd_nums", + .handler = &imx_gpio_handle_swd_gpionums, + .mode = COMMAND_CONFIG, + .help = "gpio numbers for swclk, swdio. (in that order)", + .usage = "(swclk swdio)* ", + }, + { + .name = "imx_gpio_swclk_num", + .handler = &imx_gpio_handle_swd_gpionum_swclk, + .mode = COMMAND_CONFIG, + .help = "gpio number for swclk.", + }, + { + .name = "imx_gpio_swdio_num", + .handler = &imx_gpio_handle_swd_gpionum_swdio, + .mode = COMMAND_CONFIG, + .help = "gpio number for swdio.", + }, + { + .name = "imx_gpio_srst_num", + .handler = &imx_gpio_handle_jtag_gpionum_srst, + .mode = COMMAND_CONFIG, + .help = "gpio number for srst.", + }, + { + .name = "imx_gpio_trst_num", + .handler = &imx_gpio_handle_jtag_gpionum_trst, + .mode = COMMAND_CONFIG, + .help = "gpio number for trst.", + }, + { + .name = "imx_gpio_speed_coeffs", + .handler = &imx_gpio_handle_speed_coeffs, + .mode = COMMAND_CONFIG, + .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.", + }, + { + .name = "imx_gpio_peripheral_base", + .handler = &imx_gpio_handle_peripheral_base, + .mode = COMMAND_CONFIG, + .help = "peripheral base to access GPIOs (0x0209c000 for most IMX).", + }, + + COMMAND_REGISTRATION_DONE +}; + +static const char * const imx_gpio_transports[] = { "jtag", "swd", NULL }; + +struct jtag_interface imx_gpio_interface = { + .name = "imx_gpio", + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = bitbang_execute_queue, + .transports = imx_gpio_transports, + .swd = &bitbang_swd, + .speed = imx_gpio_speed, + .khz = imx_gpio_khz, + .speed_div = imx_gpio_speed_div, + .commands = imx_gpio_command_handlers, + .init = imx_gpio_init, + .quit = imx_gpio_quit, +}; + +static bool imx_gpio_jtag_mode_possible(void) +{ + if (!is_gpio_valid(tck_gpio)) + return 0; + if (!is_gpio_valid(tms_gpio)) + return 0; + if (!is_gpio_valid(tdi_gpio)) + return 0; + if (!is_gpio_valid(tdo_gpio)) + return 0; + return 1; +} + +static bool imx_gpio_swd_mode_possible(void) +{ + if (!is_gpio_valid(swclk_gpio)) + return 0; + if (!is_gpio_valid(swdio_gpio)) + return 0; + return 1; +} + +static int imx_gpio_init(void) +{ + bitbang_interface = &imx_gpio_bitbang; + + LOG_INFO("imx_gpio GPIO JTAG/SWD bitbang driver"); + + if (imx_gpio_jtag_mode_possible()) { + if (imx_gpio_swd_mode_possible()) + LOG_INFO("JTAG and SWD modes enabled"); + else + LOG_INFO("JTAG only mode enabled (specify swclk and swdio gpio to add SWD mode)"); + } else if (imx_gpio_swd_mode_possible()) { + LOG_INFO("SWD only mode enabled (specify tck, tms, tdi and tdo gpios to add JTAG mode)"); + } else { + LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode and/or swclk and swdio gpio for SWD mode"); + return ERROR_JTAG_INIT_FAILED; + } + + dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC); + if (dev_mem_fd < 0) { + perror("open"); + return ERROR_JTAG_INIT_FAILED; + } + + + LOG_INFO("imx_gpio mmap: pagesize: %u, regionsize: %u", + sysconf(_SC_PAGE_SIZE), IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE); + pio_base = mmap(NULL, IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, dev_mem_fd, imx_gpio_peri_base); + + if (pio_base == MAP_FAILED) { + perror("mmap"); + close(dev_mem_fd); + return ERROR_JTAG_INIT_FAILED; + } + + /* + * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST + * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high. + */ + if (imx_gpio_jtag_mode_possible()) { + tdo_gpio_mode = gpio_mode_get(tdo_gpio); + tdi_gpio_mode = gpio_mode_get(tdi_gpio); + tck_gpio_mode = gpio_mode_get(tck_gpio); + tms_gpio_mode = gpio_mode_get(tms_gpio); + + gpio_clear(tdi_gpio); + gpio_clear(tck_gpio); + gpio_set(tms_gpio); + + gpio_mode_input_set(tdo_gpio); + gpio_mode_output_set(tdi_gpio); + gpio_mode_output_set(tck_gpio); + gpio_mode_output_set(tms_gpio); + } + if (imx_gpio_swd_mode_possible()) { + swclk_gpio_mode = gpio_mode_get(swclk_gpio); + swdio_gpio_mode = gpio_mode_get(swdio_gpio); + + gpio_clear(swdio_gpio); + gpio_clear(swclk_gpio); + gpio_mode_output_set(swclk_gpio); + gpio_mode_output_set(swdio_gpio); + } + if (trst_gpio != -1) { + trst_gpio_mode = gpio_mode_get(trst_gpio); + gpio_set(trst_gpio); + gpio_mode_output_set(trst_gpio); + } + if (srst_gpio != -1) { + srst_gpio_mode = gpio_mode_get(srst_gpio); + gpio_set(srst_gpio); + gpio_mode_output_set(srst_gpio); + } + + LOG_DEBUG("saved pinmux settings: tck %d tms %d tdi %d " + "tdo %d trst %d srst %d", tck_gpio_mode, tms_gpio_mode, + tdi_gpio_mode, tdo_gpio_mode, trst_gpio_mode, srst_gpio_mode); + + if (swd_mode) { + imx_gpio_bitbang.write = imx_gpio_swd_write; + bitbang_switch_to_swd(); + } + + return ERROR_OK; +} + +static int imx_gpio_quit(void) +{ + if (imx_gpio_jtag_mode_possible()) { + gpio_mode_set(tdo_gpio, tdo_gpio_mode); + gpio_mode_set(tdi_gpio, tdi_gpio_mode); + gpio_mode_set(tck_gpio, tck_gpio_mode); + gpio_mode_set(tms_gpio, tms_gpio_mode); + } + if (imx_gpio_swd_mode_possible()) { + gpio_mode_set(swclk_gpio, swclk_gpio_mode); + gpio_mode_set(swdio_gpio, swdio_gpio_mode); + } + if (trst_gpio != -1) + gpio_mode_set(trst_gpio, trst_gpio_mode); + if (srst_gpio != -1) + gpio_mode_set(srst_gpio, srst_gpio_mode); + + return ERROR_OK; +} diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c new file mode 100644 index 00000000..c689848c --- /dev/null +++ b/src/jtag/drivers/kitprog.c @@ -0,0 +1,967 @@ +/*************************************************************************** + * Copyright (C) 2007 by Juergen Stuber * + * based on Dominic Rath's and Benedikt Sauter's usbprog.c * + * * + * Copyright (C) 2008 by Spencer Oliver * + * spen@spen-soft.co.uk * + * * + * Copyright (C) 2011 by Jean-Christophe PLAGNIOL-VIILARD * + * plagnioj@jcrosoft.com * + * * + * Copyright (C) 2015 by Marc Schink * + * openocd-dev@marcschink.de * + * * + * Copyright (C) 2015 by Paul Fertser * + * fercerpav@gmail.com * + * * + * Copyright (C) 2015-2017 by Forest Crossman * + * cyrozap@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 +#include + +#include "libusb_common.h" + +#define VID 0x04b4 +#define PID 0xf139 + +#define BULK_EP_IN 1 +#define BULK_EP_OUT 2 + +#define CONTROL_TYPE_READ 0x01 +#define CONTROL_TYPE_WRITE 0x02 + +#define CONTROL_COMMAND_PROGRAM 0x07 + +#define CONTROL_MODE_POLL_PROGRAMMER_STATUS 0x01 +#define CONTROL_MODE_RESET_TARGET 0x04 +#define CONTROL_MODE_SET_PROGRAMMER_PROTOCOL 0x40 +#define CONTROL_MODE_SYNCHRONIZE_TRANSFER 0x41 +#define CONTROL_MODE_ACQUIRE_SWD_TARGET 0x42 +#define CONTROL_MODE_SEND_SWD_SEQUENCE 0x43 + +#define PROTOCOL_JTAG 0x00 +#define PROTOCOL_SWD 0x01 + +#define DEVICE_PSOC4 0x00 +#define DEVICE_PSOC3 0x01 +#define DEVICE_UNKNOWN 0x02 +#define DEVICE_PSOC5 0x03 + +#define ACQUIRE_MODE_RESET 0x00 +#define ACQUIRE_MODE_POWER_CYCLE 0x01 + +#define SEQUENCE_LINE_RESET 0x00 +#define SEQUENCE_JTAG_TO_SWD 0x01 + +#define PROGRAMMER_NOK_NACK 0x00 +#define PROGRAMMER_OK_ACK 0x01 + +#define HID_TYPE_WRITE 0x00 +#define HID_TYPE_READ 0x01 +#define HID_TYPE_START 0x02 + +#define HID_COMMAND_POWER 0x80 +#define HID_COMMAND_VERSION 0x81 +#define HID_COMMAND_RESET 0x82 +#define HID_COMMAND_CONFIGURE 0x8f +#define HID_COMMAND_BOOTLOADER 0xa0 + +/* 512 bytes seems to work reliably */ +#define SWD_MAX_BUFFER_LENGTH 512 + +struct kitprog { + hid_device *hid_handle; + struct jtag_libusb_device_handle *usb_handle; + uint16_t packet_size; + uint16_t packet_index; + uint8_t *packet_buffer; + char *serial; + uint8_t hardware_version; + uint8_t minor_version; + uint8_t major_version; + uint16_t millivolts; + + bool supports_jtag_to_swd; +}; + +struct pending_transfer_result { + uint8_t cmd; + uint32_t data; + void *buffer; +}; + +static char *kitprog_serial; +static bool kitprog_init_acquire_psoc; + +static int pending_transfer_count, pending_queue_len; +static struct pending_transfer_result *pending_transfers; + +static int queued_retval; + +static struct kitprog *kitprog_handle; + +static int kitprog_usb_open(void); +static void kitprog_usb_close(void); + +static int kitprog_hid_command(uint8_t *command, size_t command_length, + uint8_t *data, size_t data_length); +static int kitprog_get_version(void); +static int kitprog_get_millivolts(void); +static int kitprog_get_info(void); +static int kitprog_set_protocol(uint8_t protocol); +static int kitprog_get_status(void); +static int kitprog_set_unknown(void); +static int kitprog_acquire_psoc(uint8_t psoc_type, uint8_t acquire_mode, + uint8_t max_attempts); +static int kitprog_reset_target(void); +static int kitprog_swd_sync(void); +static int kitprog_swd_seq(uint8_t seq_type); + +static int kitprog_generic_acquire(void); + +static int kitprog_swd_run_queue(void); +static void kitprog_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data); +static int kitprog_swd_switch_seq(enum swd_special_seq seq); + + +static inline int mm_to_version(uint8_t major, uint8_t minor) +{ + return (major << 8) | minor; +} + +static int kitprog_init(void) +{ + int retval; + + kitprog_handle = malloc(sizeof(struct kitprog)); + if (kitprog_handle == NULL) { + LOG_ERROR("Failed to allocate memory"); + return ERROR_FAIL; + } + + if (kitprog_usb_open() != ERROR_OK) { + LOG_ERROR("Can't find a KitProg device! Please check device connections and permissions."); + return ERROR_JTAG_INIT_FAILED; + } + + /* Get the current KitProg version and target voltage */ + if (kitprog_get_info() != ERROR_OK) + return ERROR_FAIL; + + /* Compatibility check */ + kitprog_handle->supports_jtag_to_swd = true; + int kitprog_version = mm_to_version(kitprog_handle->major_version, kitprog_handle->minor_version); + if (kitprog_version < mm_to_version(2, 14)) { + LOG_WARNING("KitProg firmware versions below v2.14 do not support sending JTAG to SWD sequences. These sequences will be substituted with SWD line resets."); + kitprog_handle->supports_jtag_to_swd = false; + } + + /* I have no idea what this does */ + if (kitprog_set_unknown() != ERROR_OK) + return ERROR_FAIL; + + /* SWD won't work unless we do this */ + if (kitprog_swd_sync() != ERROR_OK) + return ERROR_FAIL; + + /* Set the protocol to SWD */ + if (kitprog_set_protocol(PROTOCOL_SWD) != ERROR_OK) + return ERROR_FAIL; + + /* Reset the SWD bus */ + if (kitprog_swd_seq(SEQUENCE_LINE_RESET) != ERROR_OK) + return ERROR_FAIL; + + if (kitprog_init_acquire_psoc) { + /* Try to acquire any device that will respond */ + retval = kitprog_generic_acquire(); + if (retval != ERROR_OK) { + LOG_ERROR("No PSoC devices found"); + return retval; + } + } + + /* Allocate packet buffers and queues */ + kitprog_handle->packet_size = SWD_MAX_BUFFER_LENGTH; + kitprog_handle->packet_buffer = malloc(SWD_MAX_BUFFER_LENGTH); + if (kitprog_handle->packet_buffer == NULL) { + LOG_ERROR("Failed to allocate memory for the packet buffer"); + return ERROR_FAIL; + } + + pending_queue_len = SWD_MAX_BUFFER_LENGTH / 5; + pending_transfers = malloc(pending_queue_len * sizeof(*pending_transfers)); + if (pending_transfers == NULL) { + LOG_ERROR("Failed to allocate memory for the SWD transfer queue"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int kitprog_quit(void) +{ + kitprog_usb_close(); + + if (kitprog_handle->packet_buffer != NULL) + free(kitprog_handle->packet_buffer); + if (kitprog_handle->serial != NULL) + free(kitprog_handle->serial); + if (kitprog_handle != NULL) + free(kitprog_handle); + + if (kitprog_serial != NULL) + free(kitprog_serial); + + if (pending_transfers != NULL) + free(pending_transfers); + + return ERROR_OK; +} + +/*************** kitprog usb functions *********************/ + +static int kitprog_get_usb_serial(void) +{ + int retval; + const uint8_t str_index = 128; /* This seems to be a constant */ + char desc_string[256+1]; /* Max size of string descriptor */ + + retval = libusb_get_string_descriptor_ascii(kitprog_handle->usb_handle, + str_index, (unsigned char *)desc_string, sizeof(desc_string)-1); + if (retval < 0) { + LOG_ERROR("libusb_get_string_descriptor_ascii() failed with %d", retval); + return ERROR_FAIL; + } + + /* Null terminate descriptor string */ + desc_string[retval] = '\0'; + + /* Allocate memory for the serial number */ + kitprog_handle->serial = calloc(retval + 1, sizeof(char)); + if (kitprog_handle->serial == NULL) { + LOG_ERROR("Failed to allocate memory for the serial number"); + return ERROR_FAIL; + } + + /* Store the serial number */ + strncpy(kitprog_handle->serial, desc_string, retval + 1); + + return ERROR_OK; +} + +static int kitprog_usb_open(void) +{ + const uint16_t vids[] = { VID, 0 }; + const uint16_t pids[] = { PID, 0 }; + + if (jtag_libusb_open(vids, pids, kitprog_serial, + &kitprog_handle->usb_handle) != ERROR_OK) { + LOG_ERROR("Failed to open or find the device"); + return ERROR_FAIL; + } + + /* Get the serial number for the device */ + if (kitprog_get_usb_serial() != ERROR_OK) + LOG_WARNING("Failed to get KitProg serial number"); + + /* Convert the ASCII serial number into a (wchar_t *) */ + size_t len = strlen(kitprog_handle->serial); + wchar_t *hid_serial = calloc(len + 1, sizeof(wchar_t)); + if (hid_serial == NULL) { + LOG_ERROR("Failed to allocate memory for the serial number"); + return ERROR_FAIL; + } + if (mbstowcs(hid_serial, kitprog_handle->serial, len + 1) == (size_t)-1) { + free(hid_serial); + LOG_ERROR("Failed to convert serial number"); + return ERROR_FAIL; + } + + /* Use HID for the KitBridge interface */ + kitprog_handle->hid_handle = hid_open(VID, PID, hid_serial); + free(hid_serial); + if (kitprog_handle->hid_handle == NULL) { + LOG_ERROR("Failed to open KitBridge (HID) interface"); + return ERROR_FAIL; + } + + /* Claim the KitProg Programmer (bulk transfer) interface */ + if (jtag_libusb_claim_interface(kitprog_handle->usb_handle, 1) != ERROR_OK) { + LOG_ERROR("Failed to claim KitProg Programmer (bulk transfer) interface"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static void kitprog_usb_close(void) +{ + if (kitprog_handle->hid_handle != NULL) { + hid_close(kitprog_handle->hid_handle); + hid_exit(); + } + + jtag_libusb_close(kitprog_handle->usb_handle); +} + +/*************** kitprog lowlevel functions *********************/ + +static int kitprog_hid_command(uint8_t *command, size_t command_length, + uint8_t *data, size_t data_length) +{ + int ret; + + ret = hid_write(kitprog_handle->hid_handle, command, command_length); + if (ret < 0) { + LOG_DEBUG("HID write returned %i", ret); + return ERROR_FAIL; + } + + ret = hid_read(kitprog_handle->hid_handle, data, data_length); + if (ret < 0) { + LOG_DEBUG("HID read returned %i", ret); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int kitprog_get_version(void) +{ + int ret; + + unsigned char command[3] = {HID_TYPE_START | HID_TYPE_WRITE, 0x00, HID_COMMAND_VERSION}; + unsigned char data[64]; + + ret = kitprog_hid_command(command, sizeof command, data, sizeof data); + if (ret != ERROR_OK) + return ret; + + kitprog_handle->hardware_version = data[1]; + kitprog_handle->minor_version = data[2]; + kitprog_handle->major_version = data[3]; + + return ERROR_OK; +} + +static int kitprog_get_millivolts(void) +{ + int ret; + + unsigned char command[3] = {HID_TYPE_START | HID_TYPE_READ, 0x00, HID_COMMAND_POWER}; + unsigned char data[64]; + + ret = kitprog_hid_command(command, sizeof command, data, sizeof data); + if (ret != ERROR_OK) + return ret; + + kitprog_handle->millivolts = (data[4] << 8) | data[3]; + + return ERROR_OK; +} + +static int kitprog_get_info(void) +{ + /* Get the device version information */ + if (kitprog_get_version() == ERROR_OK) { + LOG_INFO("KitProg v%u.%02u", + kitprog_handle->major_version, kitprog_handle->minor_version); + LOG_INFO("Hardware version: %u", + kitprog_handle->hardware_version); + } else { + LOG_ERROR("Failed to get KitProg version"); + return ERROR_FAIL; + } + + /* Get the current reported target voltage */ + if (kitprog_get_millivolts() == ERROR_OK) { + LOG_INFO("VTARG = %u.%03u V", + kitprog_handle->millivolts / 1000, kitprog_handle->millivolts % 1000); + } else { + LOG_ERROR("Failed to get target voltage"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int kitprog_set_protocol(uint8_t protocol) +{ + int transferred; + char status = PROGRAMMER_NOK_NACK; + + transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + CONTROL_TYPE_WRITE, + (CONTROL_MODE_SET_PROGRAMMER_PROTOCOL << 8) | CONTROL_COMMAND_PROGRAM, + protocol, &status, 1, 0); + + if (transferred == 0) { + LOG_DEBUG("Zero bytes transferred"); + return ERROR_FAIL; + } + + if (status != PROGRAMMER_OK_ACK) { + LOG_DEBUG("Programmer did not respond OK"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int kitprog_get_status(void) +{ + int transferred = 0; + char status = PROGRAMMER_NOK_NACK; + + /* Try a maximum of three times */ + for (int i = 0; (i < 3) && (transferred == 0); i++) { + transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + CONTROL_TYPE_READ, + (CONTROL_MODE_POLL_PROGRAMMER_STATUS << 8) | CONTROL_COMMAND_PROGRAM, + 0, &status, 1, 0); + jtag_sleep(1000); + } + + if (transferred == 0) { + LOG_DEBUG("Zero bytes transferred"); + return ERROR_FAIL; + } + + if (status != PROGRAMMER_OK_ACK) { + LOG_DEBUG("Programmer did not respond OK"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int kitprog_set_unknown(void) +{ + int transferred; + char status = PROGRAMMER_NOK_NACK; + + transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + CONTROL_TYPE_WRITE, + (0x03 << 8) | 0x04, + 0, &status, 1, 0); + + if (transferred == 0) { + LOG_DEBUG("Zero bytes transferred"); + return ERROR_FAIL; + } + + if (status != PROGRAMMER_OK_ACK) { + LOG_DEBUG("Programmer did not respond OK"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int kitprog_acquire_psoc(uint8_t psoc_type, uint8_t acquire_mode, + uint8_t max_attempts) +{ + int transferred; + char status = PROGRAMMER_NOK_NACK; + + transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + CONTROL_TYPE_WRITE, + (CONTROL_MODE_ACQUIRE_SWD_TARGET << 8) | CONTROL_COMMAND_PROGRAM, + (max_attempts << 8) | (acquire_mode << 4) | psoc_type, &status, 1, 0); + + if (transferred == 0) { + LOG_DEBUG("Zero bytes transferred"); + return ERROR_FAIL; + } + + if (status != PROGRAMMER_OK_ACK) { + LOG_DEBUG("Programmer did not respond OK"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int kitprog_reset_target(void) +{ + int transferred; + char status = PROGRAMMER_NOK_NACK; + + transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + CONTROL_TYPE_WRITE, + (CONTROL_MODE_RESET_TARGET << 8) | CONTROL_COMMAND_PROGRAM, + 0, &status, 1, 0); + + if (transferred == 0) { + LOG_DEBUG("Zero bytes transferred"); + return ERROR_FAIL; + } + + if (status != PROGRAMMER_OK_ACK) { + LOG_DEBUG("Programmer did not respond OK"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int kitprog_swd_sync(void) +{ + int transferred; + char status = PROGRAMMER_NOK_NACK; + + transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + CONTROL_TYPE_WRITE, + (CONTROL_MODE_SYNCHRONIZE_TRANSFER << 8) | CONTROL_COMMAND_PROGRAM, + 0, &status, 1, 0); + + if (transferred == 0) { + LOG_DEBUG("Zero bytes transferred"); + return ERROR_FAIL; + } + + if (status != PROGRAMMER_OK_ACK) { + LOG_DEBUG("Programmer did not respond OK"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int kitprog_swd_seq(uint8_t seq_type) +{ + int transferred; + char status = PROGRAMMER_NOK_NACK; + + transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + CONTROL_TYPE_WRITE, + (CONTROL_MODE_SEND_SWD_SEQUENCE << 8) | CONTROL_COMMAND_PROGRAM, + seq_type, &status, 1, 0); + + if (transferred == 0) { + LOG_DEBUG("Zero bytes transferred"); + return ERROR_FAIL; + } + + if (status != PROGRAMMER_OK_ACK) { + LOG_DEBUG("Programmer did not respond OK"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int kitprog_generic_acquire(void) +{ + const uint8_t devices[] = {DEVICE_PSOC4, DEVICE_PSOC3, DEVICE_PSOC5}; + + int retval; + int acquire_count = 0; + + /* Due to the way the SWD port is shared between the Test Controller (TC) + * and the Cortex-M3 DAP on the PSoC 5LP, the TC is the default SWD target + * after power is applied. To access the DAP, the PSoC 5LP requires at least + * one acquisition sequence to be run (which switches the SWD mux from the + * TC to the DAP). However, after the mux is switched, the Cortex-M3 will be + * held in reset until a series of registers are written to (see section 5.2 + * of the PSoC 5LP Device Programming Specifications for details). + * + * Instead of writing the registers in this function, we just do what the + * Cypress tools do and run the acquisition sequence a second time. This + * will take the Cortex-M3 out of reset and enable debugging. + */ + for (int i = 0; i < 2; i++) { + for (uint8_t j = 0; j < sizeof devices && acquire_count == i; j++) { + retval = kitprog_acquire_psoc(devices[j], ACQUIRE_MODE_RESET, 3); + if (retval != ERROR_OK) { + LOG_DEBUG("Aquisition function failed for device 0x%02x.", devices[j]); + return retval; + } + + if (kitprog_get_status() == ERROR_OK) + acquire_count++; + } + + jtag_sleep(10); + } + + if (acquire_count < 2) + return ERROR_FAIL; + + return ERROR_OK; +} + +/*************** swd wrapper functions *********************/ + +static int kitprog_swd_init(void) +{ + return ERROR_OK; +} + +static void kitprog_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) +{ + assert(!(cmd & SWD_CMD_RnW)); + kitprog_swd_queue_cmd(cmd, NULL, value); +} + +static void kitprog_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) +{ + assert(cmd & SWD_CMD_RnW); + kitprog_swd_queue_cmd(cmd, value, 0); +} + +/*************** swd lowlevel functions ********************/ + +static int kitprog_swd_switch_seq(enum swd_special_seq seq) +{ + switch (seq) { + case JTAG_TO_SWD: + if (kitprog_handle->supports_jtag_to_swd) { + LOG_DEBUG("JTAG to SWD"); + if (kitprog_swd_seq(SEQUENCE_JTAG_TO_SWD) != ERROR_OK) + return ERROR_FAIL; + break; + } else { + LOG_DEBUG("JTAG to SWD not supported"); + /* Fall through to fix target reset issue */ + } + case LINE_RESET: + LOG_DEBUG("SWD line reset"); + if (kitprog_swd_seq(SEQUENCE_LINE_RESET) != ERROR_OK) + return ERROR_FAIL; + break; + default: + LOG_ERROR("Sequence %d not supported.", seq); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int kitprog_swd_run_queue(void) +{ + int ret; + + size_t read_count = 0; + size_t read_index = 0; + size_t write_count = 0; + uint8_t *buffer = kitprog_handle->packet_buffer; + + do { + LOG_DEBUG("Executing %d queued transactions", pending_transfer_count); + + if (queued_retval != ERROR_OK) { + LOG_DEBUG("Skipping due to previous errors: %d", queued_retval); + break; + } + + if (!pending_transfer_count) + break; + + for (int i = 0; i < pending_transfer_count; i++) { + uint8_t cmd = pending_transfers[i].cmd; + uint32_t data = pending_transfers[i].data; + + /* When proper WAIT handling is implemented in the + * common SWD framework, this kludge can be + * removed. However, this might lead to minor + * performance degradation as the adapter wouldn't be + * able to automatically retry anything (because ARM + * has forgotten to implement sticky error flags + * clearing). See also comments regarding + * cmsis_dap_cmd_DAP_TFER_Configure() and + * cmsis_dap_cmd_DAP_SWD_Configure() in + * cmsis_dap_init(). + */ + if (!(cmd & SWD_CMD_RnW) && + !(cmd & SWD_CMD_APnDP) && + (cmd & SWD_CMD_A32) >> 1 == DP_CTRL_STAT && + (data & CORUNDETECT)) { + LOG_DEBUG("refusing to enable sticky overrun detection"); + data &= ~CORUNDETECT; + } + +#if 0 + LOG_DEBUG("%s %s reg %x %"PRIx32, + cmd & SWD_CMD_APnDP ? "AP" : "DP", + cmd & SWD_CMD_RnW ? "read" : "write", + (cmd & SWD_CMD_A32) >> 1, data); +#endif + + buffer[write_count++] = (cmd | SWD_CMD_START | SWD_CMD_PARK) & ~SWD_CMD_STOP; + read_count++; + if (!(cmd & SWD_CMD_RnW)) { + buffer[write_count++] = (data) & 0xff; + buffer[write_count++] = (data >> 8) & 0xff; + buffer[write_count++] = (data >> 16) & 0xff; + buffer[write_count++] = (data >> 24) & 0xff; + } else { + read_count += 4; + } + } + + ret = jtag_libusb_bulk_write(kitprog_handle->usb_handle, + BULK_EP_OUT, (char *)buffer, write_count, 0); + if (ret > 0) { + queued_retval = ERROR_OK; + } else { + LOG_ERROR("Bulk write failed"); + queued_retval = ERROR_FAIL; + break; + } + + /* We use the maximum buffer size here because the KitProg sometimes + * doesn't like bulk reads of fewer than 62 bytes. (?!?!) + */ + ret = jtag_libusb_bulk_read(kitprog_handle->usb_handle, + BULK_EP_IN | LIBUSB_ENDPOINT_IN, (char *)buffer, + SWD_MAX_BUFFER_LENGTH, 0); + if (ret > 0) { + /* Handle garbage data by offsetting the initial read index */ + if ((unsigned int)ret > read_count) + read_index = ret - read_count; + queued_retval = ERROR_OK; + } else { + LOG_ERROR("Bulk read failed"); + queued_retval = ERROR_FAIL; + break; + } + + for (int i = 0; i < pending_transfer_count; i++) { + if (pending_transfers[i].cmd & SWD_CMD_RnW) { + uint32_t data = le_to_h_u32(&buffer[read_index]); + +#if 0 + LOG_DEBUG("Read result: %"PRIx32, data); +#endif + + if (pending_transfers[i].buffer) + *(uint32_t *)pending_transfers[i].buffer = data; + + read_index += 4; + } + + uint8_t ack = buffer[read_index] & 0x07; + if (ack != SWD_ACK_OK || (buffer[read_index] & 0x08)) { + LOG_DEBUG("SWD ack not OK: %d %s", i, + ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK"); + queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL; + break; + } + read_index++; + } + } while (0); + + pending_transfer_count = 0; + int retval = queued_retval; + queued_retval = ERROR_OK; + + return retval; +} + +static void kitprog_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data) +{ + if (pending_transfer_count == pending_queue_len) { + /* Not enough room in the queue. Run the queue. */ + queued_retval = kitprog_swd_run_queue(); + } + + if (queued_retval != ERROR_OK) + return; + + pending_transfers[pending_transfer_count].data = data; + pending_transfers[pending_transfer_count].cmd = cmd; + if (cmd & SWD_CMD_RnW) { + /* Queue a read transaction */ + pending_transfers[pending_transfer_count].buffer = dst; + } + pending_transfer_count++; +} + +/*************** jtag lowlevel functions ********************/ + +static void kitprog_execute_reset(struct jtag_command *cmd) +{ + int retval = ERROR_OK; + + if (cmd->cmd.reset->srst == 1) { + retval = kitprog_reset_target(); + /* Since the previous command also disables SWCLK output, we need to send an + * SWD bus reset command to re-enable it. For some reason, running + * kitprog_swd_seq() immediately after kitprog_reset_target() won't + * actually fix this. Instead, kitprog_swd_seq() will be run once OpenOCD + * tries to send a JTAG-to-SWD sequence, which should happen during + * swd_check_reconnect (see the JTAG_TO_SWD case in kitprog_swd_switch_seq). + */ + } + + if (retval != ERROR_OK) + LOG_ERROR("KitProg: Interface reset failed"); +} + +static void kitprog_execute_sleep(struct jtag_command *cmd) +{ + jtag_sleep(cmd->cmd.sleep->us); +} + +static void kitprog_execute_command(struct jtag_command *cmd) +{ + switch (cmd->type) { + case JTAG_RESET: + kitprog_execute_reset(cmd); + break; + case JTAG_SLEEP: + kitprog_execute_sleep(cmd); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); + } +} + +static int kitprog_execute_queue(void) +{ + struct jtag_command *cmd = jtag_command_queue; + + while (cmd != NULL) { + kitprog_execute_command(cmd); + cmd = cmd->next; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(kitprog_handle_info_command) +{ + int retval = kitprog_get_info(); + + return retval; +} + + +COMMAND_HANDLER(kitprog_handle_acquire_psoc_command) +{ + int retval = kitprog_generic_acquire(); + + return retval; +} + +COMMAND_HANDLER(kitprog_handle_serial_command) +{ + if (CMD_ARGC == 1) { + size_t len = strlen(CMD_ARGV[0]); + kitprog_serial = calloc(len + 1, sizeof(char)); + if (kitprog_serial == NULL) { + LOG_ERROR("Failed to allocate memory for the serial number"); + return ERROR_FAIL; + } + strncpy(kitprog_serial, CMD_ARGV[0], len + 1); + } else { + LOG_ERROR("expected exactly one argument to kitprog_serial "); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(kitprog_handle_init_acquire_psoc_command) +{ + kitprog_init_acquire_psoc = true; + + return ERROR_OK; +} + +static const struct command_registration kitprog_subcommand_handlers[] = { + { + .name = "info", + .handler = &kitprog_handle_info_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "show KitProg info", + }, + { + .name = "acquire_psoc", + .handler = &kitprog_handle_acquire_psoc_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "try to acquire a PSoC", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration kitprog_command_handlers[] = { + { + .name = "kitprog", + .mode = COMMAND_ANY, + .help = "perform KitProg management", + .usage = "", + .chain = kitprog_subcommand_handlers, + }, + { + .name = "kitprog_serial", + .handler = &kitprog_handle_serial_command, + .mode = COMMAND_CONFIG, + .help = "set the serial number of the adapter", + .usage = "serial_string", + }, + { + .name = "kitprog_init_acquire_psoc", + .handler = &kitprog_handle_init_acquire_psoc_command, + .mode = COMMAND_CONFIG, + .help = "try to acquire a PSoC during init", + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct swd_driver kitprog_swd = { + .init = kitprog_swd_init, + .switch_seq = kitprog_swd_switch_seq, + .read_reg = kitprog_swd_read_reg, + .write_reg = kitprog_swd_write_reg, + .run = kitprog_swd_run_queue, +}; + +static const char * const kitprog_transports[] = { "swd", NULL }; + +struct jtag_interface kitprog_interface = { + .name = "kitprog", + .commands = kitprog_command_handlers, + .transports = kitprog_transports, + .swd = &kitprog_swd, + .execute_queue = kitprog_execute_queue, + .init = kitprog_init, + .quit = kitprog_quit +}; diff --git a/src/jtag/drivers/libusb0_common.c b/src/jtag/drivers/libusb0_common.c index e319751a..1825543e 100644 --- a/src/jtag/drivers/libusb0_common.c +++ b/src/jtag/drivers/libusb0_common.c @@ -146,7 +146,7 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh, int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh, unsigned int *usb_read_ep, unsigned int *usb_write_ep, - int bclass, int subclass, int protocol) + int bclass, int subclass, int protocol, int trans_type) { struct jtag_libusb_device *udev = jtag_libusb_get_device(devh); struct usb_interface *iface = udev->config->interface; @@ -157,7 +157,8 @@ int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh, for (int i = 0; i < desc->bNumEndpoints; i++) { if ((bclass > 0 && desc->bInterfaceClass != bclass) || (subclass > 0 && desc->bInterfaceSubClass != subclass) || - (protocol > 0 && desc->bInterfaceProtocol != protocol)) + (protocol > 0 && desc->bInterfaceProtocol != protocol) || + (trans_type > 0 && (desc->endpoint[i].bmAttributes & 0x3) != trans_type)) continue; uint8_t epnum = desc->endpoint[i].bEndpointAddress; diff --git a/src/jtag/drivers/libusb0_common.h b/src/jtag/drivers/libusb0_common.h index 7163b431..baa9e3c5 100644 --- a/src/jtag/drivers/libusb0_common.h +++ b/src/jtag/drivers/libusb0_common.h @@ -67,7 +67,7 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh, int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh, unsigned int *usb_read_ep, unsigned int *usb_write_ep, - int bclass, int subclass, int protocol); + int bclass, int subclass, int protocol, int trans_type); int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid); #endif /* OPENOCD_JTAG_DRIVERS_LIBUSB0_COMMON_H */ diff --git a/src/jtag/drivers/libusb1_common.c b/src/jtag/drivers/libusb1_common.c index f8b7c754..89f80927 100644 --- a/src/jtag/drivers/libusb1_common.c +++ b/src/jtag/drivers/libusb1_common.c @@ -187,7 +187,7 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh, int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh, unsigned int *usb_read_ep, unsigned int *usb_write_ep, - int bclass, int subclass, int protocol) + int bclass, int subclass, int protocol, int trans_type) { struct jtag_libusb_device *udev = jtag_libusb_get_device(devh); const struct libusb_interface *inter; @@ -210,6 +210,8 @@ int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh, continue; epdesc = &interdesc->endpoint[k]; + if (trans_type > 0 && (epdesc->bmAttributes & 0x3) != trans_type) + continue; uint8_t epnum = epdesc->bEndpointAddress; bool is_input = epnum & 0x80; diff --git a/src/jtag/drivers/libusb1_common.h b/src/jtag/drivers/libusb1_common.h index fc6526a3..7c73d29a 100644 --- a/src/jtag/drivers/libusb1_common.h +++ b/src/jtag/drivers/libusb1_common.h @@ -69,12 +69,13 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh, * @param bclass `bInterfaceClass` to match, or -1 to ignore this field. * @param subclass `bInterfaceSubClass` to match, or -1 to ignore this field. * @param protocol `bInterfaceProtocol` to match, or -1 to ignore this field. + * @param trans_type `bmAttributes Bits 0..1 Transfer type` to match, or -1 to ignore this field. * @returns Returns ERROR_OK on success, ERROR_FAIL otherwise. */ int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh, unsigned int *usb_read_ep, unsigned int *usb_write_ep, - int bclass, int subclass, int protocol); + int bclass, int subclass, int protocol, int trans_type); int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid); #endif /* OPENOCD_JTAG_DRIVERS_LIBUSB1_COMMON_H */ diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c index bb0ff74d..8f11b4ba 100644 --- a/src/jtag/drivers/openjtag.c +++ b/src/jtag/drivers/openjtag.c @@ -459,7 +459,7 @@ static int openjtag_init_cy7c65215(void) ret = jtag_libusb_choose_interface(usbh, &ep_in, &ep_out, CY7C65215_JTAG_CLASS, - CY7C65215_JTAG_SUBCLASS, -1); + CY7C65215_JTAG_SUBCLASS, -1, LIBUSB_TRANSFER_TYPE_BULK); if (ret != ERROR_OK) { LOG_ERROR("unable to claim JTAG interface"); goto err; diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 699c41fa..0bdcd316 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -216,7 +216,7 @@ struct stlink_usb_handle_s { #define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH 0x01 #define STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE 0x02 -#define STLINK_TRACE_SIZE 1024 +#define STLINK_TRACE_SIZE 4096 #define STLINK_TRACE_MAX_HZ 2000000 #define STLINK_TRACE_MIN_VERSION 13 diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index ad656a84..174c63a3 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -123,6 +123,12 @@ extern struct jtag_interface bcm2835gpio_interface; #if BUILD_CMSIS_DAP == 1 extern struct jtag_interface cmsis_dap_interface; #endif +#if BUILD_KITPROG == 1 +extern struct jtag_interface kitprog_interface; +#endif +#if BUILD_IMX_GPIO == 1 +extern struct jtag_interface imx_gpio_interface; +#endif #endif /* standard drivers */ /** @@ -216,6 +222,12 @@ struct jtag_interface *jtag_interfaces[] = { #if BUILD_CMSIS_DAP == 1 &cmsis_dap_interface, #endif +#if BUILD_KITPROG == 1 + &kitprog_interface, +#endif +#if BUILD_IMX_GPIO == 1 + &imx_gpio_interface, +#endif #endif /* standard drivers */ NULL, }; diff --git a/src/openocd.c b/src/openocd.c index 94fab3a9..83329b51 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -297,8 +297,10 @@ static int openocd_thread(int argc, char *argv[], struct command_context *cmd_ct if (init_at_startup) { ret = command_run_line(cmd_ctx, "init"); - if (ERROR_OK != ret) + if (ERROR_OK != ret) { + server_quit(); return ERROR_FAIL; + } } ret = server_loop(cmd_ctx); diff --git a/src/rtos/linux.c b/src/rtos/linux.c index e5a4efcd..3efaab13 100644 --- a/src/rtos/linux.c +++ b/src/rtos/linux.c @@ -105,11 +105,11 @@ static int linux_os_dummy_update(struct rtos *rtos) return 0; } -static int linux_compute_virt2phys(struct target *target, uint32_t address) +static int linux_compute_virt2phys(struct target *target, target_addr_t address) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; - uint32_t pa = 0; + target_addr_t pa = 0; int retval = target->type->virt2phys(target, address, &pa); if (retval != ERROR_OK) { LOG_ERROR("Cannot compute linux virt2phys translation"); diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index fe007444..483e5510 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -735,22 +735,22 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio stop_reason[0] = '\0'; if (target->debug_reason == DBG_REASON_WATCHPOINT) { enum watchpoint_rw hit_wp_type; - uint32_t hit_wp_address; + target_addr_t hit_wp_address; if (watchpoint_hit(target, &hit_wp_type, &hit_wp_address) == ERROR_OK) { switch (hit_wp_type) { case WPT_WRITE: snprintf(stop_reason, sizeof(stop_reason), - "watch:%08" PRIx32 ";", hit_wp_address); + "watch:%08" TARGET_PRIxADDR ";", hit_wp_address); break; case WPT_READ: snprintf(stop_reason, sizeof(stop_reason), - "rwatch:%08" PRIx32 ";", hit_wp_address); + "rwatch:%08" TARGET_PRIxADDR ";", hit_wp_address); break; case WPT_ACCESS: snprintf(stop_reason, sizeof(stop_reason), - "awatch:%08" PRIx32 ";", hit_wp_address); + "awatch:%08" TARGET_PRIxADDR ";", hit_wp_address); break; default: break; @@ -1355,7 +1355,7 @@ static int gdb_read_memory_packet(struct connection *connection, { struct target *target = get_target_from_connection(connection); char *separator; - uint32_t addr = 0; + uint64_t addr = 0; uint32_t len = 0; uint8_t *buffer; @@ -1366,7 +1366,7 @@ static int gdb_read_memory_packet(struct connection *connection, /* skip command character */ packet++; - addr = strtoul(packet, &separator, 16); + addr = strtoull(packet, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete read memory packet received, dropping connection"); @@ -1383,7 +1383,7 @@ static int gdb_read_memory_packet(struct connection *connection, buffer = malloc(len); - LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len); + LOG_DEBUG("addr: 0x%16.16" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len); retval = target_read_buffer(target, addr, len, buffer); @@ -1426,7 +1426,7 @@ static int gdb_write_memory_packet(struct connection *connection, { struct target *target = get_target_from_connection(connection); char *separator; - uint32_t addr = 0; + uint64_t addr = 0; uint32_t len = 0; uint8_t *buffer; @@ -1435,7 +1435,7 @@ static int gdb_write_memory_packet(struct connection *connection, /* skip command character */ packet++; - addr = strtoul(packet, &separator, 16); + addr = strtoull(packet, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete write memory packet received, dropping connection"); @@ -1451,7 +1451,7 @@ static int gdb_write_memory_packet(struct connection *connection, buffer = malloc(len); - LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len); + LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len); if (unhexify(buffer, separator, len) != len) LOG_ERROR("unable to decode memory packet"); @@ -1473,7 +1473,7 @@ static int gdb_write_memory_binary_packet(struct connection *connection, { struct target *target = get_target_from_connection(connection); char *separator; - uint32_t addr = 0; + uint64_t addr = 0; uint32_t len = 0; int retval = ERROR_OK; @@ -1485,7 +1485,7 @@ static int gdb_write_memory_binary_packet(struct connection *connection, /* skip command character */ packet++; - addr = strtoul(packet, &separator, 16); + addr = strtoull(packet, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete write memory binary packet received, dropping connection"); @@ -1523,7 +1523,7 @@ static int gdb_write_memory_binary_packet(struct connection *connection, } if (len) { - LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len); + LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len); retval = target_write_buffer(target, addr, len, (uint8_t *)separator); if (retval != ERROR_OK) @@ -1547,13 +1547,13 @@ static int gdb_step_continue_packet(struct connection *connection, { struct target *target = get_target_from_connection(connection); int current = 0; - uint32_t address = 0x0; + uint64_t address = 0x0; int retval = ERROR_OK; LOG_DEBUG("-"); if (packet_size > 1) - address = strtoul(packet + 1, NULL, 16); + address = strtoull(packet + 1, NULL, 16); else current = 1; @@ -1577,7 +1577,7 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection, int type; enum breakpoint_type bp_type = BKPT_SOFT /* dummy init to avoid warning */; enum watchpoint_rw wp_type = WPT_READ /* dummy init to avoid warning */; - uint32_t address; + uint64_t address; uint32_t size; char *separator; int retval; @@ -1609,7 +1609,7 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection, return ERROR_SERVER_REMOTE_CLOSED; } - address = strtoul(separator + 1, &separator, 16); + address = strtoull(separator + 1, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete breakpoint/watchpoint packet received, dropping connection"); diff --git a/src/server/server.c b/src/server/server.c index f6889a01..8009d408 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -132,7 +132,9 @@ static int add_connection(struct service *service, struct command_context *cmd_c free(out_file); if (c->fd_out == -1) { LOG_ERROR("could not open %s", service->port); - exit(1); + command_done(c->cmd_ctx); + free(c); + return ERROR_FAIL; } LOG_INFO("accepting '%s' connection from pipe %s", service->name, service->port); @@ -191,7 +193,13 @@ static int remove_connection(struct service *service, struct connection *connect return ERROR_OK; } -/* FIX! make service return error instead of invoking exit() */ +static void free_service(struct service *c) +{ + free(c->name); + free(c->port); + free(c); +} + int add_service(char *name, const char *port, int max_connections, @@ -235,7 +243,8 @@ int add_service(char *name, c->fd = socket(AF_INET, SOCK_STREAM, 0); if (c->fd == -1) { LOG_ERROR("error creating socket: %s", strerror(errno)); - exit(-1); + free_service(c); + return ERROR_FAIL; } setsockopt(c->fd, @@ -255,7 +264,9 @@ int add_service(char *name, hp = gethostbyname(bindto_name); if (hp == NULL) { LOG_ERROR("couldn't resolve bindto address: %s", bindto_name); - exit(-1); + close_socket(c->fd); + free_service(c); + return ERROR_FAIL; } memcpy(&c->sin.sin_addr, hp->h_addr_list[0], hp->h_length); } @@ -263,7 +274,9 @@ int add_service(char *name, if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) { LOG_ERROR("couldn't bind %s to socket: %s", name, strerror(errno)); - exit(-1); + close_socket(c->fd); + free_service(c); + return ERROR_FAIL; } #ifndef _WIN32 @@ -281,7 +294,9 @@ int add_service(char *name, if (listen(c->fd, 1) == -1) { LOG_ERROR("couldn't listen on socket: %s", strerror(errno)); - exit(-1); + close_socket(c->fd); + free_service(c); + return ERROR_FAIL; } } else if (c->type == CONNECTION_STDINOUT) { c->fd = fileno(stdin); @@ -302,13 +317,15 @@ int add_service(char *name, /* we currenty do not support named pipes under win32 * so exit openocd for now */ LOG_ERROR("Named pipes currently not supported under this os"); - exit(1); + free_service(c); + return ERROR_FAIL; #else /* Pipe we're reading from */ c->fd = open(c->port, O_RDONLY | O_NONBLOCK); if (c->fd == -1) { LOG_ERROR("could not open %s", c->port); - exit(1); + free_service(c); + return ERROR_FAIL; } #endif } @@ -425,7 +442,7 @@ int server_loop(struct command_context *command_context) FD_ZERO(&read_fds); else { LOG_ERROR("error during select: %s", strerror(errno)); - exit(-1); + return ERROR_FAIL; } #else @@ -433,7 +450,7 @@ int server_loop(struct command_context *command_context) FD_ZERO(&read_fds); else { LOG_ERROR("error during select: %s", strerror(errno)); - exit(-1); + return ERROR_FAIL; } #endif } @@ -552,7 +569,7 @@ int server_preinit(void) if (WSAStartup(wVersionRequested, &wsaData) != 0) { LOG_ERROR("Failed to Open Winsock"); - exit(-1); + return ERROR_FAIL; } /* register ctrl-c handler */ @@ -570,10 +587,18 @@ int server_preinit(void) int server_init(struct command_context *cmd_ctx) { int ret = tcl_init(); - if (ERROR_OK != ret) + + if (ret != ERROR_OK) return ret; - return telnet_init("Open On-Chip Debugger"); + ret = telnet_init("Open On-Chip Debugger"); + + if (ret != ERROR_OK) { + remove_services(); + return ret; + } + + return ERROR_OK; } int server_quit(void) diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index 0f5769a2..e33188b5 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -573,7 +573,7 @@ static int telnet_input(struct connection *connection) break; default: LOG_ERROR("unknown telnet state"); - exit(-1); + return ERROR_FAIL; } bytes_read--; @@ -624,9 +624,8 @@ int telnet_init(char *banner) return ERROR_OK; } - struct telnet_service *telnet_service; - - telnet_service = malloc(sizeof(struct telnet_service)); + struct telnet_service *telnet_service = + malloc(sizeof(struct telnet_service)); if (!telnet_service) { LOG_ERROR("Failed to allocate telnet service."); @@ -635,13 +634,16 @@ int telnet_init(char *banner) telnet_service->banner = banner; - return add_service("telnet", - telnet_port, - CONNECTION_LIMIT_UNLIMITED, - telnet_new_connection, - telnet_input, - telnet_connection_closed, + int ret = add_service("telnet", telnet_port, CONNECTION_LIMIT_UNLIMITED, + telnet_new_connection, telnet_input, telnet_connection_closed, telnet_service); + + if (ret != ERROR_OK) { + free(telnet_service); + return ret; + } + + return ERROR_OK; } /* daemon configuration command telnet_port */ diff --git a/src/target/Makefile.am b/src/target/Makefile.am index eb0d62ed..597070c4 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -26,6 +26,10 @@ noinst_LTLIBRARIES += %D%/libtarget.la %D%/dsp5680xx.c \ %D%/hla_target.c +if TARGET64 +%C%_libtarget_la_SOURCES +=$(ARMV8_SRC) +endif + TARGET_CORE_SRC = \ %D%/algorithm.c \ %D%/register.c \ @@ -69,6 +73,13 @@ ARMV7_SRC = \ %D%/cortex_a.c \ %D%/ls1_sap.c +ARMV8_SRC = \ + %D%/armv8_dpm.c \ + %D%/armv8_opcodes.c \ + %D%/aarch64.c \ + %D%/armv8.c \ + %D%/armv8_cache.c + ARM_DEBUG_SRC = \ %D%/arm_dpm.c \ %D%/arm_jtag.c \ @@ -85,7 +96,8 @@ ARM_DEBUG_SRC = \ %D%/etb.c \ %D%/etm.c \ $(OOCD_TRACE_FILES) \ - %D%/etm_dummy.c + %D%/etm_dummy.c \ + %D%/arm_cti.c AVR32_SRC = \ %D%/avr32_ap7k.c \ @@ -146,6 +158,10 @@ INTEL_IA32_SRC = \ %D%/armv7a.h \ %D%/armv7m.h \ %D%/armv7m_trace.h \ + %D%/armv8.h \ + %D%/armv8_dpm.h \ + %D%/armv8_opcodes.h \ + %D%/armv8_cache.h \ %D%/avrt.h \ %D%/dsp563xx.h \ %D%/dsp563xx_once.h \ @@ -153,6 +169,7 @@ INTEL_IA32_SRC = \ %D%/breakpoints.h \ %D%/cortex_m.h \ %D%/cortex_a.h \ + %D%/aarch64.h \ %D%/embeddedice.h \ %D%/etb.h \ %D%/etm.h \ @@ -189,6 +206,7 @@ INTEL_IA32_SRC = \ %D%/nds32_v3m.h \ %D%/nds32_aice.h \ %D%/lakemont.h \ - %D%/x86_32_common.h + %D%/x86_32_common.h \ + %D%/arm_cti.h include %D%/openrisc/Makefile.am diff --git a/src/target/aarch64.c b/src/target/aarch64.c new file mode 100644 index 00000000..5e5d3fc7 --- /dev/null +++ b/src/target/aarch64.c @@ -0,0 +1,2452 @@ +/*************************************************************************** + * Copyright (C) 2015 by David Ung * + * * + * 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 "breakpoints.h" +#include "aarch64.h" +#include "register.h" +#include "target_request.h" +#include "target_type.h" +#include "armv8_opcodes.h" +#include "armv8_cache.h" +#include + +enum restart_mode { + RESTART_LAZY, + RESTART_SYNC, +}; + +enum halt_mode { + HALT_LAZY, + HALT_SYNC, +}; + +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); +static int aarch64_set_breakpoint(struct target *target, + struct breakpoint *breakpoint, uint8_t matchmode); +static int aarch64_set_context_breakpoint(struct target *target, + struct breakpoint *breakpoint, uint8_t matchmode); +static int aarch64_set_hybrid_breakpoint(struct target *target, + struct breakpoint *breakpoint); +static int aarch64_unset_breakpoint(struct target *target, + struct breakpoint *breakpoint); +static int aarch64_mmu(struct target *target, int *enabled); +static int aarch64_virt2phys(struct target *target, + target_addr_t virt, target_addr_t *phys); +static int aarch64_read_apb_ap_memory(struct target *target, + uint64_t address, uint32_t size, uint32_t count, uint8_t *buffer); + +#define foreach_smp_target(pos, head) \ + for (pos = head; (pos != NULL); pos = pos->next) + +static int aarch64_restore_system_control_reg(struct target *target) +{ + enum arm_mode target_mode = ARM_MODE_ANY; + int retval = ERROR_OK; + uint32_t instr; + + struct aarch64_common *aarch64 = target_to_aarch64(target); + struct armv8_common *armv8 = target_to_armv8(target); + + if (aarch64->system_control_reg != aarch64->system_control_reg_curr) { + aarch64->system_control_reg_curr = aarch64->system_control_reg; + /* LOG_INFO("cp15_control_reg: %8.8" PRIx32, cortex_v8->cp15_control_reg); */ + + switch (armv8->arm.core_mode) { + case ARMV8_64_EL0T: + target_mode = ARMV8_64_EL1H; + /* fall through */ + case ARMV8_64_EL1T: + case ARMV8_64_EL1H: + instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL1, 0); + break; + case ARMV8_64_EL2T: + case ARMV8_64_EL2H: + instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL2, 0); + break; + case ARMV8_64_EL3H: + case ARMV8_64_EL3T: + instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL3, 0); + break; + + case ARM_MODE_SVC: + case ARM_MODE_ABT: + case ARM_MODE_FIQ: + case ARM_MODE_IRQ: + instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0); + break; + + default: + LOG_INFO("cannot read system control register in this mode"); + return ERROR_FAIL; + } + + if (target_mode != ARM_MODE_ANY) + armv8_dpm_modeswitch(&armv8->dpm, target_mode); + + retval = armv8->dpm.instr_write_data_r0(&armv8->dpm, instr, aarch64->system_control_reg); + if (retval != ERROR_OK) + return retval; + + if (target_mode != ARM_MODE_ANY) + armv8_dpm_modeswitch(&armv8->dpm, ARM_MODE_ANY); + } + + return retval; +} + +/* modify system_control_reg in order to enable or disable mmu for : + * - virt2phys address conversion + * - read or write memory in phys or virt address */ +static int aarch64_mmu_modify(struct target *target, int enable) +{ + struct aarch64_common *aarch64 = target_to_aarch64(target); + struct armv8_common *armv8 = &aarch64->armv8_common; + int retval = ERROR_OK; + uint32_t instr = 0; + + if (enable) { + /* if mmu enabled at target stop and mmu not enable */ + if (!(aarch64->system_control_reg & 0x1U)) { + LOG_ERROR("trying to enable mmu on target stopped with mmu disable"); + return ERROR_FAIL; + } + if (!(aarch64->system_control_reg_curr & 0x1U)) + aarch64->system_control_reg_curr |= 0x1U; + } else { + if (aarch64->system_control_reg_curr & 0x4U) { + /* data cache is active */ + aarch64->system_control_reg_curr &= ~0x4U; + /* flush data cache armv8 function to be called */ + if (armv8->armv8_mmu.armv8_cache.flush_all_data_cache) + armv8->armv8_mmu.armv8_cache.flush_all_data_cache(target); + } + if ((aarch64->system_control_reg_curr & 0x1U)) { + aarch64->system_control_reg_curr &= ~0x1U; + } + } + + switch (armv8->arm.core_mode) { + case ARMV8_64_EL0T: + case ARMV8_64_EL1T: + case ARMV8_64_EL1H: + instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL1, 0); + break; + case ARMV8_64_EL2T: + case ARMV8_64_EL2H: + instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL2, 0); + break; + case ARMV8_64_EL3H: + case ARMV8_64_EL3T: + instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL3, 0); + break; + default: + LOG_DEBUG("unknown cpu state 0x%x" PRIx32, armv8->arm.core_state); + break; + } + + retval = armv8->dpm.instr_write_data_r0(&armv8->dpm, instr, + aarch64->system_control_reg_curr); + return retval; +} + +/* + * Basic debug access, very low level assumes state is saved + */ +static int aarch64_init_debug_access(struct target *target) +{ + struct armv8_common *armv8 = target_to_armv8(target); + int retval; + uint32_t dummy; + + LOG_DEBUG(" "); + + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_OSLAR, 0); + if (retval != ERROR_OK) { + LOG_DEBUG("Examine %s failed", "oslock"); + return retval; + } + + /* Clear Sticky Power Down status Bit in PRSR to enable access to + the registers in the Core Power Domain */ + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_PRSR, &dummy); + if (retval != ERROR_OK) + return retval; + + /* + * Static CTI configuration: + * Channel 0 -> trigger outputs HALT request to PE + * Channel 1 -> trigger outputs Resume request to PE + * Gate all channel trigger events from entering the CTM + */ + + /* Enable CTI */ + retval = arm_cti_enable(armv8->cti, true); + /* By default, gate all channel events to and from the CTM */ + if (retval == ERROR_OK) + retval = arm_cti_write_reg(armv8->cti, CTI_GATE, 0); + /* output halt requests to PE on channel 0 event */ + if (retval == ERROR_OK) + retval = arm_cti_write_reg(armv8->cti, CTI_OUTEN0, CTI_CHNL(0)); + /* output restart requests to PE on channel 1 event */ + if (retval == ERROR_OK) + retval = arm_cti_write_reg(armv8->cti, CTI_OUTEN1, CTI_CHNL(1)); + if (retval != ERROR_OK) + return retval; + + /* Resync breakpoint registers */ + + return ERROR_OK; +} + +/* Write to memory mapped registers directly with no cache or mmu handling */ +static int aarch64_dap_write_memap_register_u32(struct target *target, + uint32_t address, + uint32_t value) +{ + int retval; + struct armv8_common *armv8 = target_to_armv8(target); + + retval = mem_ap_write_atomic_u32(armv8->debug_ap, address, value); + + return retval; +} + +static int aarch64_dpm_setup(struct aarch64_common *a8, uint64_t debug) +{ + struct arm_dpm *dpm = &a8->armv8_common.dpm; + int retval; + + dpm->arm = &a8->armv8_common.arm; + dpm->didr = debug; + + retval = armv8_dpm_setup(dpm); + if (retval == ERROR_OK) + retval = armv8_dpm_initialize(dpm); + + return retval; +} + +static int aarch64_set_dscr_bits(struct target *target, unsigned long bit_mask, unsigned long value) +{ + struct armv8_common *armv8 = target_to_armv8(target); + return armv8_set_dbgreg_bits(armv8, CPUV8_DBG_DSCR, bit_mask, value); +} + +static int aarch64_check_state_one(struct target *target, + uint32_t mask, uint32_t val, int *p_result, uint32_t *p_prsr) +{ + struct armv8_common *armv8 = target_to_armv8(target); + uint32_t prsr; + int retval; + + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_PRSR, &prsr); + if (retval != ERROR_OK) + return retval; + + if (p_prsr) + *p_prsr = prsr; + + if (p_result) + *p_result = (prsr & mask) == (val & mask); + + return ERROR_OK; +} + +static int aarch64_wait_halt_one(struct target *target) +{ + int retval = ERROR_OK; + uint32_t prsr; + + int64_t then = timeval_ms(); + for (;;) { + int halted; + + retval = aarch64_check_state_one(target, PRSR_HALT, PRSR_HALT, &halted, &prsr); + if (retval != ERROR_OK || halted) + break; + + if (timeval_ms() > then + 1000) { + retval = ERROR_TARGET_TIMEOUT; + LOG_DEBUG("target %s timeout, prsr=0x%08"PRIx32, target_name(target), prsr); + break; + } + } + return retval; +} + +static int aarch64_prepare_halt_smp(struct target *target, bool exc_target, struct target **p_first) +{ + int retval = ERROR_OK; + struct target_list *head = target->head; + struct target *first = NULL; + + LOG_DEBUG("target %s exc %i", target_name(target), exc_target); + + while (head != NULL) { + struct target *curr = head->target; + struct armv8_common *armv8 = target_to_armv8(curr); + head = head->next; + + if (exc_target && curr == target) + continue; + if (!target_was_examined(curr)) + continue; + if (curr->state != TARGET_RUNNING) + continue; + + /* HACK: mark this target as prepared for halting */ + curr->debug_reason = DBG_REASON_DBGRQ; + + /* open the gate for channel 0 to let HALT requests pass to the CTM */ + retval = arm_cti_ungate_channel(armv8->cti, 0); + if (retval == ERROR_OK) + retval = aarch64_set_dscr_bits(curr, DSCR_HDE, DSCR_HDE); + if (retval != ERROR_OK) + break; + + LOG_DEBUG("target %s prepared", target_name(curr)); + + if (first == NULL) + first = curr; + } + + if (p_first) { + if (exc_target && first) + *p_first = first; + else + *p_first = target; + } + + return retval; +} + +static int aarch64_halt_one(struct target *target, enum halt_mode mode) +{ + int retval = ERROR_OK; + struct armv8_common *armv8 = target_to_armv8(target); + + LOG_DEBUG("%s", target_name(target)); + + /* allow Halting Debug Mode */ + retval = aarch64_set_dscr_bits(target, DSCR_HDE, DSCR_HDE); + if (retval != ERROR_OK) + return retval; + + /* trigger an event on channel 0, this outputs a halt request to the PE */ + retval = arm_cti_pulse_channel(armv8->cti, 0); + if (retval != ERROR_OK) + return retval; + + if (mode == HALT_SYNC) { + retval = aarch64_wait_halt_one(target); + if (retval != ERROR_OK) { + if (retval == ERROR_TARGET_TIMEOUT) + LOG_ERROR("Timeout waiting for target %s halt", target_name(target)); + return retval; + } + } + + return ERROR_OK; +} + +static int aarch64_halt_smp(struct target *target, bool exc_target) +{ + struct target *next = target; + int retval; + + /* prepare halt on all PEs of the group */ + retval = aarch64_prepare_halt_smp(target, exc_target, &next); + + if (exc_target && next == target) + return retval; + + /* halt the target PE */ + if (retval == ERROR_OK) + retval = aarch64_halt_one(next, HALT_LAZY); + + if (retval != ERROR_OK) + return retval; + + /* wait for all PEs to halt */ + int64_t then = timeval_ms(); + for (;;) { + bool all_halted = true; + struct target_list *head; + struct target *curr; + + foreach_smp_target(head, target->head) { + int halted; + + curr = head->target; + + if (!target_was_examined(curr)) + continue; + + retval = aarch64_check_state_one(curr, PRSR_HALT, PRSR_HALT, &halted, NULL); + if (retval != ERROR_OK || !halted) { + all_halted = false; + break; + } + } + + if (all_halted) + break; + + if (timeval_ms() > then + 1000) { + retval = ERROR_TARGET_TIMEOUT; + break; + } + + /* + * HACK: on Hi6220 there are 8 cores organized in 2 clusters + * and it looks like the CTI's are not connected by a common + * trigger matrix. It seems that we need to halt one core in each + * cluster explicitly. So if we find that a core has not halted + * yet, we trigger an explicit halt for the second cluster. + */ + retval = aarch64_halt_one(curr, HALT_LAZY); + if (retval != ERROR_OK) + break; + } + + return retval; +} + +static int update_halt_gdb(struct target *target, enum target_debug_reason debug_reason) +{ + struct target *gdb_target = NULL; + struct target_list *head; + struct target *curr; + + if (debug_reason == DBG_REASON_NOTHALTED) { + LOG_INFO("Halting remaining targets in SMP group"); + aarch64_halt_smp(target, true); + } + + /* poll all targets in the group, but skip the target that serves GDB */ + foreach_smp_target(head, target->head) { + curr = head->target; + /* skip calling context */ + if (curr == target) + continue; + if (!target_was_examined(curr)) + continue; + /* skip targets that were already halted */ + if (curr->state == TARGET_HALTED) + continue; + /* remember the gdb_service->target */ + if (curr->gdb_service != NULL) + gdb_target = curr->gdb_service->target; + /* skip it */ + if (curr == gdb_target) + continue; + + /* avoid recursion in aarch64_poll() */ + curr->smp = 0; + aarch64_poll(curr); + curr->smp = 1; + } + + /* after all targets were updated, poll the gdb serving target */ + if (gdb_target != NULL && gdb_target != target) + aarch64_poll(gdb_target); + + return ERROR_OK; +} + +/* + * Aarch64 Run control + */ + +static int aarch64_poll(struct target *target) +{ + enum target_state prev_target_state; + int retval = ERROR_OK; + int halted; + + retval = aarch64_check_state_one(target, + PRSR_HALT, PRSR_HALT, &halted, NULL); + if (retval != ERROR_OK) + return retval; + + if (halted) { + prev_target_state = target->state; + if (prev_target_state != TARGET_HALTED) { + enum target_debug_reason debug_reason = target->debug_reason; + + /* We have a halting debug event */ + target->state = TARGET_HALTED; + LOG_DEBUG("Target %s halted", target_name(target)); + retval = aarch64_debug_entry(target); + if (retval != ERROR_OK) + return retval; + + if (target->smp) + update_halt_gdb(target, debug_reason); + + switch (prev_target_state) { + case TARGET_RUNNING: + case TARGET_UNKNOWN: + case TARGET_RESET: + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + break; + case TARGET_DEBUG_RUNNING: + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); + break; + default: + break; + } + } + } else + target->state = TARGET_RUNNING; + + return retval; +} + +static int aarch64_halt(struct target *target) +{ + if (target->smp) + return aarch64_halt_smp(target, false); + + return aarch64_halt_one(target, HALT_SYNC); +} + +static int aarch64_restore_one(struct target *target, int current, + uint64_t *address, int handle_breakpoints, int debug_execution) +{ + struct armv8_common *armv8 = target_to_armv8(target); + struct arm *arm = &armv8->arm; + int retval; + uint64_t resume_pc; + + LOG_DEBUG("%s", target_name(target)); + + if (!debug_execution) + target_free_all_working_areas(target); + + /* current = 1: continue on current pc, otherwise continue at
*/ + resume_pc = buf_get_u64(arm->pc->value, 0, 64); + if (!current) + resume_pc = *address; + else + *address = resume_pc; + + /* Make sure that the Armv7 gdb thumb fixups does not + * kill the return address + */ + switch (arm->core_state) { + case ARM_STATE_ARM: + resume_pc &= 0xFFFFFFFC; + break; + case ARM_STATE_AARCH64: + resume_pc &= 0xFFFFFFFFFFFFFFFC; + break; + case ARM_STATE_THUMB: + case ARM_STATE_THUMB_EE: + /* When the return address is loaded into PC + * bit 0 must be 1 to stay in Thumb state + */ + resume_pc |= 0x1; + break; + case ARM_STATE_JAZELLE: + LOG_ERROR("How do I resume into Jazelle state??"); + return ERROR_FAIL; + } + LOG_DEBUG("resume pc = 0x%016" PRIx64, resume_pc); + buf_set_u64(arm->pc->value, 0, 64, resume_pc); + arm->pc->dirty = 1; + arm->pc->valid = 1; + + /* called it now before restoring context because it uses cpu + * register r0 for restoring system control register */ + retval = aarch64_restore_system_control_reg(target); + if (retval == ERROR_OK) + retval = aarch64_restore_context(target, handle_breakpoints); + + return retval; +} + +/** + * prepare single target for restart + * + * + */ +static int aarch64_prepare_restart_one(struct target *target) +{ + struct armv8_common *armv8 = target_to_armv8(target); + int retval; + uint32_t dscr; + uint32_t tmp; + + LOG_DEBUG("%s", target_name(target)); + + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, &dscr); + if (retval != ERROR_OK) + return retval; + + if ((dscr & DSCR_ITE) == 0) + LOG_ERROR("DSCR.ITE must be set before leaving debug!"); + if ((dscr & DSCR_ERR) != 0) + LOG_ERROR("DSCR.ERR must be cleared before leaving debug!"); + + /* acknowledge a pending CTI halt event */ + retval = arm_cti_ack_events(armv8->cti, CTI_TRIG(HALT)); + /* + * open the CTI gate for channel 1 so that the restart events + * get passed along to all PEs. Also close gate for channel 0 + * to isolate the PE from halt events. + */ + if (retval == ERROR_OK) + retval = arm_cti_ungate_channel(armv8->cti, 1); + if (retval == ERROR_OK) + retval = arm_cti_gate_channel(armv8->cti, 0); + + /* make sure that DSCR.HDE is set */ + if (retval == ERROR_OK) { + dscr |= DSCR_HDE; + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, dscr); + } + + /* clear sticky bits in PRSR, SDR is now 0 */ + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_PRSR, &tmp); + + return retval; +} + +static int aarch64_do_restart_one(struct target *target, enum restart_mode mode) +{ + struct armv8_common *armv8 = target_to_armv8(target); + int retval; + + LOG_DEBUG("%s", target_name(target)); + + /* trigger an event on channel 1, generates a restart request to the PE */ + retval = arm_cti_pulse_channel(armv8->cti, 1); + if (retval != ERROR_OK) + return retval; + + if (mode == RESTART_SYNC) { + int64_t then = timeval_ms(); + for (;;) { + int resumed; + /* + * if PRSR.SDR is set now, the target did restart, even + * if it's now already halted again (e.g. due to breakpoint) + */ + retval = aarch64_check_state_one(target, + PRSR_SDR, PRSR_SDR, &resumed, NULL); + if (retval != ERROR_OK || resumed) + break; + + if (timeval_ms() > then + 1000) { + LOG_ERROR("%s: Timeout waiting for resume"PRIx32, target_name(target)); + retval = ERROR_TARGET_TIMEOUT; + break; + } + } + } + + if (retval != ERROR_OK) + return retval; + + target->debug_reason = DBG_REASON_NOTHALTED; + target->state = TARGET_RUNNING; + + return ERROR_OK; +} + +static int aarch64_restart_one(struct target *target, enum restart_mode mode) +{ + int retval; + + LOG_DEBUG("%s", target_name(target)); + + retval = aarch64_prepare_restart_one(target); + if (retval == ERROR_OK) + retval = aarch64_do_restart_one(target, mode); + + return retval; +} + +/* + * prepare all but the current target for restart + */ +static int aarch64_prep_restart_smp(struct target *target, int handle_breakpoints, struct target **p_first) +{ + int retval = ERROR_OK; + struct target_list *head; + struct target *first = NULL; + uint64_t address; + + foreach_smp_target(head, target->head) { + struct target *curr = head->target; + + /* skip calling target */ + if (curr == target) + continue; + if (!target_was_examined(curr)) + continue; + if (curr->state != TARGET_HALTED) + continue; + + /* resume at current address, not in step mode */ + retval = aarch64_restore_one(curr, 1, &address, handle_breakpoints, 0); + if (retval == ERROR_OK) + retval = aarch64_prepare_restart_one(curr); + if (retval != ERROR_OK) { + LOG_ERROR("failed to restore target %s", target_name(curr)); + break; + } + /* remember the first valid target in the group */ + if (first == NULL) + first = curr; + } + + if (p_first) + *p_first = first; + + return retval; +} + + +static int aarch64_step_restart_smp(struct target *target) +{ + int retval = ERROR_OK; + struct target_list *head; + struct target *first = NULL; + + LOG_DEBUG("%s", target_name(target)); + + retval = aarch64_prep_restart_smp(target, 0, &first); + if (retval != ERROR_OK) + return retval; + + if (first != NULL) + retval = aarch64_do_restart_one(first, RESTART_LAZY); + if (retval != ERROR_OK) { + LOG_DEBUG("error restarting target %s", target_name(first)); + return retval; + } + + int64_t then = timeval_ms(); + for (;;) { + struct target *curr = target; + bool all_resumed = true; + + foreach_smp_target(head, target->head) { + uint32_t prsr; + int resumed; + + curr = head->target; + + if (curr == target) + continue; + + retval = aarch64_check_state_one(curr, + PRSR_SDR, PRSR_SDR, &resumed, &prsr); + if (retval != ERROR_OK || (!resumed && (prsr & PRSR_HALT))) { + all_resumed = false; + break; + } + + if (curr->state != TARGET_RUNNING) { + curr->state = TARGET_RUNNING; + curr->debug_reason = DBG_REASON_NOTHALTED; + target_call_event_callbacks(curr, TARGET_EVENT_RESUMED); + } + } + + if (all_resumed) + break; + + if (timeval_ms() > then + 1000) { + LOG_ERROR("%s: timeout waiting for target resume", __func__); + retval = ERROR_TARGET_TIMEOUT; + break; + } + /* + * HACK: on Hi6220 there are 8 cores organized in 2 clusters + * and it looks like the CTI's are not connected by a common + * trigger matrix. It seems that we need to halt one core in each + * cluster explicitly. So if we find that a core has not halted + * yet, we trigger an explicit resume for the second cluster. + */ + retval = aarch64_do_restart_one(curr, RESTART_LAZY); + if (retval != ERROR_OK) + break; +} + + return retval; +} + +static int aarch64_resume(struct target *target, int current, + target_addr_t address, int handle_breakpoints, int debug_execution) +{ + int retval = 0; + uint64_t addr = address; + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + /* + * If this target is part of a SMP group, prepare the others + * targets for resuming. This involves restoring the complete + * target register context and setting up CTI gates to accept + * resume events from the trigger matrix. + */ + if (target->smp) { + retval = aarch64_prep_restart_smp(target, handle_breakpoints, NULL); + if (retval != ERROR_OK) + return retval; + } + + /* all targets prepared, restore and restart the current target */ + retval = aarch64_restore_one(target, current, &addr, handle_breakpoints, + debug_execution); + if (retval == ERROR_OK) + retval = aarch64_restart_one(target, RESTART_SYNC); + if (retval != ERROR_OK) + return retval; + + if (target->smp) { + int64_t then = timeval_ms(); + for (;;) { + struct target *curr = target; + struct target_list *head; + bool all_resumed = true; + + foreach_smp_target(head, target->head) { + uint32_t prsr; + int resumed; + + curr = head->target; + if (curr == target) + continue; + if (!target_was_examined(curr)) + continue; + + retval = aarch64_check_state_one(curr, + PRSR_SDR, PRSR_SDR, &resumed, &prsr); + if (retval != ERROR_OK || (!resumed && (prsr & PRSR_HALT))) { + all_resumed = false; + break; + } + + if (curr->state != TARGET_RUNNING) { + curr->state = TARGET_RUNNING; + curr->debug_reason = DBG_REASON_NOTHALTED; + target_call_event_callbacks(curr, TARGET_EVENT_RESUMED); + } + } + + if (all_resumed) + break; + + if (timeval_ms() > then + 1000) { + LOG_ERROR("%s: timeout waiting for target %s to resume", __func__, target_name(curr)); + retval = ERROR_TARGET_TIMEOUT; + break; + } + + /* + * HACK: on Hi6220 there are 8 cores organized in 2 clusters + * and it looks like the CTI's are not connected by a common + * trigger matrix. It seems that we need to halt one core in each + * cluster explicitly. So if we find that a core has not halted + * yet, we trigger an explicit resume for the second cluster. + */ + retval = aarch64_do_restart_one(curr, RESTART_LAZY); + if (retval != ERROR_OK) + break; + } + } + + if (retval != ERROR_OK) + return retval; + + target->debug_reason = DBG_REASON_NOTHALTED; + + if (!debug_execution) { + target->state = TARGET_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + LOG_DEBUG("target resumed at 0x%" PRIx64, addr); + } else { + target->state = TARGET_DEBUG_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); + LOG_DEBUG("target debug resumed at 0x%" PRIx64, addr); + } + + return ERROR_OK; +} + +static int aarch64_debug_entry(struct target *target) +{ + int retval = ERROR_OK; + struct armv8_common *armv8 = target_to_armv8(target); + struct arm_dpm *dpm = &armv8->dpm; + enum arm_state core_state; + uint32_t dscr; + + /* make sure to clear all sticky errors */ + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DRCR, DRCR_CSE); + if (retval == ERROR_OK) + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, &dscr); + if (retval == ERROR_OK) + retval = arm_cti_ack_events(armv8->cti, CTI_TRIG(HALT)); + + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("%s dscr = 0x%08" PRIx32, target_name(target), dscr); + + dpm->dscr = dscr; + core_state = armv8_dpm_get_core_state(dpm); + armv8_select_opcodes(armv8, core_state == ARM_STATE_AARCH64); + armv8_select_reg_access(armv8, core_state == ARM_STATE_AARCH64); + + /* close the CTI gate for all events */ + if (retval == ERROR_OK) + retval = arm_cti_write_reg(armv8->cti, CTI_GATE, 0); + /* discard async exceptions */ + if (retval == ERROR_OK) + retval = dpm->instr_cpsr_sync(dpm); + if (retval != ERROR_OK) + return retval; + + /* Examine debug reason */ + armv8_dpm_report_dscr(dpm, dscr); + + /* save address of instruction that triggered the watchpoint? */ + if (target->debug_reason == DBG_REASON_WATCHPOINT) { + uint32_t tmp; + uint64_t wfar = 0; + + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_WFAR1, + &tmp); + if (retval != ERROR_OK) + return retval; + wfar = tmp; + wfar = (wfar << 32); + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_WFAR0, + &tmp); + if (retval != ERROR_OK) + return retval; + wfar |= tmp; + armv8_dpm_report_wfar(&armv8->dpm, wfar); + } + + retval = armv8_dpm_read_current_registers(&armv8->dpm); + + if (retval == ERROR_OK && armv8->post_debug_entry) + retval = armv8->post_debug_entry(target); + + return retval; +} + +static int aarch64_post_debug_entry(struct target *target) +{ + struct aarch64_common *aarch64 = target_to_aarch64(target); + struct armv8_common *armv8 = &aarch64->armv8_common; + int retval; + enum arm_mode target_mode = ARM_MODE_ANY; + uint32_t instr; + + switch (armv8->arm.core_mode) { + case ARMV8_64_EL0T: + target_mode = ARMV8_64_EL1H; + /* fall through */ + case ARMV8_64_EL1T: + case ARMV8_64_EL1H: + instr = ARMV8_MRS(SYSTEM_SCTLR_EL1, 0); + break; + case ARMV8_64_EL2T: + case ARMV8_64_EL2H: + instr = ARMV8_MRS(SYSTEM_SCTLR_EL2, 0); + break; + case ARMV8_64_EL3H: + case ARMV8_64_EL3T: + instr = ARMV8_MRS(SYSTEM_SCTLR_EL3, 0); + break; + + case ARM_MODE_SVC: + case ARM_MODE_ABT: + case ARM_MODE_FIQ: + case ARM_MODE_IRQ: + instr = ARMV4_5_MRC(15, 0, 0, 1, 0, 0); + break; + + default: + LOG_INFO("cannot read system control register in this mode"); + return ERROR_FAIL; + } + + if (target_mode != ARM_MODE_ANY) + armv8_dpm_modeswitch(&armv8->dpm, target_mode); + + retval = armv8->dpm.instr_read_data_r0(&armv8->dpm, instr, &aarch64->system_control_reg); + if (retval != ERROR_OK) + return retval; + + if (target_mode != ARM_MODE_ANY) + armv8_dpm_modeswitch(&armv8->dpm, ARM_MODE_ANY); + + LOG_DEBUG("System_register: %8.8" PRIx32, aarch64->system_control_reg); + aarch64->system_control_reg_curr = aarch64->system_control_reg; + + if (armv8->armv8_mmu.armv8_cache.info == -1) { + armv8_identify_cache(armv8); + armv8_read_mpidr(armv8); + } + + armv8->armv8_mmu.mmu_enabled = + (aarch64->system_control_reg & 0x1U) ? 1 : 0; + armv8->armv8_mmu.armv8_cache.d_u_cache_enabled = + (aarch64->system_control_reg & 0x4U) ? 1 : 0; + armv8->armv8_mmu.armv8_cache.i_cache_enabled = + (aarch64->system_control_reg & 0x1000U) ? 1 : 0; + return ERROR_OK; +} + +/* + * single-step a target + */ +static int aarch64_step(struct target *target, int current, target_addr_t address, + int handle_breakpoints) +{ + struct armv8_common *armv8 = target_to_armv8(target); + int saved_retval = ERROR_OK; + int retval; + uint32_t edecr; + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_EDECR, &edecr); + /* make sure EDECR.SS is not set when restoring the register */ + + if (retval == ERROR_OK) { + edecr &= ~0x4; + /* set EDECR.SS to enter hardware step mode */ + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_EDECR, (edecr|0x4)); + } + /* disable interrupts while stepping */ + if (retval == ERROR_OK) + retval = aarch64_set_dscr_bits(target, 0x3 << 22, 0x3 << 22); + /* bail out if stepping setup has failed */ + if (retval != ERROR_OK) + return retval; + + if (target->smp && !handle_breakpoints) { + /* + * isolate current target so that it doesn't get resumed + * together with the others + */ + retval = arm_cti_gate_channel(armv8->cti, 1); + /* resume all other targets in the group */ + if (retval == ERROR_OK) + retval = aarch64_step_restart_smp(target); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to restart non-stepping targets in SMP group"); + return retval; + } + LOG_DEBUG("Restarted all non-stepping targets in SMP group"); + } + + /* all other targets running, restore and restart the current target */ + retval = aarch64_restore_one(target, current, &address, 0, 0); + if (retval == ERROR_OK) + retval = aarch64_restart_one(target, RESTART_LAZY); + + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("target step-resumed at 0x%" PRIx64, address); + if (!handle_breakpoints) + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + + int64_t then = timeval_ms(); + for (;;) { + int stepped; + uint32_t prsr; + + retval = aarch64_check_state_one(target, + PRSR_SDR|PRSR_HALT, PRSR_SDR|PRSR_HALT, &stepped, &prsr); + if (retval != ERROR_OK || stepped) + break; + + if (timeval_ms() > then + 1000) { + LOG_ERROR("timeout waiting for target %s halt after step", + target_name(target)); + retval = ERROR_TARGET_TIMEOUT; + break; + } + } + + if (retval == ERROR_TARGET_TIMEOUT) + saved_retval = retval; + + /* restore EDECR */ + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_EDECR, edecr); + if (retval != ERROR_OK) + return retval; + + /* restore interrupts */ + retval = aarch64_set_dscr_bits(target, 0x3 << 22, 0); + if (retval != ERROR_OK) + return ERROR_OK; + + if (saved_retval != ERROR_OK) + return saved_retval; + + return aarch64_poll(target); +} + +static int aarch64_restore_context(struct target *target, bool bpwp) +{ + struct armv8_common *armv8 = target_to_armv8(target); + struct arm *arm = &armv8->arm; + + int retval; + + LOG_DEBUG("%s", target_name(target)); + + if (armv8->pre_restore_context) + armv8->pre_restore_context(target); + + retval = armv8_dpm_write_dirty_registers(&armv8->dpm, bpwp); + if (retval == ERROR_OK) { + /* registers are now invalid */ + register_cache_invalidate(arm->core_cache); + register_cache_invalidate(arm->core_cache->next); + } + + return retval; +} + +/* + * Cortex-A8 Breakpoint and watchpoint functions + */ + +/* Setup hardware Breakpoint Register Pair */ +static int aarch64_set_breakpoint(struct target *target, + struct breakpoint *breakpoint, uint8_t matchmode) +{ + int retval; + int brp_i = 0; + uint32_t control; + uint8_t byte_addr_select = 0x0F; + struct aarch64_common *aarch64 = target_to_aarch64(target); + struct armv8_common *armv8 = &aarch64->armv8_common; + struct aarch64_brp *brp_list = aarch64->brp_list; + + if (breakpoint->set) { + LOG_WARNING("breakpoint already set"); + return ERROR_OK; + } + + if (breakpoint->type == BKPT_HARD) { + int64_t bpt_value; + while (brp_list[brp_i].used && (brp_i < aarch64->brp_num)) + brp_i++; + if (brp_i >= aarch64->brp_num) { + LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + breakpoint->set = brp_i + 1; + if (breakpoint->length == 2) + byte_addr_select = (3 << (breakpoint->address & 0x02)); + control = ((matchmode & 0x7) << 20) + | (1 << 13) + | (byte_addr_select << 5) + | (3 << 1) | 1; + brp_list[brp_i].used = 1; + brp_list[brp_i].value = breakpoint->address & 0xFFFFFFFFFFFFFFFC; + brp_list[brp_i].control = control; + bpt_value = brp_list[brp_i].value; + + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].BRPn, + (uint32_t)(bpt_value & 0xFFFFFFFF)); + if (retval != ERROR_OK) + return retval; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].BRPn, + (uint32_t)(bpt_value >> 32)); + if (retval != ERROR_OK) + return retval; + + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].BRPn, + brp_list[brp_i].control); + if (retval != ERROR_OK) + return retval; + LOG_DEBUG("brp %i control 0x%0" PRIx32 " value 0x%" TARGET_PRIxADDR, brp_i, + brp_list[brp_i].control, + brp_list[brp_i].value); + + } else if (breakpoint->type == BKPT_SOFT) { + uint8_t code[4]; + + buf_set_u32(code, 0, 32, armv8_opcode(armv8, ARMV8_OPC_HLT)); + retval = target_read_memory(target, + breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->length, 1, + breakpoint->orig_instr); + if (retval != ERROR_OK) + return retval; + + armv8_cache_d_inner_flush_virt(armv8, + breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->length); + + retval = target_write_memory(target, + breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->length, 1, code); + if (retval != ERROR_OK) + return retval; + + armv8_cache_d_inner_flush_virt(armv8, + breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->length); + + armv8_cache_i_inner_inval_virt(armv8, + breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->length); + + breakpoint->set = 0x11; /* Any nice value but 0 */ + } + + /* Ensure that halting debug mode is enable */ + retval = aarch64_set_dscr_bits(target, DSCR_HDE, DSCR_HDE); + if (retval != ERROR_OK) { + LOG_DEBUG("Failed to set DSCR.HDE"); + return retval; + } + + return ERROR_OK; +} + +static int aarch64_set_context_breakpoint(struct target *target, + struct breakpoint *breakpoint, uint8_t matchmode) +{ + int retval = ERROR_FAIL; + int brp_i = 0; + uint32_t control; + uint8_t byte_addr_select = 0x0F; + struct aarch64_common *aarch64 = target_to_aarch64(target); + struct armv8_common *armv8 = &aarch64->armv8_common; + struct aarch64_brp *brp_list = aarch64->brp_list; + + if (breakpoint->set) { + LOG_WARNING("breakpoint already set"); + return retval; + } + /*check available context BRPs*/ + while ((brp_list[brp_i].used || + (brp_list[brp_i].type != BRP_CONTEXT)) && (brp_i < aarch64->brp_num)) + brp_i++; + + if (brp_i >= aarch64->brp_num) { + LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); + return ERROR_FAIL; + } + + breakpoint->set = brp_i + 1; + control = ((matchmode & 0x7) << 20) + | (1 << 13) + | (byte_addr_select << 5) + | (3 << 1) | 1; + brp_list[brp_i].used = 1; + brp_list[brp_i].value = (breakpoint->asid); + brp_list[brp_i].control = control; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].BRPn, + brp_list[brp_i].value); + if (retval != ERROR_OK) + return retval; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].BRPn, + brp_list[brp_i].control); + if (retval != ERROR_OK) + return retval; + LOG_DEBUG("brp %i control 0x%0" PRIx32 " value 0x%" TARGET_PRIxADDR, brp_i, + brp_list[brp_i].control, + brp_list[brp_i].value); + return ERROR_OK; + +} + +static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint) +{ + int retval = ERROR_FAIL; + int brp_1 = 0; /* holds the contextID pair */ + int brp_2 = 0; /* holds the IVA pair */ + uint32_t control_CTX, control_IVA; + uint8_t CTX_byte_addr_select = 0x0F; + uint8_t IVA_byte_addr_select = 0x0F; + uint8_t CTX_machmode = 0x03; + uint8_t IVA_machmode = 0x01; + struct aarch64_common *aarch64 = target_to_aarch64(target); + struct armv8_common *armv8 = &aarch64->armv8_common; + struct aarch64_brp *brp_list = aarch64->brp_list; + + if (breakpoint->set) { + LOG_WARNING("breakpoint already set"); + return retval; + } + /*check available context BRPs*/ + while ((brp_list[brp_1].used || + (brp_list[brp_1].type != BRP_CONTEXT)) && (brp_1 < aarch64->brp_num)) + brp_1++; + + printf("brp(CTX) found num: %d\n", brp_1); + if (brp_1 >= aarch64->brp_num) { + LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); + return ERROR_FAIL; + } + + while ((brp_list[brp_2].used || + (brp_list[brp_2].type != BRP_NORMAL)) && (brp_2 < aarch64->brp_num)) + brp_2++; + + printf("brp(IVA) found num: %d\n", brp_2); + if (brp_2 >= aarch64->brp_num) { + LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); + return ERROR_FAIL; + } + + breakpoint->set = brp_1 + 1; + breakpoint->linked_BRP = brp_2; + control_CTX = ((CTX_machmode & 0x7) << 20) + | (brp_2 << 16) + | (0 << 14) + | (CTX_byte_addr_select << 5) + | (3 << 1) | 1; + brp_list[brp_1].used = 1; + brp_list[brp_1].value = (breakpoint->asid); + brp_list[brp_1].control = control_CTX; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_1].BRPn, + brp_list[brp_1].value); + if (retval != ERROR_OK) + return retval; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_1].BRPn, + brp_list[brp_1].control); + if (retval != ERROR_OK) + return retval; + + control_IVA = ((IVA_machmode & 0x7) << 20) + | (brp_1 << 16) + | (1 << 13) + | (IVA_byte_addr_select << 5) + | (3 << 1) | 1; + brp_list[brp_2].used = 1; + brp_list[brp_2].value = breakpoint->address & 0xFFFFFFFFFFFFFFFC; + brp_list[brp_2].control = control_IVA; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_2].BRPn, + brp_list[brp_2].value & 0xFFFFFFFF); + if (retval != ERROR_OK) + return retval; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_2].BRPn, + brp_list[brp_2].value >> 32); + if (retval != ERROR_OK) + return retval; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_2].BRPn, + brp_list[brp_2].control); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *breakpoint) +{ + int retval; + struct aarch64_common *aarch64 = target_to_aarch64(target); + struct armv8_common *armv8 = &aarch64->armv8_common; + struct aarch64_brp *brp_list = aarch64->brp_list; + + if (!breakpoint->set) { + LOG_WARNING("breakpoint not set"); + return ERROR_OK; + } + + if (breakpoint->type == BKPT_HARD) { + if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { + int brp_i = breakpoint->set - 1; + int brp_j = breakpoint->linked_BRP; + if ((brp_i < 0) || (brp_i >= aarch64->brp_num)) { + LOG_DEBUG("Invalid BRP number in breakpoint"); + return ERROR_OK; + } + LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%" TARGET_PRIxADDR, brp_i, + brp_list[brp_i].control, brp_list[brp_i].value); + brp_list[brp_i].used = 0; + brp_list[brp_i].value = 0; + brp_list[brp_i].control = 0; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].BRPn, + brp_list[brp_i].control); + if (retval != ERROR_OK) + return retval; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].BRPn, + (uint32_t)brp_list[brp_i].value); + if (retval != ERROR_OK) + return retval; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].BRPn, + (uint32_t)brp_list[brp_i].value); + if (retval != ERROR_OK) + return retval; + if ((brp_j < 0) || (brp_j >= aarch64->brp_num)) { + LOG_DEBUG("Invalid BRP number in breakpoint"); + return ERROR_OK; + } + LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx64, brp_j, + brp_list[brp_j].control, brp_list[brp_j].value); + brp_list[brp_j].used = 0; + brp_list[brp_j].value = 0; + brp_list[brp_j].control = 0; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_j].BRPn, + brp_list[brp_j].control); + if (retval != ERROR_OK) + return retval; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_j].BRPn, + (uint32_t)brp_list[brp_j].value); + if (retval != ERROR_OK) + return retval; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_j].BRPn, + (uint32_t)brp_list[brp_j].value); + if (retval != ERROR_OK) + return retval; + + breakpoint->linked_BRP = 0; + breakpoint->set = 0; + return ERROR_OK; + + } else { + int brp_i = breakpoint->set - 1; + if ((brp_i < 0) || (brp_i >= aarch64->brp_num)) { + LOG_DEBUG("Invalid BRP number in breakpoint"); + return ERROR_OK; + } + LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx64, brp_i, + brp_list[brp_i].control, brp_list[brp_i].value); + brp_list[brp_i].used = 0; + brp_list[brp_i].value = 0; + brp_list[brp_i].control = 0; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].BRPn, + brp_list[brp_i].control); + if (retval != ERROR_OK) + return retval; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].BRPn, + brp_list[brp_i].value); + if (retval != ERROR_OK) + return retval; + + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].BRPn, + (uint32_t)brp_list[brp_i].value); + if (retval != ERROR_OK) + return retval; + breakpoint->set = 0; + return ERROR_OK; + } + } else { + /* restore original instruction (kept in target endianness) */ + + armv8_cache_d_inner_flush_virt(armv8, + breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->length); + + if (breakpoint->length == 4) { + retval = target_write_memory(target, + breakpoint->address & 0xFFFFFFFFFFFFFFFE, + 4, 1, breakpoint->orig_instr); + if (retval != ERROR_OK) + return retval; + } else { + retval = target_write_memory(target, + breakpoint->address & 0xFFFFFFFFFFFFFFFE, + 2, 1, breakpoint->orig_instr); + if (retval != ERROR_OK) + return retval; + } + + armv8_cache_d_inner_flush_virt(armv8, + breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->length); + + armv8_cache_i_inner_inval_virt(armv8, + breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->length); + } + breakpoint->set = 0; + + return ERROR_OK; +} + +static int aarch64_add_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + struct aarch64_common *aarch64 = target_to_aarch64(target); + + if ((breakpoint->type == BKPT_HARD) && (aarch64->brp_num_available < 1)) { + LOG_INFO("no hardware breakpoint available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + if (breakpoint->type == BKPT_HARD) + aarch64->brp_num_available--; + + return aarch64_set_breakpoint(target, breakpoint, 0x00); /* Exact match */ +} + +static int aarch64_add_context_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + struct aarch64_common *aarch64 = target_to_aarch64(target); + + if ((breakpoint->type == BKPT_HARD) && (aarch64->brp_num_available < 1)) { + LOG_INFO("no hardware breakpoint available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + if (breakpoint->type == BKPT_HARD) + aarch64->brp_num_available--; + + return aarch64_set_context_breakpoint(target, breakpoint, 0x02); /* asid match */ +} + +static int aarch64_add_hybrid_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + struct aarch64_common *aarch64 = target_to_aarch64(target); + + if ((breakpoint->type == BKPT_HARD) && (aarch64->brp_num_available < 1)) { + LOG_INFO("no hardware breakpoint available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + if (breakpoint->type == BKPT_HARD) + aarch64->brp_num_available--; + + return aarch64_set_hybrid_breakpoint(target, breakpoint); /* ??? */ +} + + +static int aarch64_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) +{ + struct aarch64_common *aarch64 = target_to_aarch64(target); + +#if 0 +/* It is perfectly possible to remove breakpoints while the target is running */ + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } +#endif + + if (breakpoint->set) { + aarch64_unset_breakpoint(target, breakpoint); + if (breakpoint->type == BKPT_HARD) + aarch64->brp_num_available++; + } + + return ERROR_OK; +} + +/* + * Cortex-A8 Reset functions + */ + +static int aarch64_assert_reset(struct target *target) +{ + struct armv8_common *armv8 = target_to_armv8(target); + + LOG_DEBUG(" "); + + /* FIXME when halt is requested, make it work somehow... */ + + /* Issue some kind of warm reset. */ + if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) + target_handle_event(target, TARGET_EVENT_RESET_ASSERT); + else if (jtag_get_reset_config() & RESET_HAS_SRST) { + /* REVISIT handle "pulls" cases, if there's + * hardware that needs them to work. + */ + jtag_add_reset(0, 1); + } else { + LOG_ERROR("%s: how to reset?", target_name(target)); + return ERROR_FAIL; + } + + /* registers are now invalid */ + if (target_was_examined(target)) { + register_cache_invalidate(armv8->arm.core_cache); + register_cache_invalidate(armv8->arm.core_cache->next); + } + + target->state = TARGET_RESET; + + return ERROR_OK; +} + +static int aarch64_deassert_reset(struct target *target) +{ + int retval; + + LOG_DEBUG(" "); + + /* be certain SRST is off */ + jtag_add_reset(0, 0); + + if (!target_was_examined(target)) + return ERROR_OK; + + retval = aarch64_poll(target); + if (retval != ERROR_OK) + return retval; + + if (target->reset_halt) { + if (target->state != TARGET_HALTED) { + LOG_WARNING("%s: ran after reset and before halt ...", + target_name(target)); + retval = target_halt(target); + if (retval != ERROR_OK) + return retval; + } + } + + return aarch64_init_debug_access(target); +} + +static int aarch64_write_apb_ap_memory(struct target *target, + uint64_t address, uint32_t size, + uint32_t count, const uint8_t *buffer) +{ + /* write memory through APB-AP */ + int retval = ERROR_COMMAND_SYNTAX_ERROR; + struct armv8_common *armv8 = target_to_armv8(target); + struct arm_dpm *dpm = &armv8->dpm; + struct arm *arm = &armv8->arm; + int total_bytes = count * size; + int total_u32; + int start_byte = address & 0x3; + int end_byte = (address + total_bytes) & 0x3; + struct reg *reg; + uint32_t dscr; + uint8_t *tmp_buff = NULL; + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + total_u32 = DIV_ROUND_UP((address & 3) + total_bytes, 4); + + /* Mark register R0 as dirty, as it will be used + * for transferring the data. + * It will be restored automatically when exiting + * debug mode + */ + reg = armv8_reg_current(arm, 1); + reg->dirty = true; + + reg = armv8_reg_current(arm, 0); + reg->dirty = true; + + /* This algorithm comes from DDI0487A.g, chapter J9.1 */ + + /* The algorithm only copies 32 bit words, so the buffer + * should be expanded to include the words at either end. + * The first and last words will be read first to avoid + * corruption if needed. + */ + tmp_buff = malloc(total_u32 * 4); + + if ((start_byte != 0) && (total_u32 > 1)) { + /* First bytes not aligned - read the 32 bit word to avoid corrupting + * the other bytes in the word. + */ + retval = aarch64_read_apb_ap_memory(target, (address & ~0x3), 4, 1, tmp_buff); + if (retval != ERROR_OK) + goto error_free_buff_w; + } + + /* If end of write is not aligned, or the write is less than 4 bytes */ + if ((end_byte != 0) || + ((total_u32 == 1) && (total_bytes != 4))) { + + /* Read the last word to avoid corruption during 32 bit write */ + int mem_offset = (total_u32-1) * 4; + retval = aarch64_read_apb_ap_memory(target, (address & ~0x3) + mem_offset, 4, 1, &tmp_buff[mem_offset]); + if (retval != ERROR_OK) + goto error_free_buff_w; + } + + /* Copy the write buffer over the top of the temporary buffer */ + memcpy(&tmp_buff[start_byte], buffer, total_bytes); + + /* We now have a 32 bit aligned buffer that can be written */ + + /* Read DSCR */ + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, &dscr); + if (retval != ERROR_OK) + goto error_free_buff_w; + + /* Set Normal access mode */ + dscr = (dscr & ~DSCR_MA); + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, dscr); + + if (arm->core_state == ARM_STATE_AARCH64) { + /* Write X0 with value 'address' using write procedure */ + /* Step 1.a+b - Write the address for read access into DBGDTR_EL0 */ + /* Step 1.c - Copy value from DTR to R0 using instruction mrs DBGDTR_EL0, x0 */ + retval = dpm->instr_write_data_dcc_64(dpm, + ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, 0), address & ~0x3ULL); + } else { + /* Write R0 with value 'address' using write procedure */ + /* Step 1.a+b - Write the address for read access into DBGDTRRX */ + /* Step 1.c - Copy value from DTR to R0 using instruction mrc DBGDTRTXint, r0 */ + dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, 0, 0, 5, 0), address & ~0x3ULL); + + } + /* Step 1.d - Change DCC to memory mode */ + dscr = dscr | DSCR_MA; + retval += mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, dscr); + if (retval != ERROR_OK) + goto error_unset_dtr_w; + + + /* Step 2.a - Do the write */ + retval = mem_ap_write_buf_noincr(armv8->debug_ap, + tmp_buff, 4, total_u32, armv8->debug_base + CPUV8_DBG_DTRRX); + if (retval != ERROR_OK) + goto error_unset_dtr_w; + + /* Step 3.a - Switch DTR mode back to Normal mode */ + dscr = (dscr & ~DSCR_MA); + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, dscr); + if (retval != ERROR_OK) + goto error_unset_dtr_w; + + /* Check for sticky abort flags in the DSCR */ + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, &dscr); + if (retval != ERROR_OK) + goto error_free_buff_w; + + dpm->dscr = dscr; + 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); + goto error_free_buff_w; + } + + /* Done */ + free(tmp_buff); + return ERROR_OK; + +error_unset_dtr_w: + /* Unset DTR mode */ + mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, &dscr); + dscr = (dscr & ~DSCR_MA); + mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, dscr); +error_free_buff_w: + LOG_ERROR("error"); + free(tmp_buff); + return ERROR_FAIL; +} + +static int aarch64_read_apb_ap_memory(struct target *target, + target_addr_t address, uint32_t size, + uint32_t count, uint8_t *buffer) +{ + /* read memory through APB-AP */ + int retval = ERROR_COMMAND_SYNTAX_ERROR; + struct armv8_common *armv8 = target_to_armv8(target); + struct arm_dpm *dpm = &armv8->dpm; + struct arm *arm = &armv8->arm; + int total_bytes = count * size; + int total_u32; + int start_byte = address & 0x3; + int end_byte = (address + total_bytes) & 0x3; + struct reg *reg; + uint32_t dscr; + uint8_t *tmp_buff = NULL; + uint8_t *u8buf_ptr; + uint32_t value; + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + total_u32 = DIV_ROUND_UP((address & 3) + total_bytes, 4); + /* Mark register X0, X1 as dirty, as it will be used + * for transferring the data. + * It will be restored automatically when exiting + * debug mode + */ + reg = armv8_reg_current(arm, 1); + reg->dirty = true; + + reg = armv8_reg_current(arm, 0); + reg->dirty = true; + + /* Read DSCR */ + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, &dscr); + + /* This algorithm comes from DDI0487A.g, chapter J9.1 */ + + /* Set Normal access mode */ + dscr = (dscr & ~DSCR_MA); + retval += mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, dscr); + + if (arm->core_state == ARM_STATE_AARCH64) { + /* Write X0 with value 'address' using write procedure */ + /* Step 1.a+b - Write the address for read access into DBGDTR_EL0 */ + /* Step 1.c - Copy value from DTR to R0 using instruction mrs DBGDTR_EL0, x0 */ + retval += dpm->instr_write_data_dcc_64(dpm, + ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, 0), address & ~0x3ULL); + /* Step 1.d - Dummy operation to ensure EDSCR.Txfull == 1 */ + retval += dpm->instr_execute(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0, 0)); + /* Step 1.e - Change DCC to memory mode */ + dscr = dscr | DSCR_MA; + retval += mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, dscr); + /* Step 1.f - read DBGDTRTX and discard the value */ + retval += mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DTRTX, &value); + } else { + /* Write R0 with value 'address' using write procedure */ + /* Step 1.a+b - Write the address for read access into DBGDTRRXint */ + /* Step 1.c - Copy value from DTR to R0 using instruction mrc DBGDTRTXint, r0 */ + retval += dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, 0, 0, 5, 0), address & ~0x3ULL); + /* Step 1.d - Dummy operation to ensure EDSCR.Txfull == 1 */ + retval += dpm->instr_execute(dpm, ARMV4_5_MCR(14, 0, 0, 0, 5, 0)); + /* Step 1.e - Change DCC to memory mode */ + dscr = dscr | DSCR_MA; + retval += mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, dscr); + /* Step 1.f - read DBGDTRTX and discard the value */ + retval += mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DTRTX, &value); + + } + if (retval != ERROR_OK) + goto error_unset_dtr_r; + + /* Optimize the read as much as we can, either way we read in a single pass */ + if ((start_byte) || (end_byte)) { + /* The algorithm only copies 32 bit words, so the buffer + * should be expanded to include the words at either end. + * The first and last words will be read into a temp buffer + * to avoid corruption + */ + tmp_buff = malloc(total_u32 * 4); + if (!tmp_buff) + goto error_unset_dtr_r; + + /* use the tmp buffer to read the entire data */ + u8buf_ptr = tmp_buff; + } else + /* address and read length are aligned so read directly into the passed buffer */ + u8buf_ptr = buffer; + + /* Read the data - Each read of the DTRTX register causes the instruction to be reissued + * Abort flags are sticky, so can be read at end of transactions + * + * This data is read in aligned to 32 bit boundary. + */ + + /* Step 2.a - Loop n-1 times, each read of DBGDTRTX reads the data from [X0] and + * increments X0 by 4. */ + retval = mem_ap_read_buf_noincr(armv8->debug_ap, u8buf_ptr, 4, total_u32-1, + armv8->debug_base + CPUV8_DBG_DTRTX); + if (retval != ERROR_OK) + goto error_unset_dtr_r; + + /* Step 3.a - set DTR access mode back to Normal mode */ + dscr = (dscr & ~DSCR_MA); + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, dscr); + if (retval != ERROR_OK) + goto error_free_buff_r; + + /* Step 3.b - read DBGDTRTX for the final value */ + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DTRTX, &value); + memcpy(u8buf_ptr + (total_u32-1) * 4, &value, 4); + + /* Check for sticky abort flags in the DSCR */ + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, &dscr); + if (retval != ERROR_OK) + goto error_free_buff_r; + + dpm->dscr = dscr; + + 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); + goto error_free_buff_r; + } + + /* check if we need to copy aligned data by applying any shift necessary */ + if (tmp_buff) { + memcpy(buffer, tmp_buff + start_byte, total_bytes); + free(tmp_buff); + } + + /* Done */ + return ERROR_OK; + +error_unset_dtr_r: + /* Unset DTR mode */ + mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, &dscr); + dscr = (dscr & ~DSCR_MA); + mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, dscr); +error_free_buff_r: + LOG_ERROR("error"); + free(tmp_buff); + return ERROR_FAIL; +} + +static int aarch64_read_phys_memory(struct target *target, + target_addr_t address, uint32_t size, + uint32_t count, uint8_t *buffer) +{ + int retval = ERROR_COMMAND_SYNTAX_ERROR; + + if (count && buffer) { + /* read memory through APB-AP */ + retval = aarch64_mmu_modify(target, 0); + if (retval != ERROR_OK) + return retval; + retval = aarch64_read_apb_ap_memory(target, address, size, count, buffer); + } + return retval; +} + +static int aarch64_read_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + int mmu_enabled = 0; + int retval; + + /* determine if MMU was enabled on target stop */ + retval = aarch64_mmu(target, &mmu_enabled); + if (retval != ERROR_OK) + return retval; + + if (mmu_enabled) { + /* enable MMU as we could have disabled it for phys access */ + retval = aarch64_mmu_modify(target, 1); + if (retval != ERROR_OK) + return retval; + } + return aarch64_read_apb_ap_memory(target, address, size, count, buffer); +} + +static int aarch64_write_phys_memory(struct target *target, + target_addr_t address, uint32_t size, + uint32_t count, const uint8_t *buffer) +{ + int retval = ERROR_COMMAND_SYNTAX_ERROR; + + if (count && buffer) { + /* write memory through APB-AP */ + retval = aarch64_mmu_modify(target, 0); + if (retval != ERROR_OK) + return retval; + return aarch64_write_apb_ap_memory(target, address, size, count, buffer); + } + + return retval; +} + +static int aarch64_write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + int mmu_enabled = 0; + int retval; + + /* determine if MMU was enabled on target stop */ + retval = aarch64_mmu(target, &mmu_enabled); + if (retval != ERROR_OK) + return retval; + + if (mmu_enabled) { + /* enable MMU as we could have disabled it for phys access */ + retval = aarch64_mmu_modify(target, 1); + if (retval != ERROR_OK) + return retval; + } + return aarch64_write_apb_ap_memory(target, address, size, count, buffer); +} + +static int aarch64_handle_target_request(void *priv) +{ + struct target *target = priv; + struct armv8_common *armv8 = target_to_armv8(target); + int retval; + + if (!target_was_examined(target)) + return ERROR_OK; + if (!target->dbg_msg_enabled) + return ERROR_OK; + + if (target->state == TARGET_RUNNING) { + uint32_t request; + uint32_t dscr; + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, &dscr); + + /* check if we have data */ + while ((dscr & DSCR_DTR_TX_FULL) && (retval == ERROR_OK)) { + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DTRTX, &request); + if (retval == ERROR_OK) { + target_request(target, request); + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, &dscr); + } + } + } + + return ERROR_OK; +} + +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; + int i; + int retval = ERROR_OK; + uint64_t debug, ttypr; + uint32_t cpuid; + uint32_t tmp0, tmp1; + 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) { + LOG_ERROR("Could not find APB-AP for debug access"); + return retval; + } + + retval = mem_ap_init(armv8->debug_ap); + if (retval != ERROR_OK) { + LOG_ERROR("Could not initialize the APB-AP"); + return retval; + } + + armv8->debug_ap->memaccess_tck = 10; + + if (!target->dbgbase_set) { + uint32_t dbgbase; + /* Get ROM Table base */ + uint32_t apid; + int32_t coreidx = target->coreid; + retval = dap_get_debugbase(armv8->debug_ap, &dbgbase, &apid); + if (retval != ERROR_OK) + return retval; + /* Lookup 0x15 -- Processor DAP */ + retval = dap_lookup_cs_component(armv8->debug_ap, dbgbase, 0x15, + &armv8->debug_base, &coreidx); + if (retval != ERROR_OK) + return retval; + LOG_DEBUG("Detected core %" PRId32 " dbgbase: %08" PRIx32 + " apid: %08" PRIx32, coreidx, armv8->debug_base, apid); + } else + armv8->debug_base = target->dbgbase; + + uint32_t prsr; + int64_t then = timeval_ms(); + do { + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_PRSR, &prsr); + if (retval == ERROR_OK) { + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_PRCR, PRCR_COREPURQ|PRCR_CORENPDRQ); + if (retval != ERROR_OK) { + LOG_DEBUG("write to PRCR failed"); + break; + } + } + + if (timeval_ms() > then + 1000) { + retval = ERROR_TARGET_TIMEOUT; + break; + } + + } while ((prsr & PRSR_PU) == 0); + + if (retval != ERROR_OK) { + LOG_ERROR("target %s: failed to set power state of the core.", target_name(target)); + return retval; + } + + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_OSLAR, 0); + if (retval != ERROR_OK) { + LOG_DEBUG("Examine %s failed", "oslock"); + return retval; + } + + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_MAINID0, &cpuid); + if (retval != ERROR_OK) { + LOG_DEBUG("Examine %s failed", "CPUID"); + return retval; + } + + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_MEMFEATURE0, &tmp0); + retval += mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_MEMFEATURE0 + 4, &tmp1); + if (retval != ERROR_OK) { + LOG_DEBUG("Examine %s failed", "Memory Model Type"); + return retval; + } + ttypr |= tmp1; + ttypr = (ttypr << 32) | tmp0; + + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DBGFEATURE0, &tmp0); + retval += mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DBGFEATURE0 + 4, &tmp1); + if (retval != ERROR_OK) { + LOG_DEBUG("Examine %s failed", "ID_AA64DFR0_EL1"); + return retval; + } + debug |= tmp1; + debug = (debug << 32) | tmp0; + + LOG_DEBUG("cpuid = 0x%08" PRIx32, cpuid); + 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) + return ERROR_FAIL; + + retval = aarch64_dpm_setup(aarch64, debug); + if (retval != ERROR_OK) + return retval; + + /* Setup Breakpoint Register Pairs */ + aarch64->brp_num = (uint32_t)((debug >> 12) & 0x0F) + 1; + aarch64->brp_num_context = (uint32_t)((debug >> 28) & 0x0F) + 1; + aarch64->brp_num_available = aarch64->brp_num; + aarch64->brp_list = calloc(aarch64->brp_num, sizeof(struct aarch64_brp)); + for (i = 0; i < aarch64->brp_num; i++) { + aarch64->brp_list[i].used = 0; + if (i < (aarch64->brp_num-aarch64->brp_num_context)) + aarch64->brp_list[i].type = BRP_NORMAL; + else + aarch64->brp_list[i].type = BRP_CONTEXT; + aarch64->brp_list[i].value = 0; + aarch64->brp_list[i].control = 0; + aarch64->brp_list[i].BRPn = i; + } + + LOG_DEBUG("Configured %i hw breakpoints", aarch64->brp_num); + + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + + target_set_examined(target); + return ERROR_OK; +} + +static int aarch64_examine(struct target *target) +{ + int retval = ERROR_OK; + + /* don't re-probe hardware after each reset */ + if (!target_was_examined(target)) + retval = aarch64_examine_first(target); + + /* Configure core debug access */ + if (retval == ERROR_OK) + retval = aarch64_init_debug_access(target); + + return retval; +} + +/* + * Cortex-A8 target creation and initialization + */ + +static int aarch64_init_target(struct command_context *cmd_ctx, + struct target *target) +{ + /* examine_first() does a bunch of this */ + return ERROR_OK; +} + +static int aarch64_init_arch_info(struct target *target, + struct aarch64_common *aarch64, struct jtag_tap *tap) +{ + 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; + + /* register arch-specific functions */ + armv8->examine_debug_reason = NULL; + armv8->post_debug_entry = aarch64_post_debug_entry; + armv8->pre_restore_context = NULL; + armv8->armv8_mmu.read_physical_memory = aarch64_read_phys_memory; + + armv8_init_arch_info(target, armv8); + target_register_timer_callback(aarch64_handle_target_request, 1, 1, target); + + return ERROR_OK; +} + +static int aarch64_target_create(struct target *target, Jim_Interp *interp) +{ + struct aarch64_common *aarch64 = calloc(1, sizeof(struct aarch64_common)); + + return aarch64_init_arch_info(target, aarch64, target->tap); +} + +static int aarch64_mmu(struct target *target, int *enabled) +{ + if (target->state != TARGET_HALTED) { + LOG_ERROR("%s: target %s not halted", __func__, target_name(target)); + return ERROR_TARGET_INVALID; + } + + *enabled = target_to_aarch64(target)->armv8_common.armv8_mmu.mmu_enabled; + return ERROR_OK; +} + +static int aarch64_virt2phys(struct target *target, target_addr_t virt, + target_addr_t *phys) +{ + return armv8_mmu_translate_va_pa(target, virt, phys, 1); +} + +COMMAND_HANDLER(aarch64_handle_cache_info_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct armv8_common *armv8 = target_to_armv8(target); + + return armv8_handle_cache_info_command(CMD_CTX, + &armv8->armv8_mmu.armv8_cache); +} + + +COMMAND_HANDLER(aarch64_handle_dbginit_command) +{ + struct target *target = get_current_target(CMD_CTX); + if (!target_was_examined(target)) { + LOG_ERROR("target not examined yet"); + return ERROR_FAIL; + } + + return aarch64_init_debug_access(target); +} +COMMAND_HANDLER(aarch64_handle_smp_off_command) +{ + struct target *target = get_current_target(CMD_CTX); + /* check target is an smp target */ + struct target_list *head; + struct target *curr; + head = target->head; + target->smp = 0; + if (head != (struct target_list *)NULL) { + while (head != (struct target_list *)NULL) { + curr = head->target; + curr->smp = 0; + head = head->next; + } + /* fixes the target display to the debugger */ + target->gdb_service->target = target; + } + return ERROR_OK; +} + +COMMAND_HANDLER(aarch64_handle_smp_on_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct target_list *head; + struct target *curr; + head = target->head; + if (head != (struct target_list *)NULL) { + target->smp = 1; + while (head != (struct target_list *)NULL) { + curr = head->target; + curr->smp = 1; + head = head->next; + } + } + return ERROR_OK; +} + +static const struct command_registration aarch64_exec_command_handlers[] = { + { + .name = "cache_info", + .handler = aarch64_handle_cache_info_command, + .mode = COMMAND_EXEC, + .help = "display information about target caches", + .usage = "", + }, + { + .name = "dbginit", + .handler = aarch64_handle_dbginit_command, + .mode = COMMAND_EXEC, + .help = "Initialize core debug", + .usage = "", + }, + { .name = "smp_off", + .handler = aarch64_handle_smp_off_command, + .mode = COMMAND_EXEC, + .help = "Stop smp handling", + .usage = "", + }, + { + .name = "smp_on", + .handler = aarch64_handle_smp_on_command, + .mode = COMMAND_EXEC, + .help = "Restart smp handling", + .usage = "", + }, + + COMMAND_REGISTRATION_DONE +}; +static const struct command_registration aarch64_command_handlers[] = { + { + .chain = armv8_command_handlers, + }, + { + .name = "aarch64", + .mode = COMMAND_ANY, + .help = "Aarch64 command group", + .usage = "", + .chain = aarch64_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct target_type aarch64_target = { + .name = "aarch64", + + .poll = aarch64_poll, + .arch_state = armv8_arch_state, + + .halt = aarch64_halt, + .resume = aarch64_resume, + .step = aarch64_step, + + .assert_reset = aarch64_assert_reset, + .deassert_reset = aarch64_deassert_reset, + + /* REVISIT allow exporting VFP3 registers ... */ + .get_gdb_reg_list = armv8_get_gdb_reg_list, + + .read_memory = aarch64_read_memory, + .write_memory = aarch64_write_memory, + + .add_breakpoint = aarch64_add_breakpoint, + .add_context_breakpoint = aarch64_add_context_breakpoint, + .add_hybrid_breakpoint = aarch64_add_hybrid_breakpoint, + .remove_breakpoint = aarch64_remove_breakpoint, + .add_watchpoint = NULL, + .remove_watchpoint = NULL, + + .commands = aarch64_command_handlers, + .target_create = aarch64_target_create, + .init_target = aarch64_init_target, + .examine = aarch64_examine, + + .read_phys_memory = aarch64_read_phys_memory, + .write_phys_memory = aarch64_write_phys_memory, + .mmu = aarch64_mmu, + .virt2phys = aarch64_virt2phys, +}; diff --git a/src/target/aarch64.h b/src/target/aarch64.h new file mode 100644 index 00000000..c9ec02db --- /dev/null +++ b/src/target/aarch64.h @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright (C) 2015 by David Ung * + * * + * 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., * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_AARCH64_H +#define OPENOCD_TARGET_AARCH64_H + +#include "armv8.h" + +#define AARCH64_COMMON_MAGIC 0x411fc082 + +#define CPUDBG_CPUID 0xD00 +#define CPUDBG_CTYPR 0xD04 +#define CPUDBG_TTYPR 0xD0C +#define ID_AA64PFR0_EL1 0xD20 +#define ID_AA64DFR0_EL1 0xD28 +#define CPUDBG_LOCKACCESS 0xFB0 +#define CPUDBG_LOCKSTATUS 0xFB4 + +#define BRP_NORMAL 0 +#define BRP_CONTEXT 1 + +#define AARCH64_PADDRDBG_CPU_SHIFT 13 + +struct aarch64_brp { + int used; + int type; + target_addr_t value; + uint32_t control; + uint8_t BRPn; +}; + +struct aarch64_common { + int common_magic; + + /* Context information */ + uint32_t system_control_reg; + uint32_t system_control_reg_curr; + + /* Breakpoint register pairs */ + int brp_num_context; + int brp_num; + int brp_num_available; + struct aarch64_brp *brp_list; + + struct armv8_common armv8_common; +}; + +static inline struct aarch64_common * +target_to_aarch64(struct target *target) +{ + return container_of(target->arch_info, struct aarch64_common, armv8_common.arm); +} + +#endif /* OPENOCD_TARGET_AARCH64_H */ diff --git a/src/target/algorithm.h b/src/target/algorithm.h index d216a824..8894241c 100644 --- a/src/target/algorithm.h +++ b/src/target/algorithm.h @@ -26,7 +26,7 @@ enum param_direction { }; struct mem_param { - uint32_t address; + target_addr_t address; uint32_t size; uint8_t *value; enum param_direction direction; diff --git a/src/target/arm.h b/src/target/arm.h index 226dd656..d63ead21 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -66,6 +66,15 @@ enum arm_mode { ARM_MODE_USER_THREAD = 1, ARM_MODE_HANDLER = 2, + /* shift left 4 bits for armv8 64 */ + ARMV8_64_EL0T = 0x0F, + ARMV8_64_EL1T = 0x4F, + ARMV8_64_EL1H = 0x5F, + ARMV8_64_EL2T = 0x8F, + ARMV8_64_EL2H = 0x9F, + ARMV8_64_EL3T = 0xCF, + ARMV8_64_EL3H = 0xDF, + ARM_MODE_ANY = -1 }; @@ -78,6 +87,7 @@ enum arm_state { ARM_STATE_THUMB, ARM_STATE_JAZELLE, ARM_STATE_THUMB_EE, + ARM_STATE_AARCH64, }; #define ARM_COMMON_MAGIC 0x0A450A45 @@ -213,10 +223,11 @@ struct arm_reg { enum arm_mode mode; struct target *target; struct arm *arm; - uint8_t value[4]; + uint8_t value[8]; }; struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm); +struct reg_cache *armv8_build_reg_cache(struct target *target); extern const struct command_registration arm_command_handlers[]; @@ -224,6 +235,9 @@ int arm_arch_state(struct target *target); int arm_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); +int armv8_get_gdb_reg_list(struct target *target, + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class); int arm_init_arch_info(struct target *target, struct arm *arm); @@ -231,7 +245,7 @@ int arm_init_arch_info(struct target *target, struct arm *arm); int armv4_5_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - uint32_t entry_point, uint32_t exit_point, + target_addr_t entry_point, target_addr_t exit_point, int timeout_ms, void *arch_info); int armv4_5_run_algorithm_inner(struct target *target, int num_mem_params, struct mem_param *mem_params, @@ -242,12 +256,13 @@ int armv4_5_run_algorithm_inner(struct target *target, int timeout_ms, void *arch_info)); int arm_checksum_memory(struct target *target, - uint32_t address, uint32_t count, uint32_t *checksum); + target_addr_t address, uint32_t count, uint32_t *checksum); int arm_blank_check_memory(struct target *target, - uint32_t address, uint32_t count, uint32_t *blank, uint8_t erased_value); + target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value); void arm_set_cpsr(struct arm *arm, uint32_t cpsr); struct reg *arm_reg_current(struct arm *arm, unsigned regnum); +struct reg *armv8_reg_current(struct arm *arm, unsigned regnum); extern struct reg arm_gdb_dummy_fp_reg; extern struct reg arm_gdb_dummy_fps_reg; diff --git a/src/target/arm11.c b/src/target/arm11.c index cbe4d450..13fbd207 100644 --- a/src/target/arm11.c +++ b/src/target/arm11.c @@ -42,7 +42,7 @@ static int arm11_step(struct target *target, int current, - uint32_t address, int handle_breakpoints); + target_addr_t address, int handle_breakpoints); /** Check and if necessary take control of the system @@ -449,7 +449,7 @@ static uint32_t arm11_nextpc(struct arm11_common *arm11, int current, uint32_t a } static int arm11_resume(struct target *target, int current, - uint32_t address, int handle_breakpoints, int debug_execution) + target_addr_t address, int handle_breakpoints, int debug_execution) { /* LOG_DEBUG("current %d address %08x handle_breakpoints %d debug_execution %d", */ /* current, address, handle_breakpoints, debug_execution); */ @@ -467,7 +467,7 @@ static int arm11_resume(struct target *target, int current, address = arm11_nextpc(arm11, current, address); - LOG_DEBUG("RESUME PC %08" PRIx32 "%s", address, !current ? "!" : ""); + LOG_DEBUG("RESUME PC %08" TARGET_PRIxADDR "%s", address, !current ? "!" : ""); /* clear breakpoints/watchpoints and VCR*/ CHECK_RETVAL(arm11_sc7_clear_vbw(arm11)); @@ -481,7 +481,7 @@ static int arm11_resume(struct target *target, int current, for (bp = target->breakpoints; bp; bp = bp->next) { if (bp->address == address) { - LOG_DEBUG("must step over %08" PRIx32 "", bp->address); + LOG_DEBUG("must step over %08" TARGET_PRIxADDR "", bp->address); arm11_step(target, 1, 0, 0); break; } @@ -507,7 +507,7 @@ static int arm11_resume(struct target *target, int current, CHECK_RETVAL(arm11_sc7_run(arm11, brp, ARRAY_SIZE(brp))); - LOG_DEBUG("Add BP %d at %08" PRIx32, brp_num, + LOG_DEBUG("Add BP %d at %08" TARGET_PRIxADDR, brp_num, bp->address); brp_num++; @@ -557,7 +557,7 @@ static int arm11_resume(struct target *target, int current, } static int arm11_step(struct target *target, int current, - uint32_t address, int handle_breakpoints) + target_addr_t address, int handle_breakpoints) { LOG_DEBUG("target->state: %s", target_state_name(target)); @@ -571,7 +571,7 @@ static int arm11_step(struct target *target, int current, address = arm11_nextpc(arm11, current, address); - LOG_DEBUG("STEP PC %08" PRIx32 "%s", address, !current ? "!" : ""); + LOG_DEBUG("STEP PC %08" TARGET_PRIxADDR "%s", address, !current ? "!" : ""); /** \todo TODO: Thumb not supported here */ @@ -583,13 +583,13 @@ static int arm11_step(struct target *target, int current, /* skip over BKPT */ if ((next_instruction & 0xFFF00070) == 0xe1200070) { address = arm11_nextpc(arm11, 0, address + 4); - LOG_DEBUG("Skipping BKPT %08" PRIx32, address); + LOG_DEBUG("Skipping BKPT %08" TARGET_PRIxADDR, address); } /* skip over Wait for interrupt / Standby * mcr 15, 0, r?, cr7, cr0, {4} */ else if ((next_instruction & 0xFFFF0FFF) == 0xee070f90) { address = arm11_nextpc(arm11, 0, address + 4); - LOG_DEBUG("Skipping WFI %08" PRIx32, address); + LOG_DEBUG("Skipping WFI %08" TARGET_PRIxADDR, address); } /* ignore B to self */ else if ((next_instruction & 0xFEFFFFFF) == 0xeafffffe) @@ -887,7 +887,7 @@ static int arm11_read_memory_inner(struct target *target, } static int arm11_read_memory(struct target *target, - uint32_t address, + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) @@ -1043,7 +1043,7 @@ static int arm11_write_memory_inner(struct target *target, } static int arm11_write_memory(struct target *target, - uint32_t address, uint32_t size, + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { /* pointer increment matters only for multi-unit writes ... diff --git a/src/target/arm720t.c b/src/target/arm720t.c index 3991e19f..bcbfa9df 100644 --- a/src/target/arm720t.c +++ b/src/target/arm720t.c @@ -271,7 +271,7 @@ static int arm720_mmu(struct target *target, int *enabled) } static int arm720_virt2phys(struct target *target, - uint32_t virtual, uint32_t *physical) + target_addr_t virtual, target_addr_t *physical) { uint32_t cb; struct arm720t_common *arm720t = target_to_arm720(target); @@ -286,7 +286,7 @@ static int arm720_virt2phys(struct target *target, } static int arm720t_read_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval; struct arm720t_common *arm720t = target_to_arm720(target); @@ -309,7 +309,7 @@ static int arm720t_read_memory(struct target *target, } static int arm720t_read_phys_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct arm720t_common *arm720t = target_to_arm720(target); @@ -317,7 +317,7 @@ static int arm720t_read_phys_memory(struct target *target, } static int arm720t_write_phys_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct arm720t_common *arm720t = target_to_arm720(target); diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index c1d5c794..7fd1ed9f 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -101,7 +101,8 @@ static void arm7_9_assign_wp(struct arm7_9_common *arm7_9, struct breakpoint *br arm7_9->wp_available--; } else LOG_ERROR("BUG: no hardware comparator available"); - LOG_DEBUG("BPID: %" PRId32 " (0x%08" PRIx32 ") using hw wp: %d", + + LOG_DEBUG("BPID: %" PRId32 " (0x%08" TARGET_PRIxADDR ") using hw wp: %d", breakpoint->unique_id, breakpoint->address, breakpoint->set); @@ -187,7 +188,7 @@ static int arm7_9_set_breakpoint(struct target *target, struct breakpoint *break struct arm7_9_common *arm7_9 = target_to_arm7_9(target); int retval = ERROR_OK; - LOG_DEBUG("BPID: %" PRId32 ", Address: 0x%08" PRIx32 ", Type: %d", + LOG_DEBUG("BPID: %" PRId32 ", Address: 0x%08" TARGET_PRIxADDR ", Type: %d", breakpoint->unique_id, breakpoint->address, breakpoint->type); @@ -244,7 +245,7 @@ static int arm7_9_set_breakpoint(struct target *target, struct breakpoint *break if (retval != ERROR_OK) return retval; if (verify != arm7_9->arm_bkpt) { - LOG_ERROR("Unable to set 32 bit software breakpoint at address %08" PRIx32 + LOG_ERROR("Unable to set 32 bit software breakpoint at address %08" TARGET_PRIxADDR " - check that memory is read/writable", breakpoint->address); return ERROR_OK; } @@ -264,7 +265,7 @@ static int arm7_9_set_breakpoint(struct target *target, struct breakpoint *break if (retval != ERROR_OK) return retval; if (verify != arm7_9->thumb_bkpt) { - LOG_ERROR("Unable to set thumb software breakpoint at address %08" PRIx32 + LOG_ERROR("Unable to set thumb software breakpoint at address %08" TARGET_PRIxADDR " - check that memory is read/writable", breakpoint->address); return ERROR_OK; } @@ -299,7 +300,7 @@ static int arm7_9_unset_breakpoint(struct target *target, struct breakpoint *bre int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); - LOG_DEBUG("BPID: %" PRId32 ", Address: 0x%08" PRIx32, + LOG_DEBUG("BPID: %" PRId32 ", Address: 0x%08" TARGET_PRIxADDR, breakpoint->unique_id, breakpoint->address); @@ -1692,7 +1693,7 @@ static void arm7_9_enable_breakpoints(struct target *target) int arm7_9_resume(struct target *target, int current, - uint32_t address, + target_addr_t address, int handle_breakpoints, int debug_execution) { @@ -1724,7 +1725,7 @@ int arm7_9_resume(struct target *target, breakpoint = breakpoint_find(target, buf_get_u32(arm->pc->value, 0, 32)); if (breakpoint != NULL) { - LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 " (id: %" PRId32, + LOG_DEBUG("unset breakpoint at 0x%8.8" TARGET_PRIxADDR " (id: %" PRId32, breakpoint->address, breakpoint->unique_id); retval = arm7_9_unset_breakpoint(target, breakpoint); @@ -1783,7 +1784,7 @@ int arm7_9_resume(struct target *target, LOG_DEBUG("new PC after step: 0x%8.8" PRIx32, buf_get_u32(arm->pc->value, 0, 32)); - LOG_DEBUG("set breakpoint at 0x%8.8" PRIx32 "", breakpoint->address); + LOG_DEBUG("set breakpoint at 0x%8.8" TARGET_PRIxADDR "", breakpoint->address); retval = arm7_9_set_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; @@ -1894,7 +1895,7 @@ void arm7_9_disable_eice_step(struct target *target) embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE]); } -int arm7_9_step(struct target *target, int current, uint32_t address, int handle_breakpoints) +int arm7_9_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; @@ -2094,7 +2095,7 @@ static int arm7_9_write_core_reg(struct target *target, struct reg *r, } int arm7_9_read_memory(struct target *target, - uint32_t address, + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) @@ -2109,7 +2110,7 @@ int arm7_9_read_memory(struct target *target, int retval; int last_reg = 0; - LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); if (target->state != TARGET_HALTED) { @@ -2247,7 +2248,8 @@ int arm7_9_read_memory(struct target *target, if (((cpsr & 0x1f) == ARM_MODE_ABT) && (arm->core_mode != ARM_MODE_ABT)) { LOG_WARNING( - "memory read caused data abort (address: 0x%8.8" PRIx32 ", size: 0x%" PRIx32 ", count: 0x%" PRIx32 ")", + "memory read caused data abort " + "(address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%" PRIx32 ", count: 0x%" PRIx32 ")", address, size, count); @@ -2263,7 +2265,7 @@ int arm7_9_read_memory(struct target *target, } int arm7_9_write_memory(struct target *target, - uint32_t address, + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) @@ -2460,7 +2462,8 @@ int arm7_9_write_memory(struct target *target, if (((cpsr & 0x1f) == ARM_MODE_ABT) && (arm->core_mode != ARM_MODE_ABT)) { LOG_WARNING( - "memory write caused data abort (address: 0x%8.8" PRIx32 ", size: 0x%" PRIx32 ", count: 0x%" PRIx32 ")", + "memory write caused data abort " + "(address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%" PRIx32 ", count: 0x%" PRIx32 ")", address, size, count); @@ -2476,7 +2479,7 @@ int arm7_9_write_memory(struct target *target, } int arm7_9_write_memory_opt(struct target *target, - uint32_t address, + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) @@ -2576,7 +2579,7 @@ static const uint32_t dcc_code[] = { }; int arm7_9_bulk_write_memory(struct target *target, - uint32_t address, + target_addr_t address, uint32_t count, const uint8_t *buffer) { @@ -2632,7 +2635,7 @@ int arm7_9_bulk_write_memory(struct target *target, uint32_t endaddress = buf_get_u32(reg_params[0].value, 0, 32); if (endaddress != (address + count*4)) { LOG_ERROR( - "DCC write failed, expected end address 0x%08" PRIx32 " got 0x%0" PRIx32 "", + "DCC write failed, expected end address 0x%08" TARGET_PRIxADDR " got 0x%0" PRIx32 "", (address + count*4), endaddress); retval = ERROR_FAIL; diff --git a/src/target/arm7_9_common.h b/src/target/arm7_9_common.h index 044384b2..811f9c59 100644 --- a/src/target/arm7_9_common.h +++ b/src/target/arm7_9_common.h @@ -122,13 +122,13 @@ struct arm7_9_common { * Used as a fallback when bulk writes are unavailable, or for writing data needed to * do the bulk writes. */ - int (*write_memory)(struct target *target, uint32_t address, + int (*write_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); /** * Write target memory in multiples of 4 bytes, optimized for * writing large quantities of data. */ - int (*bulk_write_memory)(struct target *target, uint32_t address, + int (*bulk_write_memory)(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer); }; @@ -155,19 +155,19 @@ int arm7_9_early_halt(struct target *target); int arm7_9_soft_reset_halt(struct target *target); int arm7_9_halt(struct target *target); -int arm7_9_resume(struct target *target, int current, uint32_t address, +int arm7_9_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution); -int arm7_9_step(struct target *target, int current, uint32_t address, +int arm7_9_step(struct target *target, int current, target_addr_t address, int handle_breakpoints); -int arm7_9_read_memory(struct target *target, uint32_t address, +int arm7_9_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); -int arm7_9_write_memory(struct target *target, uint32_t address, +int arm7_9_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); -int arm7_9_write_memory_opt(struct target *target, uint32_t address, +int arm7_9_write_memory_opt(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int arm7_9_write_memory_no_opt(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); -int arm7_9_bulk_write_memory(struct target *target, uint32_t address, +int arm7_9_bulk_write_memory(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer); int arm7_9_run_algorithm(struct target *target, int num_mem_params, diff --git a/src/target/arm920t.c b/src/target/arm920t.c index 2c96d193..7927a2be 100644 --- a/src/target/arm920t.c +++ b/src/target/arm920t.c @@ -553,7 +553,7 @@ static int arm920_mmu(struct target *target, int *enabled) } static int arm920_virt2phys(struct target *target, - uint32_t virt, uint32_t *phys) + target_addr_t virt, target_addr_t *phys) { uint32_t cb; struct arm920t_common *arm920t = target_to_arm920(target); @@ -568,7 +568,7 @@ static int arm920_virt2phys(struct target *target, } /** Reads a buffer, in the specified word size, with current MMU settings. */ -int arm920t_read_memory(struct target *target, uint32_t address, +int arm920t_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval; @@ -580,7 +580,7 @@ int arm920t_read_memory(struct target *target, uint32_t address, static int arm920t_read_phys_memory(struct target *target, - uint32_t address, uint32_t size, + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct arm920t_common *arm920t = target_to_arm920(target); @@ -590,7 +590,7 @@ static int arm920t_read_phys_memory(struct target *target, } static int arm920t_write_phys_memory(struct target *target, - uint32_t address, uint32_t size, + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct arm920t_common *arm920t = target_to_arm920(target); @@ -600,7 +600,7 @@ static int arm920t_write_phys_memory(struct target *target, } /** Writes a buffer, in the specified word size, with current MMU settings. */ -int arm920t_write_memory(struct target *target, uint32_t address, +int arm920t_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval; diff --git a/src/target/arm920t.h b/src/target/arm920t.h index 3401b094..2e3b08ca 100644 --- a/src/target/arm920t.h +++ b/src/target/arm920t.h @@ -55,9 +55,9 @@ struct arm920t_tlb_entry { int arm920t_arch_state(struct target *target); int arm920t_soft_reset_halt(struct target *target); int arm920t_read_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); int arm920t_write_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int arm920t_post_debug_entry(struct target *target); void arm920t_pre_restore_context(struct target *target); int arm920t_get_ttb(struct target *target, uint32_t *result); diff --git a/src/target/arm926ejs.c b/src/target/arm926ejs.c index d7c043e8..58de7785 100644 --- a/src/target/arm926ejs.c +++ b/src/target/arm926ejs.c @@ -594,7 +594,7 @@ int arm926ejs_soft_reset_halt(struct target *target) } /** Writes a buffer, in the specified word size, with current MMU settings. */ -int arm926ejs_write_memory(struct target *target, uint32_t address, +int arm926ejs_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval; @@ -623,7 +623,7 @@ int arm926ejs_write_memory(struct target *target, uint32_t address, return retval; } - uint32_t pa; + target_addr_t pa; retval = target->type->virt2phys(target, address, &pa); if (retval != ERROR_OK) return retval; @@ -655,7 +655,7 @@ int arm926ejs_write_memory(struct target *target, uint32_t address, } static int arm926ejs_write_phys_memory(struct target *target, - uint32_t address, uint32_t size, + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); @@ -665,7 +665,7 @@ static int arm926ejs_write_phys_memory(struct target *target, } static int arm926ejs_read_phys_memory(struct target *target, - uint32_t address, uint32_t size, + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); @@ -736,7 +736,7 @@ COMMAND_HANDLER(arm926ejs_handle_cache_info_command) return armv4_5_handle_cache_info_command(CMD_CTX, &arm926ejs->armv4_5_mmu.armv4_5_cache); } -static int arm926ejs_virt2phys(struct target *target, uint32_t virtual, uint32_t *physical) +static int arm926ejs_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical) { uint32_t cb; struct arm926ejs_common *arm926ejs = target_to_arm926(target); diff --git a/src/target/arm926ejs.h b/src/target/arm926ejs.h index 02b4ef84..d4fd0cb6 100644 --- a/src/target/arm926ejs.h +++ b/src/target/arm926ejs.h @@ -47,7 +47,7 @@ int arm926ejs_init_arch_info(struct target *target, struct arm926ejs_common *arm926ejs, struct jtag_tap *tap); int arm926ejs_arch_state(struct target *target); int arm926ejs_write_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int arm926ejs_soft_reset_halt(struct target *target); extern const struct command_registration arm926ejs_command_handlers[]; diff --git a/src/target/arm946e.c b/src/target/arm946e.c index 5ee31cc2..06c9fc30 100644 --- a/src/target/arm946e.c +++ b/src/target/arm946e.c @@ -487,7 +487,7 @@ uint32_t arm946e_invalidate_icache(struct target *target, uint32_t address, } /** Writes a buffer, in the specified word size, with current MMU settings. */ -int arm946e_write_memory(struct target *target, uint32_t address, +int arm946e_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval; @@ -535,7 +535,7 @@ int arm946e_write_memory(struct target *target, uint32_t address, } -int arm946e_read_memory(struct target *target, uint32_t address, +int arm946e_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval; diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c new file mode 100644 index 00000000..75169b2e --- /dev/null +++ b/src/target/arm_cti.c @@ -0,0 +1,148 @@ +/*************************************************************************** + * 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_cti.h" +#include "target/target.h" +#include "helper/time_support.h" + +struct arm_cti { + uint32_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; + + self->base = base; + self->ap = ap; + return self; +} + +static int arm_cti_mod_reg_bits(struct arm_cti *self, unsigned int reg, uint32_t mask, uint32_t value) +{ + uint32_t tmp; + + /* Read register */ + int retval = mem_ap_read_atomic_u32(self->ap, self->base + reg, &tmp); + if (ERROR_OK != retval) + return retval; + + /* clear bitfield */ + tmp &= ~mask; + /* put new value */ + tmp |= value & mask; + + /* write new value */ + return mem_ap_write_atomic_u32(self->ap, self->base + reg, tmp); +} + +int arm_cti_enable(struct arm_cti *self, bool enable) +{ + uint32_t val = enable ? 1 : 0; + + return mem_ap_write_atomic_u32(self->ap, self->base + CTI_CTR, val); +} + +int arm_cti_ack_events(struct arm_cti *self, uint32_t event) +{ + int retval; + uint32_t tmp; + + retval = mem_ap_write_atomic_u32(self->ap, self->base + CTI_INACK, event); + if (retval == ERROR_OK) { + int64_t then = timeval_ms(); + for (;;) { + retval = mem_ap_read_atomic_u32(self->ap, self->base + CTI_TROUT_STATUS, &tmp); + if (retval != ERROR_OK) + break; + if ((tmp & event) == 0) + break; + if (timeval_ms() > then + 1000) { + LOG_ERROR("timeout waiting for target"); + retval = ERROR_TARGET_TIMEOUT; + break; + } + } + } + + return retval; +} + +int arm_cti_gate_channel(struct arm_cti *self, uint32_t channel) +{ + if (channel > 31) + return ERROR_COMMAND_ARGUMENT_INVALID; + + return arm_cti_mod_reg_bits(self, CTI_GATE, CTI_CHNL(channel), 0); +} + +int arm_cti_ungate_channel(struct arm_cti *self, uint32_t channel) +{ + if (channel > 31) + return ERROR_COMMAND_ARGUMENT_INVALID; + + return arm_cti_mod_reg_bits(self, CTI_GATE, CTI_CHNL(channel), 0xFFFFFFFF); +} + +int arm_cti_write_reg(struct arm_cti *self, unsigned int reg, uint32_t value) +{ + return mem_ap_write_atomic_u32(self->ap, self->base + reg, value); +} + +int arm_cti_read_reg(struct arm_cti *self, unsigned int reg, uint32_t *p_value) +{ + if (p_value == NULL) + return ERROR_COMMAND_ARGUMENT_INVALID; + + return mem_ap_read_atomic_u32(self->ap, self->base + reg, p_value); +} + +int arm_cti_pulse_channel(struct arm_cti *self, uint32_t channel) +{ + if (channel > 31) + return ERROR_COMMAND_ARGUMENT_INVALID; + + return arm_cti_write_reg(self, CTI_APPPULSE, CTI_CHNL(channel)); +} + +int arm_cti_set_channel(struct arm_cti *self, uint32_t channel) +{ + if (channel > 31) + return ERROR_COMMAND_ARGUMENT_INVALID; + + return arm_cti_write_reg(self, CTI_APPSET, CTI_CHNL(channel)); +} + +int arm_cti_clear_channel(struct arm_cti *self, uint32_t channel) +{ + if (channel > 31) + return ERROR_COMMAND_ARGUMENT_INVALID; + + return arm_cti_write_reg(self, CTI_APPCLEAR, CTI_CHNL(channel)); +} diff --git a/src/target/arm_cti.h b/src/target/arm_cti.h new file mode 100644 index 00000000..99724c40 --- /dev/null +++ b/src/target/arm_cti.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * 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., * + * * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ARM_CTI_H +#define OPENOCD_TARGET_ARM_CTI_H + +/*define CTI(cross trigger interface)*/ +#define CTI_CTR 0x0 +#define CTI_INACK 0x10 +#define CTI_APPSET 0x14 +#define CTI_APPCLEAR 0x18 +#define CTI_APPPULSE 0x1C +#define CTI_INEN0 0x20 +#define CTI_INEN1 0x24 +#define CTI_INEN2 0x28 +#define CTI_INEN3 0x2C +#define CTI_INEN4 0x30 +#define CTI_INEN5 0x34 +#define CTI_INEN6 0x38 +#define CTI_INEN7 0x3C +#define CTI_INEN(n) (0x20 + 4 * n) +#define CTI_OUTEN0 0xA0 +#define CTI_OUTEN1 0xA4 +#define CTI_OUTEN2 0xA8 +#define CTI_OUTEN3 0xAC +#define CTI_OUTEN4 0xB0 +#define CTI_OUTEN5 0xB4 +#define CTI_OUTEN6 0xB8 +#define CTI_OUTEN7 0xBC +#define CTI_OUTEN(n) (0xA0 + 4 * n) +#define CTI_TRIN_STATUS 0x130 +#define CTI_TROUT_STATUS 0x134 +#define CTI_CHIN_STATUS 0x138 +#define CTI_CHOU_STATUS 0x13C +#define CTI_GATE 0x140 +#define CTI_UNLOCK 0xFB0 + +#define CTI_CHNL(x) (1 << x) +#define CTI_TRIG_HALT 0 +#define CTI_TRIG_RESUME 1 +#define CTI_TRIG(n) (1 << CTI_TRIG_##n) + +/* forward-declare arm_cti struct */ +struct arm_cti; + +extern struct arm_cti *arm_cti_create(struct adiv5_ap *ap, uint32_t base); +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); +extern int arm_cti_ungate_channel(struct arm_cti *self, uint32_t channel); +extern int arm_cti_write_reg(struct arm_cti *self, unsigned int reg, uint32_t value); +extern int arm_cti_read_reg(struct arm_cti *self, unsigned int reg, uint32_t *value); +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); + +#endif /* OPENOCD_TARGET_ARM_CTI_H */ diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index 62c61755..3e8180c3 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -21,6 +21,7 @@ #include "arm.h" #include "arm_dpm.h" +#include "armv8_dpm.h" #include #include "register.h" #include "breakpoints.h" @@ -165,6 +166,9 @@ static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) /* core-specific ... ? */ LOG_WARNING("Jazelle PC adjustment unknown"); break; + default: + LOG_WARNING("unknow core state"); + break; } break; default: @@ -433,20 +437,20 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) /* cope with special cases */ switch (regnum) { - case 8 ... 12: - /* r8..r12 "anything but FIQ" case; - * we "know" core mode is accurate - * since we haven't changed it yet - */ - if (arm->core_mode == ARM_MODE_FIQ - && ARM_MODE_ANY - != mode) - tmode = ARM_MODE_USR; - break; - case 16: - /* SPSR */ - regnum++; - break; + case 8 ... 12: + /* r8..r12 "anything but FIQ" case; + * we "know" core mode is accurate + * since we haven't changed it yet + */ + if (arm->core_mode == ARM_MODE_FIQ + && ARM_MODE_ANY + != mode) + tmode = ARM_MODE_USR; + break; + case 16: + /* SPSR */ + regnum++; + break; } /* REVISIT error checks */ @@ -460,8 +464,8 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) continue; retval = dpm_write_reg(dpm, - &cache->reg_list[i], - regnum); + &cache->reg_list[i], + regnum); if (retval != ERROR_OK) goto done; } @@ -905,6 +909,7 @@ void arm_dpm_report_wfar(struct arm_dpm *dpm, uint32_t addr) addr -= 4; break; case ARM_STATE_JAZELLE: + case ARM_STATE_AARCH64: /* ?? */ break; } @@ -925,20 +930,16 @@ void arm_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dscr) /* Examine debug reason */ switch (DSCR_ENTRY(dscr)) { - case 6: /* Data abort (v6 only) */ - case 7: /* Prefetch abort (v6 only) */ - /* FALL THROUGH -- assume a v6 core in abort mode */ - case 0: /* HALT request from debugger */ - case 4: /* EDBGRQ */ + case DSCR_ENTRY_HALT_REQ: /* HALT request from debugger */ + case DSCR_ENTRY_EXT_DBG_REQ: /* EDBGRQ */ target->debug_reason = DBG_REASON_DBGRQ; break; - case 1: /* HW breakpoint */ - case 3: /* SW BKPT */ - case 5: /* vector catch */ + case DSCR_ENTRY_BREAKPOINT: /* HW breakpoint */ + case DSCR_ENTRY_BKPT_INSTR: /* vector catch */ target->debug_reason = DBG_REASON_BREAKPOINT; break; - case 2: /* asynch watchpoint */ - case 10:/* precise watchpoint */ + case DSCR_ENTRY_IMPRECISE_WATCHPT: /* asynch watchpoint */ + case DSCR_ENTRY_PRECISE_WATCHPT:/* precise watchpoint */ target->debug_reason = DBG_REASON_WATCHPOINT; break; default: @@ -963,7 +964,7 @@ int arm_dpm_setup(struct arm_dpm *dpm) { struct arm *arm = dpm->arm; struct target *target = arm->target; - struct reg_cache *cache; + struct reg_cache *cache = 0; arm->dpm = dpm; @@ -972,7 +973,6 @@ int arm_dpm_setup(struct arm_dpm *dpm) arm->read_core_reg = arm_dpm_read_core_reg; arm->write_core_reg = arm_dpm_write_core_reg; - /* avoid duplicating the register cache */ if (arm->core_cache == NULL) { cache = arm_build_reg_cache(target, arm); if (!cache) @@ -998,9 +998,8 @@ int arm_dpm_setup(struct arm_dpm *dpm) /* FIXME add vector catch support */ dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf); - dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp); - dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf); + dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp); dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp); if (!dpm->dbp || !dpm->dwp) { diff --git a/src/target/arm_dpm.h b/src/target/arm_dpm.h index bbcae785..f8d12481 100644 --- a/src/target/arm_dpm.h +++ b/src/target/arm_dpm.h @@ -59,7 +59,7 @@ struct arm_dpm { struct arm *arm; /** Cache of DIDR */ - uint32_t didr; + uint64_t didr; /** Invoke before a series of instruction operations */ int (*prepare)(struct arm_dpm *); @@ -67,16 +67,26 @@ struct arm_dpm { /** Invoke after a series of instruction operations */ int (*finish)(struct arm_dpm *); + /** Runs one instruction. */ + int (*instr_execute)(struct arm_dpm *, uint32_t opcode); + /* WRITE TO CPU */ /** Runs one instruction, writing data to DCC before execution. */ int (*instr_write_data_dcc)(struct arm_dpm *, uint32_t opcode, uint32_t data); + int (*instr_write_data_dcc_64)(struct arm_dpm *, + uint32_t opcode, uint64_t data); + /** Runs one instruction, writing data to R0 before execution. */ int (*instr_write_data_r0)(struct arm_dpm *, uint32_t opcode, uint32_t data); + /** Runs one instruction, writing data to R0 before execution. */ + int (*instr_write_data_r0_64)(struct arm_dpm *, + uint32_t opcode, uint64_t data); + /** Optional core-specific operation invoked after CPSR writes. */ int (*instr_cpsr_sync)(struct arm_dpm *dpm); @@ -86,10 +96,19 @@ struct arm_dpm { int (*instr_read_data_dcc)(struct arm_dpm *, uint32_t opcode, uint32_t *data); + int (*instr_read_data_dcc_64)(struct arm_dpm *, + uint32_t opcode, uint64_t *data); + /** Runs one instruction, reading data from r0 after execution. */ int (*instr_read_data_r0)(struct arm_dpm *, uint32_t opcode, uint32_t *data); + int (*instr_read_data_r0_64)(struct arm_dpm *, + uint32_t opcode, uint64_t *data); + + struct reg *(*arm_reg_current)(struct arm *arm, + unsigned regnum); + /* BREAKPOINT/WATCHPOINT SUPPORT */ /** @@ -119,11 +138,14 @@ struct arm_dpm { struct dpm_wp *dwp; /** Address of the instruction which triggered a watchpoint. */ - uint32_t wp_pc; + target_addr_t wp_pc; /** Recent value of DSCR. */ uint32_t dscr; + /** Recent exception level on armv8 */ + unsigned int last_el; + /* FIXME -- read/write DCSR methods and symbols */ }; @@ -133,7 +155,6 @@ int arm_dpm_initialize(struct arm_dpm *dpm); int arm_dpm_read_current_registers(struct arm_dpm *); int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode); - int arm_dpm_write_dirty_registers(struct arm_dpm *, bool bpwp); void arm_dpm_report_wfar(struct arm_dpm *, uint32_t wfar); @@ -166,21 +187,21 @@ void arm_dpm_report_wfar(struct arm_dpm *, uint32_t wfar); #define DSCR_DTR_TX_FULL (0x1 << 29) #define DSCR_DTR_RX_FULL (0x1 << 30) /* bit 31 is reserved */ -#define DSCR_ENTRY(dscr) (((dscr) >> 2) & 0xf) -#define DSCR_RUN_MODE(dscr) ((dscr) & (DSCR_CORE_HALTED | DSCR_CORE_RESTARTED)) +#define DSCR_ENTRY(dscr) ((dscr) & 0x3f) +#define DSCR_RUN_MODE(dscr) ((dscr) & 0x03) /* Methods of entry into debug mode */ -#define DSCR_ENTRY_HALT_REQ (0x0 << 2) -#define DSCR_ENTRY_BREAKPOINT (0x1 << 2) -#define DSCR_ENTRY_IMPRECISE_WATCHPT (0x2 << 2) -#define DSCR_ENTRY_BKPT_INSTR (0x3 << 2) -#define DSCR_ENTRY_EXT_DBG_REQ (0x4 << 2) -#define DSCR_ENTRY_VECT_CATCH (0x5 << 2) -#define DSCR_ENTRY_D_SIDE_ABORT (0x6 << 2) /* v6 only */ -#define DSCR_ENTRY_I_SIDE_ABORT (0x7 << 2) /* v6 only */ -#define DSCR_ENTRY_OS_UNLOCK (0x8 << 2) -#define DSCR_ENTRY_PRECISE_WATCHPT (0xA << 2) +#define DSCR_ENTRY_HALT_REQ (0x03) +#define DSCR_ENTRY_BREAKPOINT (0x07) +#define DSCR_ENTRY_IMPRECISE_WATCHPT (0x0B) +#define DSCR_ENTRY_BKPT_INSTR (0x0F) +#define DSCR_ENTRY_EXT_DBG_REQ (0x13) +#define DSCR_ENTRY_VECT_CATCH (0x17) +#define DSCR_ENTRY_D_SIDE_ABORT (0x1B) /* v6 only */ +#define DSCR_ENTRY_I_SIDE_ABORT (0x1F) /* v6 only */ +#define DSCR_ENTRY_OS_UNLOCK (0x23) +#define DSCR_ENTRY_PRECISE_WATCHPT (0x2B) /* DTR modes */ #define DSCR_EXT_DCC_NON_BLOCKING (0x0 << 20) diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 624a2543..2029ca92 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -816,7 +816,7 @@ COMMAND_HANDLER(handle_arm_disassemble_command) } struct arm *arm = target_to_arm(target); - uint32_t address; + target_addr_t address; int count = 1; int thumb = 0; @@ -840,7 +840,7 @@ COMMAND_HANDLER(handle_arm_disassemble_command) COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], count); /* FALL THROUGH */ case 1: - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); if (address & 0x01) { if (!thumb) { command_print(CMD_CTX, "Disassemble as Thumb"); @@ -1434,8 +1434,8 @@ int armv4_5_run_algorithm(struct target *target, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - uint32_t entry_point, - uint32_t exit_point, + target_addr_t entry_point, + target_addr_t exit_point, int timeout_ms, void *arch_info) { @@ -1444,8 +1444,8 @@ int armv4_5_run_algorithm(struct target *target, mem_params, num_reg_params, reg_params, - entry_point, - exit_point, + (uint32_t)entry_point, + (uint32_t)exit_point, timeout_ms, arch_info, armv4_5_run_algorithm_completion); @@ -1456,7 +1456,7 @@ int armv4_5_run_algorithm(struct target *target, * */ int arm_checksum_memory(struct target *target, - uint32_t address, uint32_t count, uint32_t *checksum) + target_addr_t address, uint32_t count, uint32_t *checksum) { struct working_area *crc_algorithm; struct arm_algorithm arm_algo; @@ -1529,7 +1529,7 @@ int arm_checksum_memory(struct target *target, * */ int arm_blank_check_memory(struct target *target, - uint32_t address, uint32_t count, uint32_t *blank, uint8_t erased_value) + target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value) { struct working_area *check_algorithm; struct reg_param reg_params[3]; diff --git a/src/target/armv4_5_mmu.h b/src/target/armv4_5_mmu.h index 0f521214..7beaf4ee 100644 --- a/src/target/armv4_5_mmu.h +++ b/src/target/armv4_5_mmu.h @@ -25,8 +25,9 @@ struct target; struct armv4_5_mmu_common { int (*get_ttb)(struct target *target, uint32_t *result); - int (*read_memory)(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); - int (*write_memory)(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); + int (*read_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); + int (*write_memory)(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer); int (*disable_mmu_caches)(struct target *target, int mmu, int d_u_cache, int i_cache); int (*enable_mmu_caches)(struct target *target, int mmu, int d_u_cache, int i_cache); struct armv4_5_cache_common armv4_5_cache; diff --git a/src/target/armv7a.h b/src/target/armv7a.h index c5c03c89..14112e4e 100644 --- a/src/target/armv7a.h +++ b/src/target/armv7a.h @@ -90,7 +90,7 @@ struct armv7a_mmu_common { uint32_t ttbr_mask[2]; uint32_t ttbr_range[2]; - int (*read_physical_memory)(struct target *target, uint32_t address, uint32_t size, + int (*read_physical_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); struct armv7a_cache_common armv7a_cache; uint32_t mmu_enabled; diff --git a/src/target/armv7a_cache_l2x.c b/src/target/armv7a_cache_l2x.c index 79884383..e181f268 100644 --- a/src/target/armv7a_cache_l2x.c +++ b/src/target/armv7a_cache_l2x.c @@ -63,12 +63,12 @@ int arm7a_l2x_flush_all_data(struct target *target) l2_way_val = (1 << l2x_cache->way) - 1; - return target_write_phys_memory(target, + return target_write_phys_u32(target, l2x_cache->base + L2X0_CLEAN_INV_WAY, - 4, 1, (uint8_t *)&l2_way_val); + l2_way_val); } -int armv7a_l2x_cache_flush_virt(struct target *target, uint32_t virt, +int armv7a_l2x_cache_flush_virt(struct target *target, target_addr_t virt, uint32_t size) { struct armv7a_common *armv7a = target_to_armv7a(target); @@ -83,16 +83,15 @@ int armv7a_l2x_cache_flush_virt(struct target *target, uint32_t virt, return retval; for (i = 0; i < size; i += linelen) { - uint32_t pa, offs = virt + i; + target_addr_t pa, offs = virt + i; /* FIXME: use less verbose virt2phys? */ retval = target->type->virt2phys(target, offs, &pa); if (retval != ERROR_OK) goto done; - retval = target_write_phys_memory(target, - l2x_cache->base + L2X0_CLEAN_INV_LINE_PA, - 4, 1, (uint8_t *)&pa); + retval = target_write_phys_u32(target, + l2x_cache->base + L2X0_CLEAN_INV_LINE_PA, pa); if (retval != ERROR_OK) goto done; } @@ -104,7 +103,7 @@ int armv7a_l2x_cache_flush_virt(struct target *target, uint32_t virt, return retval; } -static int armv7a_l2x_cache_inval_virt(struct target *target, uint32_t virt, +static int armv7a_l2x_cache_inval_virt(struct target *target, target_addr_t virt, uint32_t size) { struct armv7a_common *armv7a = target_to_armv7a(target); @@ -119,16 +118,15 @@ static int armv7a_l2x_cache_inval_virt(struct target *target, uint32_t virt, return retval; for (i = 0; i < size; i += linelen) { - uint32_t pa, offs = virt + i; + target_addr_t pa, offs = virt + i; /* FIXME: use less verbose virt2phys? */ retval = target->type->virt2phys(target, offs, &pa); if (retval != ERROR_OK) goto done; - retval = target_write_phys_memory(target, - l2x_cache->base + L2X0_INV_LINE_PA, - 4, 1, (uint8_t *)&pa); + retval = target_write_phys_u32(target, + l2x_cache->base + L2X0_INV_LINE_PA, pa); if (retval != ERROR_OK) goto done; } @@ -140,7 +138,7 @@ static int armv7a_l2x_cache_inval_virt(struct target *target, uint32_t virt, return retval; } -static int armv7a_l2x_cache_clean_virt(struct target *target, uint32_t virt, +static int armv7a_l2x_cache_clean_virt(struct target *target, target_addr_t virt, unsigned int size) { struct armv7a_common *armv7a = target_to_armv7a(target); @@ -155,16 +153,15 @@ static int armv7a_l2x_cache_clean_virt(struct target *target, uint32_t virt, return retval; for (i = 0; i < size; i += linelen) { - uint32_t pa, offs = virt + i; + target_addr_t pa, offs = virt + i; /* FIXME: use less verbose virt2phys? */ retval = target->type->virt2phys(target, offs, &pa); if (retval != ERROR_OK) goto done; - retval = target_write_phys_memory(target, - l2x_cache->base + L2X0_CLEAN_LINE_PA, - 4, 1, (uint8_t *)&pa); + retval = target_write_phys_u32(target, + l2x_cache->base + L2X0_CLEAN_LINE_PA, pa); if (retval != ERROR_OK) goto done; } @@ -252,7 +249,8 @@ COMMAND_HANDLER(arm7a_l2x_cache_flush_all_command) COMMAND_HANDLER(arm7a_l2x_cache_flush_virt_cmd) { struct target *target = get_current_target(CMD_CTX); - uint32_t virt, size; + target_addr_t virt; + uint32_t size; if (CMD_ARGC == 0 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; @@ -262,7 +260,7 @@ COMMAND_HANDLER(arm7a_l2x_cache_flush_virt_cmd) else size = 1; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt); + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], virt); return armv7a_l2x_cache_flush_virt(target, virt, size); } @@ -270,7 +268,8 @@ COMMAND_HANDLER(arm7a_l2x_cache_flush_virt_cmd) COMMAND_HANDLER(arm7a_l2x_cache_inval_virt_cmd) { struct target *target = get_current_target(CMD_CTX); - uint32_t virt, size; + target_addr_t virt; + uint32_t size; if (CMD_ARGC == 0 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; @@ -280,7 +279,7 @@ COMMAND_HANDLER(arm7a_l2x_cache_inval_virt_cmd) else size = 1; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt); + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], virt); return armv7a_l2x_cache_inval_virt(target, virt, size); } @@ -288,7 +287,8 @@ COMMAND_HANDLER(arm7a_l2x_cache_inval_virt_cmd) COMMAND_HANDLER(arm7a_l2x_cache_clean_virt_cmd) { struct target *target = get_current_target(CMD_CTX); - uint32_t virt, size; + target_addr_t virt; + uint32_t size; if (CMD_ARGC == 0 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; @@ -298,7 +298,7 @@ COMMAND_HANDLER(arm7a_l2x_cache_clean_virt_cmd) else size = 1; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt); + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], virt); return armv7a_l2x_cache_clean_virt(target, virt, size); } diff --git a/src/target/armv7a_cache_l2x.h b/src/target/armv7a_cache_l2x.h index 3d9ad811..f98b5544 100644 --- a/src/target/armv7a_cache_l2x.h +++ b/src/target/armv7a_cache_l2x.h @@ -151,7 +151,7 @@ struct l2c_init_data { extern const struct command_registration arm7a_l2x_cache_command_handler[]; -int armv7a_l2x_cache_flush_virt(struct target *target, uint32_t virt, +int armv7a_l2x_cache_flush_virt(struct target *target, target_addr_t virt, uint32_t size); int arm7a_l2x_flush_all_data(struct target *target); diff --git a/src/target/armv7m.c b/src/target/armv7m.c index 64d18d75..e0911c30 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -318,7 +318,7 @@ int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int armv7m_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - uint32_t entry_point, uint32_t exit_point, + target_addr_t entry_point, target_addr_t exit_point, int timeout_ms, void *arch_info) { int retval; @@ -343,7 +343,7 @@ int armv7m_run_algorithm(struct target *target, int armv7m_start_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - uint32_t entry_point, uint32_t exit_point, + target_addr_t entry_point, target_addr_t exit_point, void *arch_info) { struct armv7m_common *armv7m = target_to_armv7m(target); @@ -431,7 +431,7 @@ int armv7m_start_algorithm(struct target *target, int armv7m_wait_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - uint32_t exit_point, int timeout_ms, + target_addr_t exit_point, int timeout_ms, void *arch_info) { struct armv7m_common *armv7m = target_to_armv7m(target); @@ -461,7 +461,7 @@ int armv7m_wait_algorithm(struct target *target, armv7m->load_core_reg_u32(target, 15, &pc); if (exit_point && (pc != exit_point)) { - LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" PRIx32, + LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" TARGET_PRIxADDR, pc, exit_point); return ERROR_TARGET_TIMEOUT; @@ -682,7 +682,7 @@ int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m) /** Generates a CRC32 checksum of a memory region. */ int armv7m_checksum_memory(struct target *target, - uint32_t address, uint32_t count, uint32_t *checksum) + target_addr_t address, uint32_t count, uint32_t *checksum) { struct working_area *crc_algorithm; struct armv7m_algorithm armv7m_info; @@ -733,7 +733,7 @@ int armv7m_checksum_memory(struct target *target, /** Checks whether a memory region is erased. */ int armv7m_blank_check_memory(struct target *target, - uint32_t address, uint32_t count, uint32_t *blank, uint8_t erased_value) + target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value) { struct working_area *erase_check_algorithm; struct reg_param reg_params[3]; diff --git a/src/target/armv7m.h b/src/target/armv7m.h index 304c72d3..284bb9ca 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -203,19 +203,19 @@ int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m); int armv7m_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - uint32_t entry_point, uint32_t exit_point, + target_addr_t entry_point, target_addr_t exit_point, int timeout_ms, void *arch_info); int armv7m_start_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - uint32_t entry_point, uint32_t exit_point, + target_addr_t entry_point, target_addr_t exit_point, void *arch_info); int armv7m_wait_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - uint32_t exit_point, int timeout_ms, + target_addr_t exit_point, int timeout_ms, void *arch_info); int armv7m_invalidate_core_regs(struct target *target); @@ -223,9 +223,9 @@ int armv7m_invalidate_core_regs(struct target *target); int armv7m_restore_context(struct target *target); int armv7m_checksum_memory(struct target *target, - uint32_t address, uint32_t count, uint32_t *checksum); + target_addr_t address, uint32_t count, uint32_t *checksum); int armv7m_blank_check_memory(struct target *target, - uint32_t address, uint32_t count, uint32_t *blank, uint8_t erased_value); + target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value); int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found); diff --git a/src/target/armv8.c b/src/target/armv8.c new file mode 100644 index 00000000..df5e2510 --- /dev/null +++ b/src/target/armv8.c @@ -0,0 +1,1308 @@ +/*************************************************************************** + * Copyright (C) 2015 by David Ung * + * * + * 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 "armv8.h" +#include "arm_disassembler.h" + +#include "register.h" +#include +#include + +#include +#include +#include + +#include "armv8_opcodes.h" +#include "target.h" +#include "target_type.h" + +static const char * const armv8_state_strings[] = { + "AArch32", "Thumb", "Jazelle", "ThumbEE", "AArch64", +}; + +static const struct { + const char *name; + unsigned psr; +} armv8_mode_data[] = { + /* These special modes are currently only supported + * by ARMv6M and ARMv7M profiles */ + { + .name = "USR", + .psr = ARM_MODE_USR, + }, + { + .name = "FIQ", + .psr = ARM_MODE_FIQ, + }, + { + .name = "IRQ", + .psr = ARM_MODE_IRQ, + }, + { + .name = "SVC", + .psr = ARM_MODE_SVC, + }, + { + .name = "MON", + .psr = ARM_MODE_MON, + }, + { + .name = "ABT", + .psr = ARM_MODE_ABT, + }, + { + .name = "EL0T", + .psr = ARMV8_64_EL0T, + }, + { + .name = "EL1T", + .psr = ARMV8_64_EL1T, + }, + { + .name = "EL1H", + .psr = ARMV8_64_EL1H, + }, + { + .name = "EL2T", + .psr = ARMV8_64_EL2T, + }, + { + .name = "EL2H", + .psr = ARMV8_64_EL2H, + }, + { + .name = "EL3T", + .psr = ARMV8_64_EL3T, + }, + { + .name = "EL3H", + .psr = ARMV8_64_EL3H, + }, +}; + +/** Map PSR mode bits to the name of an ARM processor operating mode. */ +const char *armv8_mode_name(unsigned psr_mode) +{ + for (unsigned i = 0; i < ARRAY_SIZE(armv8_mode_data); i++) { + if (armv8_mode_data[i].psr == psr_mode) + return armv8_mode_data[i].name; + } + LOG_ERROR("unrecognized psr mode: %#02x", psr_mode); + return "UNRECOGNIZED"; +} + +int armv8_mode_to_number(enum arm_mode mode) +{ + switch (mode) { + case ARM_MODE_ANY: + /* map MODE_ANY to user mode */ + case ARM_MODE_USR: + return 0; + case ARM_MODE_FIQ: + return 1; + case ARM_MODE_IRQ: + return 2; + case ARM_MODE_SVC: + return 3; + case ARM_MODE_ABT: + return 4; + case ARM_MODE_UND: + return 5; + case ARM_MODE_SYS: + return 6; + case ARM_MODE_MON: + return 7; + case ARMV8_64_EL0T: + return 8; + case ARMV8_64_EL1T: + return 9; + case ARMV8_64_EL1H: + return 10; + case ARMV8_64_EL2T: + return 11; + case ARMV8_64_EL2H: + return 12; + case ARMV8_64_EL3T: + return 13; + case ARMV8_64_EL3H: + return 14; + + default: + LOG_ERROR("invalid mode value encountered %d", mode); + return -1; + } +} + +static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regval) +{ + struct arm_dpm *dpm = &armv8->dpm; + int retval; + uint32_t value; + uint64_t value_64; + + switch (regnum) { + case 0 ... 30: + retval = dpm->instr_read_data_dcc_64(dpm, + ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0, regnum), &value_64); + break; + case ARMV8_SP: + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MOVFSP_64(0), &value_64); + break; + case ARMV8_PC: + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS_DLR(0), &value_64); + break; + case ARMV8_xPSR: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS_DSPSR(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); + break; + case ARMV8_ELR_EL2: + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_ELR_EL2, 0), &value_64); + break; + case ARMV8_ELR_EL3: + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_ELR_EL3, 0), &value_64); + break; + case ARMV8_ESR_EL1: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS(SYSTEM_ESR_EL1, 0), &value); + value_64 = value; + break; + case ARMV8_ESR_EL2: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS(SYSTEM_ESR_EL2, 0), &value); + value_64 = value; + break; + case ARMV8_ESR_EL3: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS(SYSTEM_ESR_EL3, 0), &value); + value_64 = value; + break; + case ARMV8_SPSR_EL1: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS(SYSTEM_SPSR_EL1, 0), &value); + value_64 = value; + break; + case ARMV8_SPSR_EL2: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS(SYSTEM_SPSR_EL2, 0), &value); + value_64 = value; + break; + case ARMV8_SPSR_EL3: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS(SYSTEM_SPSR_EL3, 0), &value); + value_64 = value; + break; + default: + retval = ERROR_FAIL; + break; + } + + if (retval == ERROR_OK && regval != NULL) + *regval = value_64; + + return retval; +} + +static int armv8_write_reg(struct armv8_common *armv8, int regnum, uint64_t value_64) +{ + struct arm_dpm *dpm = &armv8->dpm; + int retval; + uint32_t value; + + switch (regnum) { + case 0 ... 30: + retval = dpm->instr_write_data_dcc_64(dpm, + ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, regnum), + value_64); + break; + case ARMV8_SP: + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MOVTSP_64(0), + value_64); + break; + case ARMV8_PC: + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MSR_DLR(0), + value_64); + break; + case ARMV8_xPSR: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_DSPSR(0), + value); + break; + /* registers clobbered by taking exception in debug state */ + case ARMV8_ELR_EL1: + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MSR_GP(SYSTEM_ELR_EL1, 0), value_64); + break; + case ARMV8_ELR_EL2: + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MSR_GP(SYSTEM_ELR_EL2, 0), value_64); + break; + case ARMV8_ELR_EL3: + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MSR_GP(SYSTEM_ELR_EL3, 0), value_64); + break; + case ARMV8_ESR_EL1: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP(SYSTEM_ESR_EL1, 0), value); + break; + case ARMV8_ESR_EL2: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP(SYSTEM_ESR_EL2, 0), value); + break; + case ARMV8_ESR_EL3: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP(SYSTEM_ESR_EL3, 0), value); + break; + case ARMV8_SPSR_EL1: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP(SYSTEM_SPSR_EL1, 0), value); + break; + case ARMV8_SPSR_EL2: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP(SYSTEM_SPSR_EL2, 0), value); + break; + case ARMV8_SPSR_EL3: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP(SYSTEM_SPSR_EL3, 0), value); + 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; + uint32_t value = 0; + int retval; + + switch (regnum) { + case ARMV8_R0 ... ARMV8_R14: + /* return via DCC: "MCR p14, 0, Rnum, c0, c5, 0" */ + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, regnum, 0, 5, 0), + &value); + break; + case ARMV8_SP: + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, 13, 0, 5, 0), + &value); + break; + case ARMV8_PC: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRC_DLR(0), + &value); + break; + case ARMV8_xPSR: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRC_DSPSR(0), + &value); + break; + case ARMV8_ELR_EL1: /* mapped to LR_svc */ + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, 14, 0, 5, 0), + &value); + break; + case ARMV8_ELR_EL2: /* mapped to ELR_hyp */ + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS_T1(0, 14, 0, 1), + &value); + break; + case ARMV8_ELR_EL3: /* mapped to LR_mon */ + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, 14, 0, 5, 0), + &value); + break; + case ARMV8_ESR_EL1: /* mapped to DFSR */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRC(15, 0, 0, 5, 0, 0), + &value); + break; + case ARMV8_ESR_EL2: /* mapped to HSR */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRC(15, 4, 0, 5, 2, 0), + &value); + break; + case ARMV8_ESR_EL3: /* FIXME: no equivalent in aarch32? */ + retval = ERROR_FAIL; + break; + case ARMV8_SPSR_EL1: /* mapped to SPSR_svc */ + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS_xPSR_T1(1, 0), + &value); + break; + case ARMV8_SPSR_EL2: /* mapped to SPSR_hyp */ + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS_xPSR_T1(1, 0), + &value); + break; + case ARMV8_SPSR_EL3: /* mapped to SPSR_mon */ + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS_xPSR_T1(1, 0), + &value); + break; + default: + retval = ERROR_FAIL; + break; + } + + if (retval == ERROR_OK && regval != NULL) + *regval = value; + + return retval; +} + +static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t value) +{ + struct arm_dpm *dpm = &armv8->dpm; + int retval; + + switch (regnum) { + case ARMV8_R0 ... ARMV8_R14: + /* load register from DCC: "MRC p14, 0, Rnum, c0, c5, 0" */ + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, regnum, 0, 5, 0), value); + break; + case ARMV8_SP: + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, 13, 0, 5, 0), value); + break; + case ARMV8_PC:/* PC + * read r0 from DCC; then "MOV pc, r0" */ + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MCR_DLR(0), value); + break; + case ARMV8_xPSR: /* CPSR */ + /* read r0 from DCC, then "MCR r0, DSPSR" */ + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MCR_DSPSR(0), value); + break; + case ARMV8_ELR_EL1: /* mapped to LR_svc */ + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, 14, 0, 5, 0), + value); + break; + case ARMV8_ELR_EL2: /* mapped to ELR_hyp */ + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP_T1(0, 14, 0, 1), + value); + break; + case ARMV8_ELR_EL3: /* mapped to LR_mon */ + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, 14, 0, 5, 0), + value); + break; + case ARMV8_ESR_EL1: /* mapped to DFSR */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_MCR(15, 0, 0, 5, 0, 0), + value); + break; + case ARMV8_ESR_EL2: /* mapped to HSR */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_MCR(15, 4, 0, 5, 2, 0), + value); + break; + case ARMV8_ESR_EL3: /* FIXME: no equivalent in aarch32? */ + retval = ERROR_FAIL; + break; + case ARMV8_SPSR_EL1: /* mapped to SPSR_svc */ + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP_xPSR_T1(1, 0, 15), + value); + break; + case ARMV8_SPSR_EL2: /* mapped to SPSR_hyp */ + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP_xPSR_T1(1, 0, 15), + value); + break; + case ARMV8_SPSR_EL3: /* mapped to SPSR_mon */ + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP_xPSR_T1(1, 0, 15), + value); + 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; + } else { + armv8->read_reg_u64 = armv8_read_reg32; + armv8->write_reg_u64 = armv8_write_reg32; + } +} + +/* retrieve core id cluster id */ +int armv8_read_mpidr(struct armv8_common *armv8) +{ + int retval = ERROR_FAIL; + struct arm_dpm *dpm = armv8->arm.dpm; + uint32_t mpidr; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + + retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_MPIDR), &mpidr); + if (retval != ERROR_OK) + goto done; + if (mpidr & 1<<31) { + armv8->multi_processor_system = (mpidr >> 30) & 1; + armv8->cluster_id = (mpidr >> 8) & 0xf; + armv8->cpu_id = mpidr & 0x3; + LOG_INFO("%s cluster %x core %x %s", target_name(armv8->arm.target), + armv8->cluster_id, + armv8->cpu_id, + armv8->multi_processor_system == 0 ? "multi core" : "single core"); + } else + LOG_ERROR("mpidr not in multiprocessor format"); + +done: + dpm->finish(dpm); + return retval; +} + +/** + * Configures host-side ARM records to reflect the specified CPSR. + * Later, code can use arm_reg_current() to map register numbers + * according to how they are exposed by this mode. + */ +void armv8_set_cpsr(struct arm *arm, uint32_t cpsr) +{ + uint32_t mode = cpsr & 0x1F; + + /* NOTE: this may be called very early, before the register + * cache is set up. We can't defend against many errors, in + * particular against CPSRs that aren't valid *here* ... + */ + if (arm->cpsr) { + buf_set_u32(arm->cpsr->value, 0, 32, cpsr); + arm->cpsr->valid = 1; + arm->cpsr->dirty = 0; + } + + /* Older ARMs won't have the J bit */ + enum arm_state state = 0xFF; + + if (((cpsr & 0x10) >> 4) == 0) { + state = ARM_STATE_AARCH64; + } else { + if (cpsr & (1 << 5)) { /* T */ + if (cpsr & (1 << 24)) { /* J */ + LOG_WARNING("ThumbEE -- incomplete support"); + state = ARM_STATE_THUMB_EE; + } else + state = ARM_STATE_THUMB; + } else { + if (cpsr & (1 << 24)) { /* J */ + LOG_ERROR("Jazelle state handling is BROKEN!"); + state = ARM_STATE_JAZELLE; + } else + state = ARM_STATE_ARM; + } + } + arm->core_state = state; + if (arm->core_state == ARM_STATE_AARCH64) + arm->core_mode = (mode << 4) | 0xf; + else + arm->core_mode = mode; + + LOG_DEBUG("set CPSR %#8.8x: %s mode, %s state", (unsigned) cpsr, + armv8_mode_name(arm->core_mode), + armv8_state_strings[arm->core_state]); +} + +static void armv8_show_fault_registers32(struct armv8_common *armv8) +{ + uint32_t dfsr, ifsr, dfar, ifar; + struct arm_dpm *dpm = armv8->arm.dpm; + int retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + return; + + /* ARMV4_5_MRC(cpnum, op1, r0, CRn, CRm, op2) */ + + /* c5/c0 - {data, instruction} fault status registers */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRC(15, 0, 0, 5, 0, 0), + &dfsr); + if (retval != ERROR_OK) + goto done; + + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRC(15, 0, 0, 5, 0, 1), + &ifsr); + if (retval != ERROR_OK) + goto done; + + /* c6/c0 - {data, instruction} fault address registers */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRC(15, 0, 0, 6, 0, 0), + &dfar); + if (retval != ERROR_OK) + goto done; + + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRC(15, 0, 0, 6, 0, 2), + &ifar); + if (retval != ERROR_OK) + goto done; + + LOG_USER("Data fault registers DFSR: %8.8" PRIx32 + ", DFAR: %8.8" PRIx32, dfsr, dfar); + LOG_USER("Instruction fault registers IFSR: %8.8" PRIx32 + ", IFAR: %8.8" PRIx32, ifsr, ifar); + +done: + /* (void) */ dpm->finish(dpm); +} + +static __attribute__((unused)) void armv8_show_fault_registers(struct target *target) +{ + struct armv8_common *armv8 = target_to_armv8(target); + + if (armv8->arm.core_state != ARM_STATE_AARCH64) + armv8_show_fault_registers32(armv8); +} + +static uint8_t armv8_pa_size(uint32_t ps) +{ + uint8_t ret = 0; + switch (ps) { + case 0: + ret = 32; + break; + case 1: + ret = 36; + break; + case 2: + ret = 40; + break; + case 3: + ret = 42; + break; + case 4: + ret = 44; + break; + case 5: + ret = 48; + break; + default: + LOG_INFO("Unknow physicall address size"); + break; + } + return ret; +} + +static __attribute__((unused)) int armv8_read_ttbcr32(struct target *target) +{ + struct armv8_common *armv8 = target_to_armv8(target); + struct arm_dpm *dpm = armv8->arm.dpm; + uint32_t ttbcr, ttbcr_n; + int 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; + + LOG_DEBUG("ttbcr %" PRIx32, ttbcr); + + ttbcr_n = ttbcr & 0x7; + armv8->armv8_mmu.ttbcr = ttbcr; + + /* + * ARM Architecture Reference Manual (ARMv7-A and ARMv7-Redition), + * document # ARM DDI 0406C + */ + armv8->armv8_mmu.ttbr_range[0] = 0xffffffff >> ttbcr_n; + armv8->armv8_mmu.ttbr_range[1] = 0xffffffff; + armv8->armv8_mmu.ttbr_mask[0] = 0xffffffff << (14 - ttbcr_n); + armv8->armv8_mmu.ttbr_mask[1] = 0xffffffff << 14; + + LOG_DEBUG("ttbr1 %s, ttbr0_mask %" PRIx32 " ttbr1_mask %" PRIx32, + (ttbcr_n != 0) ? "used" : "not used", + armv8->armv8_mmu.ttbr_mask[0], + armv8->armv8_mmu.ttbr_mask[1]); + +done: + dpm->finish(dpm); + return retval; +} + +static __attribute__((unused)) int armv8_read_ttbcr(struct target *target) +{ + struct armv8_common *armv8 = target_to_armv8(target); + struct arm_dpm *dpm = armv8->arm.dpm; + struct arm *arm = &armv8->arm; + uint32_t ttbcr; + uint64_t ttbcr_64; + + int retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + + /* claaer ttrr1_used and ttbr0_mask */ + memset(&armv8->armv8_mmu.ttbr1_used, 0, sizeof(armv8->armv8_mmu.ttbr1_used)); + memset(&armv8->armv8_mmu.ttbr0_mask, 0, sizeof(armv8->armv8_mmu.ttbr0_mask)); + + switch (armv8_curel_from_core_mode(arm->core_mode)) { + case SYSTEM_CUREL_EL3: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS(SYSTEM_TCR_EL3, 0), + &ttbcr); + retval += dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_TTBR0_EL3, 0), + &armv8->ttbr_base); + if (retval != ERROR_OK) + goto done; + armv8->va_size = 64 - (ttbcr & 0x3F); + armv8->pa_size = armv8_pa_size((ttbcr >> 16) & 7); + armv8->page_size = (ttbcr >> 14) & 3; + break; + case SYSTEM_CUREL_EL2: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS(SYSTEM_TCR_EL2, 0), + &ttbcr); + retval += dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_TTBR0_EL2, 0), + &armv8->ttbr_base); + if (retval != ERROR_OK) + goto done; + armv8->va_size = 64 - (ttbcr & 0x3F); + armv8->pa_size = armv8_pa_size((ttbcr >> 16) & 7); + armv8->page_size = (ttbcr >> 14) & 3; + break; + case SYSTEM_CUREL_EL0: + armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H); + /* fall through */ + case SYSTEM_CUREL_EL1: + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_TCR_EL1, 0), + &ttbcr_64); + armv8->va_size = 64 - (ttbcr_64 & 0x3F); + armv8->pa_size = armv8_pa_size((ttbcr_64 >> 32) & 7); + armv8->page_size = (ttbcr_64 >> 14) & 3; + armv8->armv8_mmu.ttbr1_used = (((ttbcr_64 >> 16) & 0x3F) != 0) ? 1 : 0; + armv8->armv8_mmu.ttbr0_mask = 0x0000FFFFFFFFFFFF; + retval += dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_TTBR0_EL1 | (armv8->armv8_mmu.ttbr1_used), 0), + &armv8->ttbr_base); + if (retval != ERROR_OK) + goto done; + break; + default: + LOG_ERROR("unknow core state"); + retval = ERROR_FAIL; + break; + } + if (retval != ERROR_OK) + goto done; + + if (armv8->armv8_mmu.ttbr1_used == 1) + LOG_INFO("TTBR0 access above %" PRIx64, (uint64_t)(armv8->armv8_mmu.ttbr0_mask)); + +done: + armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); + dpm->finish(dpm); + return retval; +} + +/* method adapted to cortex A : reused arm v4 v5 method*/ +int armv8_mmu_translate_va(struct target *target, target_addr_t va, target_addr_t *val) +{ + return ERROR_OK; +} + +/* V8 method VA TO PA */ +int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va, + target_addr_t *val, int meminfo) +{ + struct armv8_common *armv8 = target_to_armv8(target); + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = &armv8->dpm; + enum arm_mode target_mode = ARM_MODE_ANY; + uint32_t retval; + uint32_t instr = 0; + uint64_t par; + + static const char * const shared_name[] = { + "Non-", "UNDEFINED ", "Outer ", "Inner " + }; + + static const char * const secure_name[] = { + "Secure", "Not Secure" + }; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + return retval; + + switch (armv8_curel_from_core_mode(arm->core_mode)) { + case SYSTEM_CUREL_EL0: + instr = ARMV8_SYS(SYSTEM_ATS12E0R, 0); + /* can only execute instruction at EL2 */ + target_mode = ARMV8_64_EL2H; + break; + case SYSTEM_CUREL_EL1: + instr = ARMV8_SYS(SYSTEM_ATS12E1R, 0); + /* can only execute instruction at EL2 */ + target_mode = ARMV8_64_EL2H; + break; + case SYSTEM_CUREL_EL2: + instr = ARMV8_SYS(SYSTEM_ATS1E2R, 0); + break; + case SYSTEM_CUREL_EL3: + instr = ARMV8_SYS(SYSTEM_ATS1E3R, 0); + break; + + default: + break; + }; + + if (target_mode != ARM_MODE_ANY) + armv8_dpm_modeswitch(dpm, target_mode); + + /* write VA to R0 and execute translation instruction */ + retval = dpm->instr_write_data_r0_64(dpm, instr, (uint64_t)va); + /* read result from PAR_EL1 */ + if (retval == ERROR_OK) + retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_PAR_EL1, 0), &par); + + /* switch back to saved PE mode */ + if (target_mode != ARM_MODE_ANY) + armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); + + dpm->finish(dpm); + + if (retval != ERROR_OK) + return retval; + + if (par & 1) { + LOG_ERROR("Address translation failed at stage %i, FST=%x, PTW=%i", + ((int)(par >> 9) & 1)+1, (int)(par >> 1) & 0x3f, (int)(par >> 8) & 1); + + *val = 0; + retval = ERROR_FAIL; + } else { + *val = (par & 0xFFFFFFFFF000UL) | (va & 0xFFF); + if (meminfo) { + int SH = (par >> 7) & 3; + int NS = (par >> 9) & 1; + int ATTR = (par >> 56) & 0xFF; + + char *memtype = (ATTR & 0xF0) == 0 ? "Device Memory" : "Normal Memory"; + + LOG_USER("%sshareable, %s", + shared_name[SH], secure_name[NS]); + LOG_USER("%s", memtype); + } + } + + return retval; +} + +int armv8_handle_cache_info_command(struct command_context *cmd_ctx, + struct armv8_cache_common *armv8_cache) +{ + if (armv8_cache->info == -1) { + command_print(cmd_ctx, "cache not yet identified"); + return ERROR_OK; + } + + if (armv8_cache->display_cache_info) + armv8_cache->display_cache_info(cmd_ctx, armv8_cache); + return ERROR_OK; +} + +int armv8_init_arch_info(struct target *target, struct armv8_common *armv8) +{ + struct arm *arm = &armv8->arm; + arm->arch_info = armv8; + target->arch_info = &armv8->arm; + /* target is useful in all function arm v4 5 compatible */ + armv8->arm.target = target; + armv8->arm.common_magic = ARM_COMMON_MAGIC; + armv8->common_magic = ARMV8_COMMON_MAGIC; + + armv8->armv8_mmu.armv8_cache.l2_cache = NULL; + armv8->armv8_mmu.armv8_cache.info = -1; + armv8->armv8_mmu.armv8_cache.flush_all_data_cache = NULL; + armv8->armv8_mmu.armv8_cache.display_cache_info = NULL; + return ERROR_OK; +} + +int armv8_aarch64_state(struct target *target) +{ + struct arm *arm = target_to_arm(target); + + if (arm->common_magic != ARM_COMMON_MAGIC) { + LOG_ERROR("BUG: called for a non-ARM target"); + return ERROR_FAIL; + } + + LOG_USER("target halted in %s state due to %s, current mode: %s\n" + "cpsr: 0x%8.8" PRIx32 " pc: 0x%" PRIx64 "%s", + armv8_state_strings[arm->core_state], + debug_reason_name(target), + armv8_mode_name(arm->core_mode), + buf_get_u32(arm->cpsr->value, 0, 32), + buf_get_u64(arm->pc->value, 0, 64), + arm->is_semihosting ? ", semihosting" : ""); + + return ERROR_OK; +} + +int armv8_arch_state(struct target *target) +{ + static const char * const state[] = { + "disabled", "enabled" + }; + + struct armv8_common *armv8 = target_to_armv8(target); + struct arm *arm = &armv8->arm; + + if (armv8->common_magic != ARMV8_COMMON_MAGIC) { + LOG_ERROR("BUG: called for a non-Armv8 target"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (arm->core_state == ARM_STATE_AARCH64) + armv8_aarch64_state(target); + else + arm_arch_state(target); + + LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s", + state[armv8->armv8_mmu.mmu_enabled], + state[armv8->armv8_mmu.armv8_cache.d_u_cache_enabled], + state[armv8->armv8_mmu.armv8_cache.i_cache_enabled]); + + if (arm->core_mode == ARM_MODE_ABT) + armv8_show_fault_registers(target); + + if (target->debug_reason == DBG_REASON_WATCHPOINT) + LOG_USER("Watchpoint triggered at PC %#08x", + (unsigned) armv8->dpm.wp_pc); + + 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" }, + + { 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" }, + + { ARMV8_xPSR, "CPSR", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.aarch64.core" }, + + { 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" }, + + { 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" }, + + { 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 const struct { + unsigned id; + 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" }, +}; + +#define ARMV8_NUM_REGS ARRAY_SIZE(armv8_regs) +#define ARMV8_NUM_REGS32 ARRAY_SIZE(armv8_regs32) + +static int armv8_get_core_reg(struct reg *reg) +{ + struct arm_reg *armv8_reg = reg->arch_info; + struct target *target = armv8_reg->target; + struct arm *arm = target_to_arm(target); + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + return arm->read_core_reg(target, reg, armv8_reg->num, arm->core_mode); +} + +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); + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + if (reg == arm->cpsr) { + armv8_set_cpsr(arm, (uint32_t)value); + } else { + buf_set_u64(reg->value, 0, 64, value); + reg->valid = 1; + } + + reg->dirty = 1; + + return ERROR_OK; +} + +static const struct reg_arch_type armv8_reg_type = { + .get = armv8_get_core_reg, + .set = armv8_set_core_reg, +}; + +static int armv8_get_core_reg32(struct reg *reg) +{ + struct arm_reg *armv8_reg = reg->arch_info; + struct target *target = armv8_reg->target; + struct arm *arm = target_to_arm(target); + struct reg_cache *cache = arm->core_cache; + struct reg *reg64; + int retval; + + /* get the corresponding Aarch64 register */ + reg64 = cache->reg_list + armv8_reg->num; + if (reg64->valid) { + reg->valid = true; + return ERROR_OK; + } + + retval = arm->read_core_reg(target, reg64, armv8_reg->num, arm->core_mode); + if (retval == ERROR_OK) + reg->valid = reg64->valid; + + return retval; +} + +static int armv8_set_core_reg32(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); + struct reg_cache *cache = arm->core_cache; + struct reg *reg64 = cache->reg_list + armv8_reg->num; + uint32_t value = buf_get_u32(buf, 0, 32); + + if (reg64 == arm->cpsr) { + armv8_set_cpsr(arm, value); + } else { + buf_set_u32(reg->value, 0, 32, value); + reg->valid = 1; + reg64->valid = 1; + } + + reg64->dirty = 1; + + return ERROR_OK; +} + +static const struct reg_arch_type armv8_reg32_type = { + .get = armv8_get_core_reg32, + .set = armv8_set_core_reg32, +}; + +/** Builds cache of architecturally defined registers. */ +struct reg_cache *armv8_build_reg_cache(struct target *target) +{ + struct armv8_common *armv8 = target_to_armv8(target); + struct arm *arm = &armv8->arm; + int num_regs = ARMV8_NUM_REGS; + int num_regs32 = ARMV8_NUM_REGS32; + struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); + struct reg_cache *cache = malloc(sizeof(struct reg_cache)); + struct reg_cache *cache32 = malloc(sizeof(struct reg_cache)); + struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); + struct reg *reg_list32 = calloc(num_regs32, sizeof(struct reg)); + struct arm_reg *arch_info = calloc(num_regs, sizeof(struct arm_reg)); + struct reg_feature *feature; + int i; + + /* Build the process context cache */ + cache->name = "Aarch64 registers"; + cache->next = cache32; + cache->reg_list = reg_list; + cache->num_regs = num_regs; + + for (i = 0; i < num_regs; i++) { + arch_info[i].num = armv8_regs[i].id; + arch_info[i].mode = armv8_regs[i].mode; + arch_info[i].target = target; + arch_info[i].arm = arm; + + reg_list[i].name = armv8_regs[i].name; + reg_list[i].size = armv8_regs[i].bits; + reg_list[i].value = &arch_info[i].value[0]; + reg_list[i].type = &armv8_reg_type; + reg_list[i].arch_info = &arch_info[i]; + + reg_list[i].group = armv8_regs[i].group; + reg_list[i].number = i; + reg_list[i].exist = true; + reg_list[i].caller_save = true; /* gdb defaults to true */ + + feature = calloc(1, sizeof(struct reg_feature)); + if (feature) { + feature->name = armv8_regs[i].feature; + reg_list[i].feature = feature; + } 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"); + } + + arm->cpsr = reg_list + ARMV8_xPSR; + arm->pc = reg_list + ARMV8_PC; + arm->core_cache = cache; + + /* shadow cache for ARM mode registers */ + cache32->name = "Aarch32 registers"; + cache32->next = NULL; + cache32->reg_list = reg_list32; + cache32->num_regs = num_regs32; + + 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].type = &armv8_reg32_type; + reg_list32[i].arch_info = &arch_info[armv8_regs32[i].id]; + reg_list32[i].group = armv8_regs32[i].group; + reg_list32[i].number = i; + reg_list32[i].exist = true; + reg_list32[i].caller_save = true; + + feature = calloc(1, sizeof(struct reg_feature)); + if (feature) { + feature->name = armv8_regs32[i].feature; + reg_list32[i].feature = feature; + } else + LOG_ERROR("unable to allocate feature list"); + + reg_list32[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); + if (reg_list32[i].reg_data_type) + reg_list32[i].reg_data_type->type = armv8_regs32[i].type; + else + LOG_ERROR("unable to allocate reg type list"); + } + + (*cache_p) = cache; + return cache; +} + +struct reg *armv8_reg_current(struct arm *arm, unsigned regnum) +{ + struct reg *r; + + if (regnum > (ARMV8_LAST_REG - 1)) + return NULL; + + r = arm->core_cache->reg_list + regnum; + return r; +} + +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) +{ + struct arm *arm = target_to_arm(target); + int i; + + if (arm->core_state == ARM_STATE_AARCH64) { + + LOG_DEBUG("Creating Aarch64 register list for target %s", target_name(target)); + + switch (reg_class) { + case REG_CLASS_GENERAL: + *reg_list_size = ARMV8_ELR_EL1; + *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); + + for (i = 0; i < *reg_list_size; i++) + (*reg_list)[i] = armv8_reg_current(arm, i); + return ERROR_OK; + + case REG_CLASS_ALL: + *reg_list_size = ARMV8_LAST_REG; + *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); + + for (i = 0; i < *reg_list_size; i++) + (*reg_list)[i] = armv8_reg_current(arm, i); + + return ERROR_OK; + + default: + LOG_ERROR("not a valid register class type in query."); + return ERROR_FAIL; + } + } else { + struct reg_cache *cache32 = arm->core_cache->next; + + LOG_DEBUG("Creating Aarch32 register list for target %s", target_name(target)); + + switch (reg_class) { + case REG_CLASS_GENERAL: + case REG_CLASS_ALL: + *reg_list_size = cache32->num_regs; + *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; + default: + LOG_ERROR("not a valid register class type in query."); + return ERROR_FAIL; + } + } +} + +int armv8_set_dbgreg_bits(struct armv8_common *armv8, unsigned int reg, unsigned long mask, unsigned long value) +{ + uint32_t tmp; + + /* Read register */ + int retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + reg, &tmp); + if (ERROR_OK != retval) + return retval; + + /* clear bitfield */ + tmp &= ~mask; + /* put new value */ + tmp |= value & mask; + + /* write new value */ + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + reg, tmp); + return retval; +} diff --git a/src/target/armv8.h b/src/target/armv8.h new file mode 100644 index 00000000..02663cab --- /dev/null +++ b/src/target/armv8.h @@ -0,0 +1,282 @@ +/*************************************************************************** + * Copyright (C) 2015 by David Ung * + * * + * 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., * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ARMV8_H +#define OPENOCD_TARGET_ARMV8_H + +#include "arm_adi_v5.h" +#include "arm.h" +#include "armv4_5_mmu.h" +#include "armv4_5_cache.h" +#include "armv8_dpm.h" +#include "arm_cti.h" + +enum { + ARMV8_R0 = 0, + ARMV8_R1, + ARMV8_R2, + ARMV8_R3, + ARMV8_R4, + ARMV8_R5, + ARMV8_R6, + ARMV8_R7, + ARMV8_R8, + ARMV8_R9, + ARMV8_R10, + ARMV8_R11, + ARMV8_R12, + ARMV8_R13, + ARMV8_R14, + ARMV8_R15, + ARMV8_R16, + ARMV8_R17, + ARMV8_R18, + ARMV8_R19, + ARMV8_R20, + ARMV8_R21, + ARMV8_R22, + ARMV8_R23, + ARMV8_R24, + ARMV8_R25, + ARMV8_R26, + ARMV8_R27, + ARMV8_R28, + ARMV8_R29, + ARMV8_R30, + + ARMV8_SP = 31, + ARMV8_PC = 32, + ARMV8_xPSR = 33, + + ARMV8_ELR_EL1 = 34, + ARMV8_ESR_EL1 = 35, + ARMV8_SPSR_EL1 = 36, + + ARMV8_ELR_EL2 = 37, + ARMV8_ESR_EL2 = 38, + ARMV8_SPSR_EL2 = 39, + + ARMV8_ELR_EL3 = 40, + ARMV8_ESR_EL3 = 41, + ARMV8_SPSR_EL3 = 42, + + ARMV8_LAST_REG, +}; + + +#define ARMV8_COMMON_MAGIC 0x0A450AAA + +/* VA to PA translation operations opc2 values*/ +#define V2PCWPR 0 +#define V2PCWPW 1 +#define V2PCWUR 2 +#define V2PCWUW 3 +#define V2POWPR 4 +#define V2POWPW 5 +#define V2POWUR 6 +#define V2POWUW 7 +/* L210/L220 cache controller support */ +struct armv8_l2x_cache { + uint32_t base; + uint32_t way; +}; + +struct armv8_cachesize { + uint32_t level_num; + /* cache dimensionning */ + uint32_t linelen; + uint32_t associativity; + uint32_t nsets; + uint32_t cachesize; + /* info for set way operation on cache */ + uint32_t index; + uint32_t index_shift; + uint32_t way; + uint32_t way_shift; +}; + +/* information about one architecture cache at any level */ +struct armv8_arch_cache { + int ctype; /* cache type, CLIDR encoding */ + struct armv8_cachesize d_u_size; /* data cache */ + struct armv8_cachesize i_size; /* instruction cache */ +}; + +struct armv8_cache_common { + int info; + int loc; + uint32_t iminline; + uint32_t dminline; + struct armv8_arch_cache arch[6]; /* cache info, L1 - L7 */ + int i_cache_enabled; + int d_u_cache_enabled; + + /* l2 external unified cache if some */ + void *l2_cache; + int (*flush_all_data_cache)(struct target *target); + int (*display_cache_info)(struct command_context *cmd_ctx, + struct armv8_cache_common *armv8_cache); +}; + +struct armv8_mmu_common { + /* following field mmu working way */ + int32_t ttbr1_used; /* -1 not initialized, 0 no ttbr1 1 ttbr1 used and */ + uint64_t ttbr0_mask;/* masked to be used */ + + uint32_t ttbcr; /* cache for ttbcr register */ + uint32_t ttbr_mask[2]; + uint32_t ttbr_range[2]; + + int (*read_physical_memory)(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer); + struct armv8_cache_common armv8_cache; + uint32_t mmu_enabled; +}; + +struct armv8_common { + struct arm arm; + int common_magic; + struct reg_cache *core_cache; + + /* Core Debug Unit */ + struct arm_dpm dpm; + uint32_t debug_base; + struct adiv5_ap *debug_ap; + + const uint32_t *opcodes; + + /* mdir */ + uint8_t multi_processor_system; + uint8_t cluster_id; + uint8_t cpu_id; + + /* armv8 aarch64 need below information for page translation */ + uint8_t va_size; + uint8_t pa_size; + uint32_t page_size; + uint64_t ttbr_base; + + struct armv8_mmu_common armv8_mmu; + + struct arm_cti *cti; + + /* Direct processor core register read and writes */ + int (*read_reg_u64)(struct armv8_common *armv8, int num, uint64_t *value); + int (*write_reg_u64)(struct armv8_common *armv8, int num, uint64_t value); + + int (*examine_debug_reason)(struct target *target); + int (*post_debug_entry)(struct target *target); + + void (*pre_restore_context)(struct target *target); +}; + +static inline struct armv8_common * +target_to_armv8(struct target *target) +{ + return container_of(target->arch_info, struct armv8_common, arm); +} + +/* register offsets from armv8.debug_base */ +#define CPUV8_DBG_MAINID0 0xD00 +#define CPUV8_DBG_CPUFEATURE0 0xD20 +#define CPUV8_DBG_DBGFEATURE0 0xD28 +#define CPUV8_DBG_MEMFEATURE0 0xD38 + +#define CPUV8_DBG_LOCKACCESS 0xFB0 +#define CPUV8_DBG_LOCKSTATUS 0xFB4 + +#define CPUV8_DBG_EDESR 0x20 +#define CPUV8_DBG_EDECR 0x24 +#define CPUV8_DBG_WFAR0 0x30 +#define CPUV8_DBG_WFAR1 0x34 +#define CPUV8_DBG_DSCR 0x088 +#define CPUV8_DBG_DRCR 0x090 +#define CPUV8_DBG_PRCR 0x310 +#define CPUV8_DBG_PRSR 0x314 + +#define CPUV8_DBG_DTRRX 0x080 +#define CPUV8_DBG_ITR 0x084 +#define CPUV8_DBG_SCR 0x088 +#define CPUV8_DBG_DTRTX 0x08c + +#define CPUV8_DBG_BVR_BASE 0x400 +#define CPUV8_DBG_BCR_BASE 0x408 +#define CPUV8_DBG_WVR_BASE 0x800 +#define CPUV8_DBG_WCR_BASE 0x808 +#define CPUV8_DBG_VCR 0x01C + +#define CPUV8_DBG_OSLAR 0x300 + +#define CPUV8_DBG_AUTHSTATUS 0xFB8 + +#define PAGE_SIZE_4KB 0x1000 +#define PAGE_SIZE_4KB_LEVEL0_BITS 39 +#define PAGE_SIZE_4KB_LEVEL1_BITS 30 +#define PAGE_SIZE_4KB_LEVEL2_BITS 21 +#define PAGE_SIZE_4KB_LEVEL3_BITS 12 + +#define PAGE_SIZE_4KB_LEVEL0_MASK ((0x1FFULL) << PAGE_SIZE_4KB_LEVEL0_BITS) +#define PAGE_SIZE_4KB_LEVEL1_MASK ((0x1FFULL) << PAGE_SIZE_4KB_LEVEL1_BITS) +#define PAGE_SIZE_4KB_LEVEL2_MASK ((0x1FFULL) << PAGE_SIZE_4KB_LEVEL2_BITS) +#define PAGE_SIZE_4KB_LEVEL3_MASK ((0x1FFULL) << PAGE_SIZE_4KB_LEVEL3_BITS) + +#define PAGE_SIZE_4KB_TRBBASE_MASK 0xFFFFFFFFF000 + +int armv8_arch_state(struct target *target); +int armv8_read_mpidr(struct armv8_common *armv8); +int armv8_identify_cache(struct armv8_common *armv8); +int armv8_init_arch_info(struct target *target, struct armv8_common *armv8); +int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va, + target_addr_t *val, int meminfo); +int armv8_mmu_translate_va(struct target *target, target_addr_t va, target_addr_t *val); + +int armv8_handle_cache_info_command(struct command_context *cmd_ctx, + struct armv8_cache_common *armv8_cache); + +void armv8_set_cpsr(struct arm *arm, uint32_t cpsr); + +static inline unsigned int armv8_curel_from_core_mode(enum arm_mode core_mode) +{ + switch (core_mode) { + /* Aarch32 modes */ + case ARM_MODE_USR: + return 0; + case ARM_MODE_SVC: + case ARM_MODE_ABT: /* FIXME: EL3? */ + case ARM_MODE_IRQ: /* FIXME: EL3? */ + case ARM_MODE_FIQ: /* FIXME: EL3? */ + case ARM_MODE_UND: /* FIXME: EL3? */ + case ARM_MODE_SYS: /* FIXME: EL3? */ + return 1; + /* case ARM_MODE_HYP: + * return 2; + */ + case ARM_MODE_MON: + return 3; + /* all Aarch64 modes */ + default: + return (core_mode >> 6) & 3; + } +} + +void armv8_select_reg_access(struct armv8_common *armv8, bool is_aarch64); +int armv8_set_dbgreg_bits(struct armv8_common *armv8, unsigned int reg, unsigned long mask, unsigned long value); + +extern const struct command_registration armv8_command_handlers[]; + +#endif /* OPENOCD_TARGET_ARMV8_H */ diff --git a/src/target/armv8_cache.c b/src/target/armv8_cache.c new file mode 100644 index 00000000..7f610c95 --- /dev/null +++ b/src/target/armv8_cache.c @@ -0,0 +1,423 @@ +/*************************************************************************** + * Copyright (C) 2016 by Matthias Welwarsky * + * matthias.welwarsky@sysgo.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 "armv8_cache.h" +#include "armv8_dpm.h" +#include "armv8_opcodes.h" + +/* CLIDR cache types */ +#define CACHE_LEVEL_HAS_UNIFIED_CACHE 0x4 +#define CACHE_LEVEL_HAS_D_CACHE 0x2 +#define CACHE_LEVEL_HAS_I_CACHE 0x1 + +static int armv8_d_cache_sanity_check(struct armv8_common *armv8) +{ + struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache; + + if (armv8_cache->d_u_cache_enabled) + return ERROR_OK; + + return ERROR_TARGET_INVALID; +} + +static int armv8_i_cache_sanity_check(struct armv8_common *armv8) +{ + struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache; + + if (armv8_cache->i_cache_enabled) + return ERROR_OK; + + return ERROR_TARGET_INVALID; +} + +static int armv8_cache_d_inner_flush_level(struct armv8_common *armv8, struct armv8_cachesize *size, int cl) +{ + struct arm_dpm *dpm = armv8->arm.dpm; + int retval = ERROR_OK; + int32_t c_way, c_index = size->index; + + LOG_DEBUG("cl %" PRId32, cl); + do { + c_way = size->way; + do { + uint32_t value = (c_index << size->index_shift) + | (c_way << size->way_shift) | (cl << 1); + /* + * DC CISW - Clean and invalidate data cache + * line by Set/Way. + */ + retval = dpm->instr_write_data_r0(dpm, + armv8_opcode(armv8, ARMV8_OPC_DCCISW), value); + if (retval != ERROR_OK) + goto done; + c_way -= 1; + } while (c_way >= 0); + c_index -= 1; + } while (c_index >= 0); + + done: + return retval; +} + +static int armv8_cache_d_inner_clean_inval_all(struct armv8_common *armv8) +{ + struct armv8_cache_common *cache = &(armv8->armv8_mmu.armv8_cache); + struct arm_dpm *dpm = armv8->arm.dpm; + int cl; + int retval; + + retval = armv8_d_cache_sanity_check(armv8); + if (retval != ERROR_OK) + return retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + + for (cl = 0; cl < cache->loc; cl++) { + /* skip i-only caches */ + if (cache->arch[cl].ctype < CACHE_LEVEL_HAS_D_CACHE) + continue; + + armv8_cache_d_inner_flush_level(armv8, &cache->arch[cl].d_u_size, cl); + } + + retval = dpm->finish(dpm); + return retval; + +done: + LOG_ERROR("clean invalidate failed"); + dpm->finish(dpm); + + return retval; +} + +int armv8_cache_d_inner_flush_virt(struct armv8_common *armv8, target_addr_t va, size_t size) +{ + struct arm_dpm *dpm = armv8->arm.dpm; + struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache; + uint64_t linelen = armv8_cache->dminline; + target_addr_t va_line, va_end; + int retval; + + retval = armv8_d_cache_sanity_check(armv8); + if (retval != ERROR_OK) + return retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + + va_line = va & (-linelen); + va_end = va + size; + + while (va_line < va_end) { + /* DC CIVAC */ + /* Aarch32: DCCIMVAC: ARMV4_5_MCR(15, 0, 0, 7, 14, 1) */ + retval = dpm->instr_write_data_r0_64(dpm, + armv8_opcode(armv8, ARMV8_OPC_DCCIVAC), va_line); + if (retval != ERROR_OK) + goto done; + va_line += linelen; + } + + dpm->finish(dpm); + return retval; + +done: + LOG_ERROR("d-cache invalidate failed"); + dpm->finish(dpm); + + return retval; +} + +int armv8_cache_i_inner_inval_virt(struct armv8_common *armv8, target_addr_t va, size_t size) +{ + struct arm_dpm *dpm = armv8->arm.dpm; + struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache; + uint64_t linelen = armv8_cache->iminline; + target_addr_t va_line, va_end; + int retval; + + retval = armv8_i_cache_sanity_check(armv8); + if (retval != ERROR_OK) + return retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + + va_line = va & (-linelen); + va_end = va + size; + + while (va_line < va_end) { + /* IC IVAU - Invalidate instruction cache by VA to PoU. */ + retval = dpm->instr_write_data_r0_64(dpm, + armv8_opcode(armv8, ARMV8_OPC_ICIVAU), va_line); + if (retval != ERROR_OK) + goto done; + va_line += linelen; + } + + dpm->finish(dpm); + return retval; + +done: + LOG_ERROR("d-cache invalidate failed"); + dpm->finish(dpm); + + return retval; +} + +static int armv8_handle_inner_cache_info_command(struct command_context *cmd_ctx, + struct armv8_cache_common *armv8_cache) +{ + int cl; + + if (armv8_cache->info == -1) { + command_print(cmd_ctx, "cache not yet identified"); + return ERROR_OK; + } + + for (cl = 0; cl < armv8_cache->loc; cl++) { + struct armv8_arch_cache *arch = &(armv8_cache->arch[cl]); + + if (arch->ctype & 1) { + command_print(cmd_ctx, + "L%d I-Cache: linelen %" PRIi32 + ", associativity %" PRIi32 + ", nsets %" PRIi32 + ", cachesize %" PRId32 " KBytes", + cl+1, + arch->i_size.linelen, + arch->i_size.associativity, + arch->i_size.nsets, + arch->i_size.cachesize); + } + + if (arch->ctype >= 2) { + command_print(cmd_ctx, + "L%d D-Cache: linelen %" PRIi32 + ", associativity %" PRIi32 + ", nsets %" PRIi32 + ", cachesize %" PRId32 " KBytes", + cl+1, + arch->d_u_size.linelen, + arch->d_u_size.associativity, + arch->d_u_size.nsets, + arch->d_u_size.cachesize); + } + } + + return ERROR_OK; +} + +static int _armv8_flush_all_data(struct target *target) +{ + return armv8_cache_d_inner_clean_inval_all(target_to_armv8(target)); +} + +static int armv8_flush_all_data(struct target *target) +{ + int retval = ERROR_FAIL; + /* check that armv8_cache is correctly identify */ + struct armv8_common *armv8 = target_to_armv8(target); + if (armv8->armv8_mmu.armv8_cache.info == -1) { + LOG_ERROR("trying to flush un-identified cache"); + return retval; + } + + if (target->smp) { + /* look if all the other target have been flushed in order to flush level + * 2 */ + struct target_list *head; + struct target *curr; + head = target->head; + while (head != (struct target_list *)NULL) { + curr = head->target; + if (curr->state == TARGET_HALTED) { + LOG_INFO("Wait flushing data l1 on core %" PRId32, curr->coreid); + retval = _armv8_flush_all_data(curr); + } + head = head->next; + } + } else + retval = _armv8_flush_all_data(target); + return retval; +} + +static int get_cache_info(struct arm_dpm *dpm, int cl, int ct, uint32_t *cache_reg) +{ + struct armv8_common *armv8 = dpm->arm->arch_info; + int retval = ERROR_OK; + + /* select cache level */ + retval = dpm->instr_write_data_r0(dpm, + armv8_opcode(armv8, WRITE_REG_CSSELR), + (cl << 1) | (ct == 1 ? 1 : 0)); + if (retval != ERROR_OK) + goto done; + + retval = dpm->instr_read_data_r0(dpm, + armv8_opcode(armv8, READ_REG_CCSIDR), + cache_reg); + done: + return retval; +} + +static struct armv8_cachesize decode_cache_reg(uint32_t cache_reg) +{ + struct armv8_cachesize size; + int i = 0; + + size.linelen = 16 << (cache_reg & 0x7); + size.associativity = ((cache_reg >> 3) & 0x3ff) + 1; + size.nsets = ((cache_reg >> 13) & 0x7fff) + 1; + size.cachesize = size.linelen * size.associativity * size.nsets / 1024; + + /* compute info for set way operation on cache */ + size.index_shift = (cache_reg & 0x7) + 4; + size.index = (cache_reg >> 13) & 0x7fff; + size.way = ((cache_reg >> 3) & 0x3ff); + + while (((size.way << i) & 0x80000000) == 0) + i++; + size.way_shift = i; + + return size; +} + +int armv8_identify_cache(struct armv8_common *armv8) +{ + /* read cache descriptor */ + int retval = ERROR_FAIL; + struct arm_dpm *dpm = armv8->arm.dpm; + uint32_t csselr, clidr, ctr; + uint32_t cache_reg; + int cl, ctype; + struct armv8_cache_common *cache = &(armv8->armv8_mmu.armv8_cache); + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + + /* retrieve CTR */ + retval = dpm->instr_read_data_r0(dpm, + armv8_opcode(armv8, READ_REG_CTR), &ctr); + if (retval != ERROR_OK) + goto done; + + cache->iminline = 4UL << (ctr & 0xf); + cache->dminline = 4UL << ((ctr & 0xf0000) >> 16); + LOG_DEBUG("ctr %" PRIx32 " ctr.iminline %" PRId32 " ctr.dminline %" PRId32, + ctr, cache->iminline, cache->dminline); + + /* retrieve CLIDR */ + retval = dpm->instr_read_data_r0(dpm, + armv8_opcode(armv8, READ_REG_CLIDR), &clidr); + if (retval != ERROR_OK) + goto done; + + cache->loc = (clidr & 0x7000000) >> 24; + LOG_DEBUG("Number of cache levels to PoC %" PRId32, cache->loc); + + /* retrieve selected cache for later restore + * MRC p15, 2,, c0, c0, 0; Read CSSELR */ + retval = dpm->instr_read_data_r0(dpm, + armv8_opcode(armv8, READ_REG_CSSELR), &csselr); + if (retval != ERROR_OK) + goto done; + + /* retrieve all available inner caches */ + for (cl = 0; cl < cache->loc; clidr >>= 3, cl++) { + + /* isolate cache type at current level */ + ctype = clidr & 7; + + /* skip reserved values */ + if (ctype > CACHE_LEVEL_HAS_UNIFIED_CACHE) + continue; + + /* separate d or unified d/i cache at this level ? */ + if (ctype & (CACHE_LEVEL_HAS_UNIFIED_CACHE | CACHE_LEVEL_HAS_D_CACHE)) { + /* retrieve d-cache info */ + retval = get_cache_info(dpm, cl, 0, &cache_reg); + if (retval != ERROR_OK) + goto done; + cache->arch[cl].d_u_size = decode_cache_reg(cache_reg); + + LOG_DEBUG("data/unified cache index %d << %d, way %d << %d", + cache->arch[cl].d_u_size.index, + cache->arch[cl].d_u_size.index_shift, + cache->arch[cl].d_u_size.way, + cache->arch[cl].d_u_size.way_shift); + + LOG_DEBUG("cacheline %d bytes %d KBytes asso %d ways", + cache->arch[cl].d_u_size.linelen, + cache->arch[cl].d_u_size.cachesize, + cache->arch[cl].d_u_size.associativity); + } + + /* separate i-cache at this level ? */ + if (ctype & CACHE_LEVEL_HAS_I_CACHE) { + /* retrieve i-cache info */ + retval = get_cache_info(dpm, cl, 1, &cache_reg); + if (retval != ERROR_OK) + goto done; + cache->arch[cl].i_size = decode_cache_reg(cache_reg); + + LOG_DEBUG("instruction cache index %d << %d, way %d << %d", + cache->arch[cl].i_size.index, + cache->arch[cl].i_size.index_shift, + cache->arch[cl].i_size.way, + cache->arch[cl].i_size.way_shift); + + LOG_DEBUG("cacheline %d bytes %d KBytes asso %d ways", + cache->arch[cl].i_size.linelen, + cache->arch[cl].i_size.cachesize, + cache->arch[cl].i_size.associativity); + } + + cache->arch[cl].ctype = ctype; + } + + /* restore selected cache */ + dpm->instr_write_data_r0(dpm, + armv8_opcode(armv8, WRITE_REG_CSSELR), csselr); + if (retval != ERROR_OK) + goto done; + + armv8->armv8_mmu.armv8_cache.info = 1; + + /* if no l2 cache initialize l1 data cache flush function function */ + if (armv8->armv8_mmu.armv8_cache.flush_all_data_cache == NULL) { + armv8->armv8_mmu.armv8_cache.display_cache_info = + armv8_handle_inner_cache_info_command; + armv8->armv8_mmu.armv8_cache.flush_all_data_cache = + armv8_flush_all_data; + } + +done: + dpm->finish(dpm); + return retval; + +} diff --git a/src/target/armv8_cache.h b/src/target/armv8_cache.h new file mode 100644 index 00000000..fa46e16d --- /dev/null +++ b/src/target/armv8_cache.h @@ -0,0 +1,26 @@ +/*************************************************************************** + * Copyright (C) 2016 by Matthias Welwarsky * + * matthias.welwarsky@sysgo.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 . * + ***************************************************************************/ +#ifndef OPENOCD_TARGET_ARMV8_CACHE_H_ +#define OPENOCD_TARGET_ARMV8_CACHE_H_ + +#include "armv8.h" + +extern int armv8_cache_d_inner_flush_virt(struct armv8_common *armv8, target_addr_t va, size_t size); +extern int armv8_cache_i_inner_inval_virt(struct armv8_common *armv8, target_addr_t va, size_t size); + +#endif /* OPENOCD_TARGET_ARMV8_CACHE_H_ */ diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c new file mode 100644 index 00000000..f4e7a079 --- /dev/null +++ b/src/target/armv8_dpm.c @@ -0,0 +1,1472 @@ +/* + * Copyright (C) 2009 by David Brownell + * + * 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. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm.h" +#include "armv8.h" +#include "armv8_dpm.h" +#include +#include "register.h" +#include "breakpoints.h" +#include "target_type.h" +#include "armv8_opcodes.h" + +#include "helper/time_support.h" + +/* T32 ITR format */ +#define T32_FMTITR(instr) (((instr & 0x0000FFFF) << 16) | ((instr & 0xFFFF0000) >> 16)) + +/** + * @file + * Implements various ARM DPM operations using architectural debug registers. + * These routines layer over core-specific communication methods to cope with + * implementation differences between cores like ARM1136 and Cortex-A8. + * + * The "Debug Programmers' Model" (DPM) for ARMv6 and ARMv7 is defined by + * Part C (Debug Architecture) of the ARM Architecture Reference Manual, + * ARMv7-A and ARMv7-R edition (ARM DDI 0406B). In OpenOCD, DPM operations + * are abstracted through internal programming interfaces to share code and + * to minimize needless differences in debug behavior between cores. + */ + +/** + * Get core state from EDSCR, without necessity to retrieve CPSR + */ +enum arm_state armv8_dpm_get_core_state(struct arm_dpm *dpm) +{ + int el = (dpm->dscr >> 8) & 0x3; + int rw = (dpm->dscr >> 10) & 0xF; + + dpm->last_el = el; + + /* In Debug state, each bit gives the current Execution state of each EL */ + if ((rw >> el) & 0b1) + return ARM_STATE_AARCH64; + + return ARM_STATE_ARM; +} + +/*----------------------------------------------------------------------*/ + +static int dpmv8_write_dcc(struct armv8_common *armv8, uint32_t data) +{ + return mem_ap_write_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DTRRX, data); +} + +static int dpmv8_write_dcc_64(struct armv8_common *armv8, uint64_t data) +{ + int ret; + ret = mem_ap_write_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DTRRX, data); + if (ret == ERROR_OK) + ret = mem_ap_write_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DTRTX, data >> 32); + return ret; +} + +static int dpmv8_read_dcc(struct armv8_common *armv8, uint32_t *data, + uint32_t *dscr_p) +{ + uint32_t dscr = DSCR_ITE; + int retval; + + if (dscr_p) + dscr = *dscr_p; + + /* Wait for DTRRXfull */ + long long then = timeval_ms(); + while ((dscr & DSCR_DTR_TX_FULL) == 0) { + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, + &dscr); + if (retval != ERROR_OK) + return retval; + if (timeval_ms() > then + 1000) { + LOG_ERROR("Timeout waiting for read dcc"); + return ERROR_FAIL; + } + } + + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DTRTX, + data); + if (retval != ERROR_OK) + return retval; + + if (dscr_p) + *dscr_p = dscr; + + return retval; +} + +static int dpmv8_read_dcc_64(struct armv8_common *armv8, uint64_t *data, + uint32_t *dscr_p) +{ + uint32_t dscr = DSCR_ITE; + uint32_t higher; + int retval; + + if (dscr_p) + dscr = *dscr_p; + + /* Wait for DTRRXfull */ + long long then = timeval_ms(); + while ((dscr & DSCR_DTR_TX_FULL) == 0) { + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, + &dscr); + if (retval != ERROR_OK) + return retval; + if (timeval_ms() > then + 1000) { + LOG_ERROR("Timeout waiting for DTR_TX_FULL, dscr = 0x%08" PRIx32, dscr); + return ERROR_FAIL; + } + } + + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DTRTX, + (uint32_t *)data); + if (retval != ERROR_OK) + return retval; + + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DTRRX, + &higher); + if (retval != ERROR_OK) + return retval; + + *data = *(uint32_t *)data | (uint64_t)higher << 32; + + if (dscr_p) + *dscr_p = dscr; + + return retval; +} + +static int dpmv8_dpm_prepare(struct arm_dpm *dpm) +{ + struct armv8_common *armv8 = dpm->arm->arch_info; + uint32_t dscr; + int retval; + + /* set up invariant: ITE is set after ever DPM operation */ + long long then = timeval_ms(); + for (;; ) { + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, + &dscr); + if (retval != ERROR_OK) + return retval; + if ((dscr & DSCR_ITE) != 0) + break; + if (timeval_ms() > then + 1000) { + LOG_ERROR("Timeout waiting for dpm prepare"); + return ERROR_FAIL; + } + } + + /* update the stored copy of dscr */ + dpm->dscr = dscr; + + /* this "should never happen" ... */ + if (dscr & DSCR_DTR_RX_FULL) { + LOG_ERROR("DSCR_DTR_RX_FULL, dscr 0x%08" PRIx32, dscr); + /* Clear DCCRX */ + retval = mem_ap_read_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DTRRX, &dscr); + if (retval != ERROR_OK) + return retval; + } + + return retval; +} + +static int dpmv8_dpm_finish(struct arm_dpm *dpm) +{ + /* REVISIT what could be done here? */ + return ERROR_OK; +} + +static int dpmv8_exec_opcode(struct arm_dpm *dpm, + uint32_t opcode, uint32_t *p_dscr) +{ + struct armv8_common *armv8 = dpm->arm->arch_info; + uint32_t dscr = dpm->dscr; + int retval; + + if (p_dscr) + dscr = *p_dscr; + + /* Wait for InstrCompl bit to be set */ + long long then = timeval_ms(); + while ((dscr & DSCR_ITE) == 0) { + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, &dscr); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read DSCR register, opcode = 0x%08" PRIx32, opcode); + return retval; + } + if (timeval_ms() > then + 1000) { + LOG_ERROR("Timeout waiting for aarch64_exec_opcode"); + return ERROR_FAIL; + } + } + + if (armv8_dpm_get_core_state(dpm) != ARM_STATE_AARCH64) + opcode = T32_FMTITR(opcode); + + retval = mem_ap_write_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_ITR, opcode); + if (retval != ERROR_OK) + return retval; + + then = timeval_ms(); + do { + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DSCR, &dscr); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read DSCR register"); + return retval; + } + if (timeval_ms() > then + 1000) { + LOG_ERROR("Timeout waiting for aarch64_exec_opcode"); + return ERROR_FAIL; + } + } while ((dscr & DSCR_ITE) == 0); /* Wait for InstrCompl bit to be set */ + + /* update dscr and el after each command execution */ + dpm->dscr = dscr; + if (dpm->last_el != ((dscr >> 8) & 3)) + LOG_DEBUG("EL %i -> %i", dpm->last_el, (dscr >> 8) & 3); + dpm->last_el = (dscr >> 8) & 3; + + 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); + retval = ERROR_FAIL; + } + + if (p_dscr) + *p_dscr = dscr; + + return retval; +} + +static int dpmv8_instr_execute(struct arm_dpm *dpm, uint32_t opcode) +{ + return dpmv8_exec_opcode(dpm, opcode, NULL); +} + +static int dpmv8_instr_write_data_dcc(struct arm_dpm *dpm, + uint32_t opcode, uint32_t data) +{ + struct armv8_common *armv8 = dpm->arm->arch_info; + int retval; + + retval = dpmv8_write_dcc(armv8, data); + if (retval != ERROR_OK) + return retval; + + return dpmv8_exec_opcode(dpm, opcode, 0); +} + +static int dpmv8_instr_write_data_dcc_64(struct arm_dpm *dpm, + uint32_t opcode, uint64_t data) +{ + struct armv8_common *armv8 = dpm->arm->arch_info; + int retval; + + retval = dpmv8_write_dcc_64(armv8, data); + if (retval != ERROR_OK) + return retval; + + return dpmv8_exec_opcode(dpm, opcode, 0); +} + +static int dpmv8_instr_write_data_r0(struct arm_dpm *dpm, + uint32_t opcode, uint32_t data) +{ + struct armv8_common *armv8 = dpm->arm->arch_info; + uint32_t dscr = DSCR_ITE; + int retval; + + retval = dpmv8_write_dcc(armv8, data); + if (retval != ERROR_OK) + return retval; + + retval = dpmv8_exec_opcode(dpm, armv8_opcode(armv8, READ_REG_DTRRX), &dscr); + if (retval != ERROR_OK) + return retval; + + /* then the opcode, taking data from R0 */ + return dpmv8_exec_opcode(dpm, opcode, &dscr); +} + +static int dpmv8_instr_write_data_r0_64(struct arm_dpm *dpm, + uint32_t opcode, uint64_t data) +{ + struct armv8_common *armv8 = dpm->arm->arch_info; + int retval; + + if (dpm->arm->core_state != ARM_STATE_AARCH64) + return dpmv8_instr_write_data_r0(dpm, opcode, data); + + /* transfer data from DCC to R0 */ + retval = dpmv8_write_dcc_64(armv8, data); + if (retval == ERROR_OK) + retval = dpmv8_exec_opcode(dpm, ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, 0), &dpm->dscr); + + /* then the opcode, taking data from R0 */ + if (retval == ERROR_OK) + retval = dpmv8_exec_opcode(dpm, opcode, &dpm->dscr); + + return retval; +} + +static int dpmv8_instr_cpsr_sync(struct arm_dpm *dpm) +{ + int retval; + struct armv8_common *armv8 = dpm->arm->arch_info; + + /* "Prefetch flush" after modifying execution status in CPSR */ + retval = dpmv8_exec_opcode(dpm, armv8_opcode(armv8, ARMV8_OPC_DSB_SY), &dpm->dscr); + if (retval == ERROR_OK) + dpmv8_exec_opcode(dpm, armv8_opcode(armv8, ARMV8_OPC_ISB_SY), &dpm->dscr); + return retval; +} + +static int dpmv8_instr_read_data_dcc(struct arm_dpm *dpm, + uint32_t opcode, uint32_t *data) +{ + struct armv8_common *armv8 = dpm->arm->arch_info; + int retval; + + /* the opcode, writing data to DCC */ + retval = dpmv8_exec_opcode(dpm, opcode, &dpm->dscr); + if (retval != ERROR_OK) + return retval; + + return dpmv8_read_dcc(armv8, data, &dpm->dscr); +} + +static int dpmv8_instr_read_data_dcc_64(struct arm_dpm *dpm, + uint32_t opcode, uint64_t *data) +{ + struct armv8_common *armv8 = dpm->arm->arch_info; + int retval; + + /* the opcode, writing data to DCC */ + retval = dpmv8_exec_opcode(dpm, opcode, &dpm->dscr); + if (retval != ERROR_OK) + return retval; + + return dpmv8_read_dcc_64(armv8, data, &dpm->dscr); +} + +static int dpmv8_instr_read_data_r0(struct arm_dpm *dpm, + uint32_t opcode, uint32_t *data) +{ + struct armv8_common *armv8 = dpm->arm->arch_info; + int retval; + + /* the opcode, writing data to R0 */ + retval = dpmv8_exec_opcode(dpm, opcode, &dpm->dscr); + if (retval != ERROR_OK) + return retval; + + /* write R0 to DCC */ + retval = dpmv8_exec_opcode(dpm, armv8_opcode(armv8, WRITE_REG_DTRTX), &dpm->dscr); + if (retval != ERROR_OK) + return retval; + + return dpmv8_read_dcc(armv8, data, &dpm->dscr); +} + +static int dpmv8_instr_read_data_r0_64(struct arm_dpm *dpm, + uint32_t opcode, uint64_t *data) +{ + struct armv8_common *armv8 = dpm->arm->arch_info; + int retval; + + if (dpm->arm->core_state != ARM_STATE_AARCH64) { + uint32_t tmp; + retval = dpmv8_instr_read_data_r0(dpm, opcode, &tmp); + if (retval == ERROR_OK) + *data = tmp; + return retval; + } + + /* the opcode, writing data to R0 */ + retval = dpmv8_exec_opcode(dpm, opcode, &dpm->dscr); + if (retval != ERROR_OK) + return retval; + + /* write R0 to DCC */ + retval = dpmv8_exec_opcode(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0, 0), &dpm->dscr); + if (retval != ERROR_OK) + return retval; + + return dpmv8_read_dcc_64(armv8, data, &dpm->dscr); +} + +#if 0 +static int dpmv8_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, + target_addr_t addr, uint32_t control) +{ + struct armv8_common *armv8 = dpm->arm->arch_info; + uint32_t vr = armv8->debug_base; + uint32_t cr = armv8->debug_base; + int retval; + + switch (index_t) { + case 0 ... 15: /* breakpoints */ + vr += CPUV8_DBG_BVR_BASE; + cr += CPUV8_DBG_BCR_BASE; + break; + case 16 ... 31: /* watchpoints */ + vr += CPUV8_DBG_WVR_BASE; + cr += CPUV8_DBG_WCR_BASE; + index_t -= 16; + break; + default: + return ERROR_FAIL; + } + vr += 16 * index_t; + cr += 16 * index_t; + + LOG_DEBUG("A8: bpwp enable, vr %08x cr %08x", + (unsigned) vr, (unsigned) cr); + + retval = mem_ap_write_atomic_u32(armv8->debug_ap, vr, addr); + if (retval != ERROR_OK) + return retval; + return mem_ap_write_atomic_u32(armv8->debug_ap, cr, control); +} +#endif + +static int dpmv8_bpwp_disable(struct arm_dpm *dpm, unsigned index_t) +{ + struct armv8_common *armv8 = dpm->arm->arch_info; + uint32_t cr; + + switch (index_t) { + case 0 ... 15: + cr = armv8->debug_base + CPUV8_DBG_BCR_BASE; + break; + case 16 ... 31: + cr = armv8->debug_base + CPUV8_DBG_WCR_BASE; + index_t -= 16; + break; + default: + return ERROR_FAIL; + } + cr += 16 * index_t; + + LOG_DEBUG("A: bpwp disable, cr %08x", (unsigned) cr); + + /* clear control register */ + return mem_ap_write_atomic_u32(armv8->debug_ap, cr, 0); +} + +/* + * Coprocessor support + */ + +/* Read coprocessor */ +static int dpmv8_mrc(struct target *target, int cpnum, + uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, + uint32_t *value) +{ + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = arm->dpm; + int retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("MRC p%d, %d, r0, c%d, c%d, %d", cpnum, + (int) op1, (int) CRn, + (int) CRm, (int) op2); + + /* read coprocessor register into R0; return via DCC */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2), + value); + + /* (void) */ dpm->finish(dpm); + return retval; +} + +static int dpmv8_mcr(struct target *target, int cpnum, + uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, + uint32_t value) +{ + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = arm->dpm; + int retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("MCR p%d, %d, r0, c%d, c%d, %d", cpnum, + (int) op1, (int) CRn, + (int) CRm, (int) op2); + + /* read DCC into r0; then write coprocessor register from R0 */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2), + value); + + /* (void) */ dpm->finish(dpm); + return retval; +} + +/*----------------------------------------------------------------------*/ + +/* + * Register access utilities + */ + +int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) +{ + struct armv8_common *armv8 = (struct armv8_common *)dpm->arm->arch_info; + int retval = ERROR_OK; + unsigned int target_el; + enum arm_state core_state; + uint32_t cpsr; + + /* restore previous mode */ + if (mode == ARM_MODE_ANY) { + cpsr = buf_get_u32(dpm->arm->cpsr->value, 0, 32); + + LOG_DEBUG("restoring mode, cpsr = 0x%08"PRIx32, cpsr); + + } else { + LOG_DEBUG("setting mode 0x%"PRIx32, mode); + + /* else force to the specified mode */ + if (is_arm_mode(mode)) + cpsr = mode; + else + cpsr = mode >> 4; + } + + switch (cpsr & 0x1f) { + /* aarch32 modes */ + case ARM_MODE_USR: + target_el = 0; + break; + case ARM_MODE_SVC: + case ARM_MODE_ABT: + case ARM_MODE_IRQ: + case ARM_MODE_FIQ: + target_el = 1; + break; + /* + * TODO: handle ARM_MODE_HYP + * case ARM_MODE_HYP: + * target_el = 2; + * break; + */ + case ARM_MODE_MON: + target_el = 3; + break; + /* aarch64 modes */ + default: + target_el = (cpsr >> 2) & 3; + } + + if (target_el > SYSTEM_CUREL_EL3) { + LOG_ERROR("%s: Invalid target exception level %i", __func__, target_el); + return ERROR_FAIL; + } + + LOG_DEBUG("target_el = %i, last_el = %i", target_el, dpm->last_el); + if (target_el > dpm->last_el) { + retval = dpm->instr_execute(dpm, + armv8_opcode(armv8, ARMV8_OPC_DCPS) | target_el); + + /* DCPS clobbers registers just like an exception taken */ + armv8_dpm_handle_exception(dpm); + } else { + core_state = armv8_dpm_get_core_state(dpm); + if (core_state != ARM_STATE_AARCH64) { + /* cannot do DRPS/ERET when already in EL0 */ + if (dpm->last_el != 0) { + /* load SPSR with the desired mode and execute DRPS */ + LOG_DEBUG("SPSR = 0x%08"PRIx32, cpsr); + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP_xPSR_T1(1, 0, 15), cpsr); + if (retval == ERROR_OK) + retval = dpm->instr_execute(dpm, armv8_opcode(armv8, ARMV8_OPC_DRPS)); + } + } else { + /* + * need to execute multiple DRPS instructions until target_el + * is reached + */ + while (retval == ERROR_OK && dpm->last_el != target_el) { + unsigned int cur_el = dpm->last_el; + retval = dpm->instr_execute(dpm, armv8_opcode(armv8, ARMV8_OPC_DRPS)); + if (cur_el == dpm->last_el) { + LOG_INFO("Cannot reach EL %i, SPSR corrupted?", target_el); + break; + } + } + } + + /* On executing DRPS, DSPSR and DLR become UNKNOWN, mark them as dirty */ + dpm->arm->cpsr->dirty = true; + dpm->arm->pc->dirty = true; + + /* + * re-evaluate the core state, we might be in Aarch32 state now + * we rely on dpm->dscr being up-to-date + */ + core_state = armv8_dpm_get_core_state(dpm); + armv8_select_opcodes(armv8, core_state == ARM_STATE_AARCH64); + armv8_select_reg_access(armv8, core_state == ARM_STATE_AARCH64); + } + + return retval; +} + +/* + * Common register read, relies on armv8_select_reg_access() having been called. + */ +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; + + 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); + } + return ERROR_OK; +} + +/* + * Common register write, relies on armv8_select_reg_access() having been called. + */ +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); + + 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); + } + + return ERROR_OK; +} + +/** + * Read basic registers of the the current context: R0 to R15, and CPSR; + * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb). + * In normal operation this is called on entry to halting debug state, + * possibly after some other operations supporting restore of debug state + * or making sure the CPU is fully idle (drain write buffer, etc). + */ +int armv8_dpm_read_current_registers(struct arm_dpm *dpm) +{ + struct arm *arm = dpm->arm; + struct armv8_common *armv8 = (struct armv8_common *)arm->arch_info; + struct reg_cache *cache; + struct reg *r; + uint32_t cpsr; + int retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + return retval; + + cache = arm->core_cache; + + /* read R0 first (it's used for scratch), then CPSR */ + r = cache->reg_list + ARMV8_R0; + if (!r->valid) { + retval = dpmv8_read_reg(dpm, r, ARMV8_R0); + if (retval != ERROR_OK) + goto fail; + } + r->dirty = true; + + /* read R1, too, it will be clobbered during memory access */ + r = cache->reg_list + ARMV8_R1; + if (!r->valid) { + retval = dpmv8_read_reg(dpm, r, ARMV8_R1); + if (retval != ERROR_OK) + goto fail; + } + + /* read cpsr to r0 and get it back */ + retval = dpm->instr_read_data_r0(dpm, + armv8_opcode(armv8, READ_REG_DSPSR), &cpsr); + if (retval != ERROR_OK) + goto fail; + + /* update core mode and state */ + armv8_set_cpsr(arm, cpsr); + + for (unsigned int i = ARMV8_PC; i < cache->num_regs ; i++) { + struct arm_reg *arm_reg; + + r = armv8_reg_current(arm, i); + if (r->valid) + continue; + + /* + * Only read registers that are available from the + * current EL (or core mode). + */ + arm_reg = r->arch_info; + if (arm_reg->mode != ARM_MODE_ANY && + dpm->last_el != armv8_curel_from_core_mode(arm_reg->mode)) + continue; + + retval = dpmv8_read_reg(dpm, r, i); + if (retval != ERROR_OK) + goto fail; + + } + +fail: + dpm->finish(dpm); + return retval; +} + +/* Avoid needless I/O ... leave breakpoints and watchpoints alone + * unless they're removed, or need updating because of single-stepping + * or running debugger code. + */ +static int dpmv8_maybe_update_bpwp(struct arm_dpm *dpm, bool bpwp, + struct dpm_bpwp *xp, int *set_p) +{ + int retval = ERROR_OK; + bool disable; + + if (!set_p) { + if (!xp->dirty) + goto done; + xp->dirty = false; + /* removed or startup; we must disable it */ + disable = true; + } else if (bpwp) { + if (!xp->dirty) + goto done; + /* disabled, but we must set it */ + xp->dirty = disable = false; + *set_p = true; + } else { + if (!*set_p) + goto done; + /* set, but we must temporarily disable it */ + xp->dirty = disable = true; + *set_p = false; + } + + if (disable) + retval = dpm->bpwp_disable(dpm, xp->number); + else + retval = dpm->bpwp_enable(dpm, xp->number, + xp->address, xp->control); + + if (retval != ERROR_OK) + LOG_ERROR("%s: can't %s HW %spoint %d", + disable ? "disable" : "enable", + target_name(dpm->arm->target), + (xp->number < 16) ? "break" : "watch", + xp->number & 0xf); +done: + return retval; +} + +static int dpmv8_add_breakpoint(struct target *target, struct breakpoint *bp); + +/** + * Writes all modified core registers for all processor modes. In normal + * operation this is called on exit from halting debug state. + * + * @param dpm: represents the processor + * @param bpwp: true ensures breakpoints and watchpoints are set, + * false ensures they are cleared + */ +int armv8_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) +{ + struct arm *arm = dpm->arm; + struct reg_cache *cache = arm->core_cache; + int retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + + /* If we're managing hardware breakpoints for this core, enable + * or disable them as requested. + * + * REVISIT We don't yet manage them for ANY cores. Eventually + * we should be able to assume we handle them; but until then, + * cope with the hand-crafted breakpoint code. + */ + if (arm->target->type->add_breakpoint == dpmv8_add_breakpoint) { + for (unsigned i = 0; i < dpm->nbp; i++) { + struct dpm_bp *dbp = dpm->dbp + i; + struct breakpoint *bp = dbp->bp; + + retval = dpmv8_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp, + bp ? &bp->set : NULL); + if (retval != ERROR_OK) + goto done; + } + } + + /* enable/disable watchpoints */ + for (unsigned i = 0; i < dpm->nwp; i++) { + struct dpm_wp *dwp = dpm->dwp + i; + struct watchpoint *wp = dwp->wp; + + retval = dpmv8_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp, + wp ? &wp->set : NULL); + if (retval != ERROR_OK) + goto done; + } + + /* NOTE: writes to breakpoint and watchpoint registers might + * be queued, and need (efficient/batched) flushing later. + */ + + /* Restore original core mode and state */ + retval = armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); + if (retval != ERROR_OK) + goto done; + + /* check everything except our scratch register R0 */ + for (unsigned i = 1; i < cache->num_regs; i++) { + struct arm_reg *r; + + /* skip PC and CPSR */ + if (i == ARMV8_PC || i == ARMV8_xPSR) + continue; + /* skip invalid */ + if (!cache->reg_list[i].valid) + continue; + /* skip non-dirty */ + if (!cache->reg_list[i].dirty) + continue; + + /* skip all registers not on the current EL */ + r = cache->reg_list[i].arch_info; + if (r->mode != ARM_MODE_ANY && + dpm->last_el != armv8_curel_from_core_mode(r->mode)) + continue; + + retval = dpmv8_write_reg(dpm, &cache->reg_list[i], i); + if (retval != ERROR_OK) + break; + } + + /* flush CPSR and PC */ + if (retval == ERROR_OK) + retval = dpmv8_write_reg(dpm, &cache->reg_list[ARMV8_xPSR], ARMV8_xPSR); + if (retval == ERROR_OK) + retval = dpmv8_write_reg(dpm, &cache->reg_list[ARMV8_PC], ARMV8_PC); + /* flush R0 -- it's *very* dirty by now */ + if (retval == ERROR_OK) + retval = dpmv8_write_reg(dpm, &cache->reg_list[0], 0); + if (retval == ERROR_OK) + dpm->instr_cpsr_sync(dpm); +done: + dpm->finish(dpm); + return retval; +} + +/* + * Standard ARM register accessors ... there are three methods + * in "struct arm", to support individual read/write and bulk read + * of registers. + */ + +static int armv8_dpm_read_core_reg(struct target *target, struct reg *r, + int regnum, enum arm_mode mode) +{ + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = target_to_arm(target)->dpm; + int retval; + int max = arm->core_cache->num_regs; + + if (regnum < 0 || regnum >= max) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* + * REVISIT what happens if we try to read SPSR in a core mode + * which has no such register? + */ + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + return retval; + + retval = dpmv8_read_reg(dpm, r, regnum); + if (retval != ERROR_OK) + goto fail; + +fail: + /* (void) */ dpm->finish(dpm); + return retval; +} + +static int armv8_dpm_write_core_reg(struct target *target, struct reg *r, + int regnum, enum arm_mode mode, uint8_t *value) +{ + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = target_to_arm(target)->dpm; + int retval; + int max = arm->core_cache->num_regs; + + if (regnum < 0 || regnum > max) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* REVISIT what happens if we try to write SPSR in a core mode + * which has no such register? + */ + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + return retval; + + retval = dpmv8_write_reg(dpm, r, regnum); + + /* always clean up, regardless of error */ + dpm->finish(dpm); + + return retval; +} + +static int armv8_dpm_full_context(struct target *target) +{ + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = arm->dpm; + struct reg_cache *cache = arm->core_cache; + int retval; + bool did_read; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + + do { + enum arm_mode mode = ARM_MODE_ANY; + + did_read = false; + + /* We "know" arm_dpm_read_current_registers() was called so + * the unmapped registers (R0..R7, PC, AND CPSR) and some + * view of R8..R14 are current. We also "know" oddities of + * register mapping: special cases for R8..R12 and SPSR. + * + * Pick some mode with unread registers and read them all. + * Repeat until done. + */ + for (unsigned i = 0; i < cache->num_regs; i++) { + struct arm_reg *r; + + if (cache->reg_list[i].valid) + continue; + r = cache->reg_list[i].arch_info; + + /* may need to pick a mode and set CPSR */ + if (!did_read) { + did_read = true; + mode = r->mode; + + /* For regular (ARM_MODE_ANY) R8..R12 + * in case we've entered debug state + * in FIQ mode we need to patch mode. + */ + if (mode != ARM_MODE_ANY) + retval = armv8_dpm_modeswitch(dpm, mode); + else + retval = armv8_dpm_modeswitch(dpm, ARM_MODE_USR); + + if (retval != ERROR_OK) + goto done; + } + if (r->mode != mode) + continue; + + /* CPSR was read, so "R16" must mean SPSR */ + retval = dpmv8_read_reg(dpm, + &cache->reg_list[i], + (r->num == 16) ? 17 : r->num); + if (retval != ERROR_OK) + goto done; + } + + } while (did_read); + + retval = armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); + /* (void) */ dpm->finish(dpm); +done: + return retval; +} + + +/*----------------------------------------------------------------------*/ + +/* + * Breakpoint and Watchpoint support. + * + * Hardware {break,watch}points are usually left active, to minimize + * debug entry/exit costs. When they are set or cleared, it's done in + * batches. Also, DPM-conformant hardware can update debug registers + * regardless of whether the CPU is running or halted ... though that + * fact isn't currently leveraged. + */ + +static int dpmv8_bpwp_setup(struct arm_dpm *dpm, struct dpm_bpwp *xp, + uint32_t addr, uint32_t length) +{ + uint32_t control; + + control = (1 << 0) /* enable */ + | (3 << 1); /* both user and privileged access */ + + /* Match 1, 2, or all 4 byte addresses in this word. + * + * FIXME: v7 hardware allows lengths up to 2 GB for BP and WP. + * Support larger length, when addr is suitably aligned. In + * particular, allow watchpoints on 8 byte "double" values. + * + * REVISIT allow watchpoints on unaligned 2-bit values; and on + * v7 hardware, unaligned 4-byte ones too. + */ + switch (length) { + case 1: + control |= (1 << (addr & 3)) << 5; + break; + case 2: + /* require 2-byte alignment */ + if (!(addr & 1)) { + control |= (3 << (addr & 2)) << 5; + break; + } + /* FALL THROUGH */ + case 4: + /* require 4-byte alignment */ + if (!(addr & 3)) { + control |= 0xf << 5; + break; + } + /* FALL THROUGH */ + default: + LOG_ERROR("unsupported {break,watch}point length/alignment"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + /* other shared control bits: + * bits 15:14 == 0 ... both secure and nonsecure states (v6.1+ only) + * bit 20 == 0 ... not linked to a context ID + * bit 28:24 == 0 ... not ignoring N LSBs (v7 only) + */ + + xp->address = addr & ~3; + xp->control = control; + xp->dirty = true; + + LOG_DEBUG("BPWP: addr %8.8" PRIx32 ", control %" PRIx32 ", number %d", + xp->address, control, xp->number); + + /* hardware is updated in write_dirty_registers() */ + return ERROR_OK; +} + +static int dpmv8_add_breakpoint(struct target *target, struct breakpoint *bp) +{ + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = arm->dpm; + int retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + + if (bp->length < 2) + return ERROR_COMMAND_SYNTAX_ERROR; + if (!dpm->bpwp_enable) + return retval; + + /* FIXME we need a generic solution for software breakpoints. */ + if (bp->type == BKPT_SOFT) + LOG_DEBUG("using HW bkpt, not SW..."); + + for (unsigned i = 0; i < dpm->nbp; i++) { + if (!dpm->dbp[i].bp) { + retval = dpmv8_bpwp_setup(dpm, &dpm->dbp[i].bpwp, + bp->address, bp->length); + if (retval == ERROR_OK) + dpm->dbp[i].bp = bp; + break; + } + } + + return retval; +} + +static int dpmv8_remove_breakpoint(struct target *target, struct breakpoint *bp) +{ + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = arm->dpm; + int retval = ERROR_COMMAND_SYNTAX_ERROR; + + for (unsigned i = 0; i < dpm->nbp; i++) { + if (dpm->dbp[i].bp == bp) { + dpm->dbp[i].bp = NULL; + dpm->dbp[i].bpwp.dirty = true; + + /* hardware is updated in write_dirty_registers() */ + retval = ERROR_OK; + break; + } + } + + return retval; +} + +static int dpmv8_watchpoint_setup(struct arm_dpm *dpm, unsigned index_t, + struct watchpoint *wp) +{ + int retval; + struct dpm_wp *dwp = dpm->dwp + index_t; + uint32_t control; + + /* this hardware doesn't support data value matching or masking */ + if (wp->value || wp->mask != ~(uint32_t)0) { + LOG_DEBUG("watchpoint values and masking not supported"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + retval = dpmv8_bpwp_setup(dpm, &dwp->bpwp, wp->address, wp->length); + if (retval != ERROR_OK) + return retval; + + control = dwp->bpwp.control; + switch (wp->rw) { + case WPT_READ: + control |= 1 << 3; + break; + case WPT_WRITE: + control |= 2 << 3; + break; + case WPT_ACCESS: + control |= 3 << 3; + break; + } + dwp->bpwp.control = control; + + dpm->dwp[index_t].wp = wp; + + return retval; +} + +static int dpmv8_add_watchpoint(struct target *target, struct watchpoint *wp) +{ + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = arm->dpm; + int retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + + if (dpm->bpwp_enable) { + for (unsigned i = 0; i < dpm->nwp; i++) { + if (!dpm->dwp[i].wp) { + retval = dpmv8_watchpoint_setup(dpm, i, wp); + break; + } + } + } + + return retval; +} + +static int dpmv8_remove_watchpoint(struct target *target, struct watchpoint *wp) +{ + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = arm->dpm; + int retval = ERROR_COMMAND_SYNTAX_ERROR; + + for (unsigned i = 0; i < dpm->nwp; i++) { + if (dpm->dwp[i].wp == wp) { + dpm->dwp[i].wp = NULL; + dpm->dwp[i].bpwp.dirty = true; + + /* hardware is updated in write_dirty_registers() */ + retval = ERROR_OK; + break; + } + } + + return retval; +} + +void armv8_dpm_report_wfar(struct arm_dpm *dpm, uint64_t addr) +{ + switch (dpm->arm->core_state) { + case ARM_STATE_ARM: + case ARM_STATE_AARCH64: + addr -= 8; + break; + case ARM_STATE_THUMB: + case ARM_STATE_THUMB_EE: + addr -= 4; + break; + case ARM_STATE_JAZELLE: + /* ?? */ + break; + default: + LOG_DEBUG("Unknown core_state"); + break; + } + dpm->wp_pc = addr; +} + +/* + * Handle exceptions taken in debug state. This happens mostly for memory + * accesses that violated a MMU policy. Taking an exception while in debug + * state clobbers certain state registers on the target exception level. + * Just mark those registers dirty so that they get restored on resume. + * This works both for Aarch32 and Aarch64 states. + * + * 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) +{ + struct armv8_common *armv8 = dpm->arm->arch_info; + struct reg_cache *cache = dpm->arm->core_cache; + enum arm_state core_state; + uint64_t dlr; + uint32_t dspsr; + unsigned int el; + + static const int clobbered_regs_by_el[3][5] = { + { ARMV8_PC, ARMV8_xPSR, ARMV8_ELR_EL1, ARMV8_ESR_EL1, ARMV8_SPSR_EL1 }, + { ARMV8_PC, ARMV8_xPSR, ARMV8_ELR_EL2, ARMV8_ESR_EL2, ARMV8_SPSR_EL2 }, + { ARMV8_PC, ARMV8_xPSR, ARMV8_ELR_EL3, ARMV8_ESR_EL3, ARMV8_SPSR_EL3 }, + }; + + el = (dpm->dscr >> 8) & 3; + + /* safety check, must not happen since EL0 cannot be a target for an exception */ + if (el < SYSTEM_CUREL_EL1 || el > SYSTEM_CUREL_EL3) { + LOG_ERROR("%s: EL %i is invalid, DSCR corrupted?", __func__, el); + return; + } + + /* Clear sticky error */ + mem_ap_write_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DRCR, DRCR_CSE); + + armv8->read_reg_u64(armv8, ARMV8_xPSR, &dlr); + dspsr = dlr; + armv8->read_reg_u64(armv8, ARMV8_PC, &dlr); + + LOG_DEBUG("Exception taken to EL %i, DLR=0x%016"PRIx64" DSPSR=0x%08"PRIx32, + el, dlr, dspsr); + + /* mark all clobbered registers as dirty */ + for (int i = 0; i < 5; i++) + cache->reg_list[clobbered_regs_by_el[el-1][i]].dirty = true; + + /* + * re-evaluate the core state, we might be in Aarch64 state now + * we rely on dpm->dscr being up-to-date + */ + core_state = armv8_dpm_get_core_state(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); +} + +/*----------------------------------------------------------------------*/ + +/* + * Other debug and support utilities + */ + +void armv8_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dscr) +{ + struct target *target = dpm->arm->target; + + dpm->dscr = dscr; + dpm->last_el = (dscr >> 8) & 3; + + /* Examine debug reason */ + switch (DSCR_ENTRY(dscr)) { + /* FALL THROUGH -- assume a v6 core in abort mode */ + case DSCRV8_ENTRY_EXT_DEBUG: /* EDBGRQ */ + target->debug_reason = DBG_REASON_DBGRQ; + break; + case DSCRV8_ENTRY_HALT_STEP_EXECLU: /* HALT step */ + case DSCRV8_ENTRY_HALT_STEP_NORMAL: /* Halt step*/ + case DSCRV8_ENTRY_HALT_STEP: + target->debug_reason = DBG_REASON_SINGLESTEP; + break; + case DSCRV8_ENTRY_HLT: /* HLT instruction (software breakpoint) */ + case DSCRV8_ENTRY_BKPT: /* SW BKPT (?) */ + case DSCRV8_ENTRY_RESET_CATCH: /* Reset catch */ + case DSCRV8_ENTRY_OS_UNLOCK: /*OS unlock catch*/ + case DSCRV8_ENTRY_EXCEPTION_CATCH: /*exception catch*/ + case DSCRV8_ENTRY_SW_ACCESS_DBG: /*SW access dbg register*/ + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case DSCRV8_ENTRY_WATCHPOINT: /* asynch watchpoint */ + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + default: + target->debug_reason = DBG_REASON_UNDEFINED; + break; + } + +} + +/*----------------------------------------------------------------------*/ + +/* + * Setup and management support. + */ + +/** + * Hooks up this DPM to its associated target; call only once. + * Initially this only covers the register cache. + * + * Oh, and watchpoints. Yeah. + */ +int armv8_dpm_setup(struct arm_dpm *dpm) +{ + struct arm *arm = dpm->arm; + struct target *target = arm->target; + struct reg_cache *cache; + arm->dpm = dpm; + + /* register access setup */ + arm->full_context = armv8_dpm_full_context; + arm->read_core_reg = armv8_dpm_read_core_reg; + arm->write_core_reg = armv8_dpm_write_core_reg; + + if (arm->core_cache == NULL) { + cache = armv8_build_reg_cache(target); + if (!cache) + return ERROR_FAIL; + } + + /* coprocessor access setup */ + arm->mrc = dpmv8_mrc; + arm->mcr = dpmv8_mcr; + + dpm->prepare = dpmv8_dpm_prepare; + dpm->finish = dpmv8_dpm_finish; + + dpm->instr_execute = dpmv8_instr_execute; + dpm->instr_write_data_dcc = dpmv8_instr_write_data_dcc; + dpm->instr_write_data_dcc_64 = dpmv8_instr_write_data_dcc_64; + dpm->instr_write_data_r0 = dpmv8_instr_write_data_r0; + dpm->instr_write_data_r0_64 = dpmv8_instr_write_data_r0_64; + dpm->instr_cpsr_sync = dpmv8_instr_cpsr_sync; + + dpm->instr_read_data_dcc = dpmv8_instr_read_data_dcc; + dpm->instr_read_data_dcc_64 = dpmv8_instr_read_data_dcc_64; + dpm->instr_read_data_r0 = dpmv8_instr_read_data_r0; + dpm->instr_read_data_r0_64 = dpmv8_instr_read_data_r0_64; + + dpm->arm_reg_current = armv8_reg_current; + +/* dpm->bpwp_enable = dpmv8_bpwp_enable; */ + dpm->bpwp_disable = dpmv8_bpwp_disable; + + /* breakpoint setup -- optional until it works everywhere */ + if (!target->type->add_breakpoint) { + target->type->add_breakpoint = dpmv8_add_breakpoint; + target->type->remove_breakpoint = dpmv8_remove_breakpoint; + } + + /* watchpoint setup */ + target->type->add_watchpoint = dpmv8_add_watchpoint; + target->type->remove_watchpoint = dpmv8_remove_watchpoint; + + /* FIXME add vector catch support */ + + dpm->nbp = 1 + ((dpm->didr >> 12) & 0xf); + dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp); + + dpm->nwp = 1 + ((dpm->didr >> 20) & 0xf); + dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp); + + if (!dpm->dbp || !dpm->dwp) { + free(dpm->dbp); + free(dpm->dwp); + return ERROR_FAIL; + } + + LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints", + target_name(target), dpm->nbp, dpm->nwp); + + /* REVISIT ... and some of those breakpoints could match + * execution context IDs... + */ + + return ERROR_OK; +} + +/** + * Reinitializes DPM state at the beginning of a new debug session + * or after a reset which may have affected the debug module. + */ +int armv8_dpm_initialize(struct arm_dpm *dpm) +{ + /* Disable all breakpoints and watchpoints at startup. */ + if (dpm->bpwp_disable) { + unsigned i; + + for (i = 0; i < dpm->nbp; i++) { + dpm->dbp[i].bpwp.number = i; + (void) dpm->bpwp_disable(dpm, i); + } + for (i = 0; i < dpm->nwp; i++) { + dpm->dwp[i].bpwp.number = 16 + i; + (void) dpm->bpwp_disable(dpm, 16 + i); + } + } else + LOG_WARNING("%s: can't disable breakpoints and watchpoints", + target_name(dpm->arm->target)); + + return ERROR_OK; +} diff --git a/src/target/armv8_dpm.h b/src/target/armv8_dpm.h new file mode 100644 index 00000000..c0393592 --- /dev/null +++ b/src/target/armv8_dpm.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2009 by David Brownell + * + * 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. + */ + +#ifndef OPENOCD_TARGET_ARMV8_DPM_H +#define OPENOCD_TARGET_ARMV8_DPM_H + +#include "arm_dpm.h" + +/* forward-declare struct armv8_common */ +struct armv8_common; + +/** + * This wraps an implementation of DPM primitives. Each interface + * provider supplies a structure like this, which is the glue between + * upper level code and the lower level hardware access. + * + * It is a PRELIMINARY AND INCOMPLETE set of primitives, starting with + * support for CPU register access. + */ +int armv8_dpm_setup(struct arm_dpm *dpm); +int armv8_dpm_initialize(struct arm_dpm *dpm); + +int armv8_dpm_read_current_registers(struct arm_dpm *); +int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode); + + +int armv8_dpm_write_dirty_registers(struct arm_dpm *, bool bpwp); + +void armv8_dpm_report_wfar(struct arm_dpm *, uint64_t wfar); + +/* DSCR bits; see ARMv7a arch spec section C10.3.1. + * Not all v7 bits are valid in v6. + */ +#define DSCR_DEBUG_STATUS_MASK (0x1F << 0) +#define DSCR_ERR (0x1 << 6) +#define DSCR_SYS_ERROR_PEND (0x1 << 7) +#define DSCR_CUR_EL (0x3 << 8) +#define DSCR_EL_STATUS_MASK (0xF << 10) +#define DSCR_HDE (0x1 << 14) +#define DSCR_SDD (0x1 << 16) +#define DSCR_NON_SECURE (0x1 << 18) +#define DSCR_MA (0x1 << 20) +#define DSCR_TDA (0x1 << 21) +#define DSCR_INTDIS_MASK (0x3 << 22) +#define DSCR_ITE (0x1 << 24) +#define DSCR_PIPE_ADVANCE (0x1 << 25) +#define DSCR_TXU (0x1 << 26) +#define DSCR_RTO (0x1 << 27) /* bit 28 is reserved */ +#define DSCR_ITO (0x1 << 28) +#define DSCR_DTR_TX_FULL (0x1 << 29) +#define DSCR_DTR_RX_FULL (0x1 << 30) /* bit 31 is reserved */ + + + +/* Methods of entry into debug mode */ +#define DSCRV8_ENTRY_NON_DEBUG (0x2) +#define DSCRV8_ENTRY_RESTARTING (0x1) +#define DSCRV8_ENTRY_BKPT (0x7) +#define DSCRV8_ENTRY_EXT_DEBUG (0x13) +#define DSCRV8_ENTRY_HALT_STEP_NORMAL (0x1B) +#define DSCRV8_ENTRY_HALT_STEP_EXECLU (0x1F) +#define DSCRV8_ENTRY_OS_UNLOCK (0x23) +#define DSCRV8_ENTRY_RESET_CATCH (0x27) +#define DSCRV8_ENTRY_WATCHPOINT (0x2B) +#define DSCRV8_ENTRY_HLT (0x2F) +#define DSCRV8_ENTRY_SW_ACCESS_DBG (0x33) +#define DSCRV8_ENTRY_EXCEPTION_CATCH (0x37) +#define DSCRV8_ENTRY_HALT_STEP (0x3B) +#define DSCRV8_HALT_MASK (0x3C) + +/*DRCR registers*/ +#define DRCR_CSE (1 << 2) +#define DRCR_CSPA (1 << 3) +#define DRCR_CBRRQ (1 << 4) + + +/* DTR modes */ +#define DSCR_EXT_DCC_NON_BLOCKING (0x0 << 20) +#define DSCR_EXT_DCC_STALL_MODE (0x1 << 20) +#define DSCR_EXT_DCC_FAST_MODE (0x2 << 20) /* bits 22, 23 are reserved */ + + +/* DRCR (debug run control register) bits */ +#define DRCR_HALT (1 << 0) +#define DRCR_RESTART (1 << 1) +#define DRCR_CLEAR_EXCEPTIONS (1 << 2) + +/* PRSR (processor debug status register) bits */ +#define PRSR_PU (1 << 0) +#define PRSR_SPD (1 << 1) +#define PRSR_RESET (1 << 2) +#define PRSR_SR (1 << 3) +#define PRSR_HALT (1 << 4) +#define PRSR_OSLK (1 << 5) +#define PRSR_DLK (1 << 6) +#define PRSR_EDAD (1 << 7) +#define PRSR_SDAD (1 << 8) +#define PRSR_EPMAD (1 << 9) +#define PRSR_SPMAD (1 << 10) +#define PRSR_SDR (1 << 11) + +/* PRCR (processor debug control register) bits */ +#define PRCR_CORENPDRQ (1 << 0) +#define PRCR_CWRR (1 << 2) +#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); +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.c b/src/target/armv8_opcodes.c new file mode 100644 index 00000000..d3c0b3f5 --- /dev/null +++ b/src/target/armv8_opcodes.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2015 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. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "armv8.h" +#include "armv8_opcodes.h" + +static const uint32_t a64_opcodes[ARMV8_OPC_NUM] = { + [READ_REG_CTR] = ARMV8_MRS(SYSTEM_CTR, 0), + [READ_REG_CLIDR] = ARMV8_MRS(SYSTEM_CLIDR, 0), + [READ_REG_CSSELR] = ARMV8_MRS(SYSTEM_CSSELR, 0), + [READ_REG_CCSIDR] = ARMV8_MRS(SYSTEM_CCSIDR, 0), + [WRITE_REG_CSSELR] = ARMV8_MSR_GP(SYSTEM_CSSELR, 0), + [READ_REG_MPIDR] = ARMV8_MRS(SYSTEM_MPIDR, 0), + [READ_REG_DTRRX] = ARMV8_MRS(SYSTEM_DBG_DTRRX_EL0, 0), + [WRITE_REG_DTRTX] = ARMV8_MSR_GP(SYSTEM_DBG_DTRTX_EL0, 0), + [WRITE_REG_DSPSR] = ARMV8_MSR_DSPSR(0), + [READ_REG_DSPSR] = ARMV8_MRS_DSPSR(0), + [ARMV8_OPC_DSB_SY] = ARMV8_DSB_SY, + [ARMV8_OPC_DCPS] = ARMV8_DCPS(0, 11), + [ARMV8_OPC_DRPS] = ARMV8_DRPS, + [ARMV8_OPC_ISB_SY] = ARMV8_ISB, + [ARMV8_OPC_DCCISW] = ARMV8_SYS(SYSTEM_DCCISW, 0), + [ARMV8_OPC_DCCIVAC] = ARMV8_SYS(SYSTEM_DCCIVAC, 0), + [ARMV8_OPC_ICIVAU] = ARMV8_SYS(SYSTEM_ICIVAU, 0), + [ARMV8_OPC_HLT] = ARMV8_HLT(11), +}; + +static const uint32_t t32_opcodes[ARMV8_OPC_NUM] = { + [READ_REG_CTR] = ARMV4_5_MRC(15, 0, 0, 0, 0, 1), + [READ_REG_CLIDR] = ARMV4_5_MRC(15, 1, 0, 0, 0, 1), + [READ_REG_CSSELR] = ARMV4_5_MRC(15, 2, 0, 0, 0, 0), + [READ_REG_CCSIDR] = ARMV4_5_MRC(15, 1, 0, 0, 0, 0), + [WRITE_REG_CSSELR] = ARMV4_5_MCR(15, 2, 0, 0, 0, 0), + [READ_REG_MPIDR] = ARMV4_5_MRC(15, 0, 0, 0, 0, 5), + [READ_REG_DTRRX] = ARMV4_5_MRC(14, 0, 0, 0, 5, 0), + [WRITE_REG_DTRTX] = ARMV4_5_MCR(14, 0, 0, 0, 5, 0), + [WRITE_REG_DSPSR] = ARMV8_MCR_DSPSR(0), + [READ_REG_DSPSR] = ARMV8_MRC_DSPSR(0), + [ARMV8_OPC_DSB_SY] = ARMV8_DSB_SY_T1, + [ARMV8_OPC_DCPS] = ARMV8_DCPS_T1(0), + [ARMV8_OPC_DRPS] = ARMV8_ERET_T1, + [ARMV8_OPC_ISB_SY] = ARMV8_ISB_SY_T1, + [ARMV8_OPC_DCCISW] = ARMV4_5_MCR(15, 0, 0, 7, 14, 2), + [ARMV8_OPC_DCCIVAC] = ARMV4_5_MCR(15, 0, 0, 7, 14, 1), + [ARMV8_OPC_ICIVAU] = ARMV4_5_MCR(15, 0, 0, 7, 5, 1), + [ARMV8_OPC_HLT] = ARMV8_HLT_A1(11), +}; + +void armv8_select_opcodes(struct armv8_common *armv8, bool state_is_aarch64) +{ + if (state_is_aarch64) + armv8->opcodes = &a64_opcodes[0]; + else + armv8->opcodes = &t32_opcodes[0]; +} + +uint32_t armv8_opcode(struct armv8_common *armv8, enum armv8_opcode code) +{ + if ((int)code >= ARMV8_OPC_NUM) + return -1; + + return *(armv8->opcodes + code); +} diff --git a/src/target/armv8_opcodes.h b/src/target/armv8_opcodes.h new file mode 100644 index 00000000..2d8ddd82 --- /dev/null +++ b/src/target/armv8_opcodes.h @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2015 by pierrr kuo + * vichy.kuo@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. + * + */ +#ifndef OPENOCD_TARGET_ARMV8_OPCODES_H +#define OPENOCD_TARGET_ARMV8_OPCODES_H + +#include "arm_opcodes.h" + +#define SYSTEM_CUREL_MASK 0xC0 +#define SYSTEM_CUREL_SHIFT 6 +#define SYSTEM_CUREL_EL0 0x0 +#define SYSTEM_CUREL_EL1 0x1 +#define SYSTEM_CUREL_EL2 0x2 +#define SYSTEM_CUREL_EL3 0x3 +#define SYSTEM_CUREL_NONCH 0xF +#define SYSTEM_AARCH64 0x1 + +#define SYSTEM_AAR64_MODE_EL0t 0x0 +#define SYSTEM_AAR64_MODE_EL1t 0x4 +#define SYSTEM_AAR64_MODE_EL1h 0x5 +#define SYSTEM_AAR64_MODE_EL2t 0x8 +#define SYSTEM_AAR64_MODE_EL2h 0x9 +#define SYSTEM_AAR64_MODE_EL3t 0xC +#define SYSTEM_AAR64_MODE_EL3h 0xd + +#define SYSTEM_DAIF 0b1101101000010001 +#define SYSTEM_DAIF_MASK 0x3C0 +#define SYSTEM_DAIF_SHIFT 6 + +#define SYSTEM_ELR_EL1 0b1100001000000001 +#define SYSTEM_ELR_EL2 0b1110001000000001 +#define SYSTEM_ELR_EL3 0b1111001000000001 + +#define SYSTEM_SCTLR_EL1 0b1100000010000000 +#define SYSTEM_SCTLR_EL2 0b1110000010000000 +#define SYSTEM_SCTLR_EL3 0b1111000010000000 + +#define SYSTEM_FPCR 0b1101101000100000 +#define SYSTEM_FPSR 0b1101101000100001 +#define SYSTEM_DAIF 0b1101101000010001 +#define SYSTEM_NZCV 0b1101101000010000 +#define SYSTEM_SP_EL0 0b1100001000001000 +#define SYSTEM_SP_EL1 0b1110001000001000 +#define SYSTEM_SP_EL2 0b1111001000001000 +#define SYSTEM_SP_SEL 0b1100001000010000 +#define SYSTEM_SPSR_ABT 0b1110001000011001 +#define SYSTEM_SPSR_FIQ 0b1110001000011011 +#define SYSTEM_SPSR_IRQ 0b1110001000011000 +#define SYSTEM_SPSR_UND 0b1110001000011010 + +#define SYSTEM_SPSR_EL1 0b1100001000000000 +#define SYSTEM_SPSR_EL2 0b1110001000000000 +#define SYSTEM_SPSR_EL3 0b1111001000000000 + +#define SYSTEM_ISR_EL1 0b1100011000001000 + +#define SYSTEM_DBG_DSPSR_EL0 0b1101101000101000 +#define SYSTEM_DBG_DLR_EL0 0b1101101000101001 +#define SYSTEM_DBG_DTRRX_EL0 0b1001100000101000 +#define SYSTEM_DBG_DTRTX_EL0 0b1001100000101000 +#define SYSTEM_DBG_DBGDTR_EL0 0b1001100000100000 + +#define SYSTEM_CCSIDR 0b1100100000000000 +#define SYSTEM_CLIDR 0b1100100000000001 +#define SYSTEM_CSSELR 0b1101000000000000 +#define SYSTEM_CTYPE 0b1101100000000001 +#define SYSTEM_CTR 0b1101100000000001 + +#define SYSTEM_DCCISW 0b0100001111110010 +#define SYSTEM_DCCSW 0b0100001111010010 +#define SYSTEM_ICIVAU 0b0101101110101001 +#define SYSTEM_DCCVAU 0b0101101111011001 +#define SYSTEM_DCCIVAC 0b0101101111110001 + +#define SYSTEM_MPIDR 0b1100000000000101 + +#define SYSTEM_TCR_EL1 0b1100000100000010 +#define SYSTEM_TCR_EL2 0b1110000100000010 +#define SYSTEM_TCR_EL3 0b1111000100000010 + +#define SYSTEM_TTBR0_EL1 0b1100000100000000 +#define SYSTEM_TTBR0_EL2 0b1110000100000000 +#define SYSTEM_TTBR0_EL3 0b1111000100000000 +#define SYSTEM_TTBR1_EL1 0b1100000100000001 + +/* ARMv8 address translation */ +#define SYSTEM_PAR_EL1 0b1100001110100000 +#define SYSTEM_ATS12E0R 0b0110001111000110 +#define SYSTEM_ATS12E1R 0b0110001111000100 +#define SYSTEM_ATS1E2R 0b0110001111000000 +#define SYSTEM_ATS1E3R 0b0111001111000000 + +/* fault status and fault address */ +#define SYSTEM_FAR_EL1 0b1100001100000000 +#define SYSTEM_FAR_EL2 0b1110001100000000 +#define SYSTEM_FAR_EL3 0b1111001100000000 +#define SYSTEM_ESR_EL1 0b1100001010010000 +#define SYSTEM_ESR_EL2 0b1110001010010000 +#define SYSTEM_ESR_EL3 0b1111001010010000 + +#define ARMV8_MRS_DSPSR(Rt) (0xd53b4500 | (Rt)) +#define ARMV8_MSR_DSPSR(Rt) (0xd51b4500 | (Rt)) +#define ARMV8_MRS_DLR(Rt) (0xd53b4520 | (Rt)) +#define ARMV8_MSR_DLR(Rt) (0xd51b4520 | (Rt)) + +/* T32 instruction to access coprocessor registers */ +#define ARMV8_MCR_T1(cp, CRn, opc1, CRm, opc2, Rt) ARMV4_5_MCR(cp, opc1, Rt, CRn, CRm, opc2) +#define ARMV8_MRC_T1(cp, CRn, opc1, CRm, opc2, Rt) ARMV4_5_MRC(cp, opc1, Rt, CRn, CRm, opc2) + +/* T32 instructions to access DSPSR and DLR */ +#define ARMV8_MRC_DSPSR(Rt) ARMV8_MRC_T1(15, 4, 3, 5, 0, Rt) +#define ARMV8_MCR_DSPSR(Rt) ARMV8_MCR_T1(15, 4, 3, 5, 0, Rt) +#define ARMV8_MRC_DLR(Rt) ARMV8_MRC_T1(15, 4, 3, 5, 1, Rt) +#define ARMV8_MCR_DLR(Rt) ARMV8_MCR_T1(15, 4, 3, 5, 1, Rt) + +#define ARMV8_DCPS1(IM) (0xd4a00001 | (((IM) & 0xFFFF) << 5)) +#define ARMV8_DCPS2(IM) (0xd4a00002 | (((IM) & 0xFFFF) << 5)) +#define ARMV8_DCPS3(IM) (0xd4a00003 | (((IM) & 0xFFFF) << 5)) +#define ARMV8_DCPS(EL, IM) (0xd4a00000 | (((IM) & 0xFFFF) << 5) | EL) +#define ARMV8_DCPS_T1(EL) (0xf78f8000 | EL) +#define ARMV8_DRPS 0xd6bf03e0 +#define ARMV8_ERET_T1 0xf3de8f00 + +#define ARMV8_DSB_SY 0xd5033F9F +#define ARMV8_DSB_SY_T1 0xf3bf8f4f +#define ARMV8_ISB 0xd5033fdf +#define ARMV8_ISB_SY_T1 0xf3bf8f6f + +#define ARMV8_MRS(System, Rt) (0xd5300000 | ((System) << 5) | (Rt)) +/* ARM V8 Move to system register. */ +#define ARMV8_MSR_GP(System, Rt) \ + (0xd5100000 | ((System) << 5) | (Rt)) +/* ARM V8 Move immediate to process state field. */ +#define ARMV8_MSR_IM(Op1, CRm, Op2) \ + (0xd500401f | ((Op1) << 16) | ((CRm) << 8) | ((Op2) << 5)) + +#define ARMV8_MRS_T1(R, M1, Rd, M) (0xF3E08020 | (R << 20) | (M1 << 16) | (Rd << 8) | (M << 4)) +#define ARMV8_MRS_xPSR_T1(R, Rd) (0xF3EF8000 | (R << 20) | (Rd << 8)) +#define ARMV8_MSR_GP_T1(R, M1, Rd, M) (0xF3808020 | (R << 20) | (M1 << 8) | (Rd << 16) | (M << 4)) +#define ARMV8_MSR_GP_xPSR_T1(R, Rn, mask) (0xF3808000 | (R << 20) | (Rn << 16) | (mask << 8)) + +#define ARMV8_BKPT(Im) (0xD4200000 | ((Im & 0xffff) << 5)) +#define ARMV8_HLT(Im) (0x0D4400000 | ((Im & 0xffff) << 5)) +#define ARMV8_HLT_A1(Im) (0xE1000070 | ((Im & 0xFFF0) << 4) | (Im & 0xF)) + +#define ARMV8_MOVFSP_64(Rt) ((1 << 31) | 0x11000000 | (0x1f << 5) | (Rt)) +#define ARMV8_MOVTSP_64(Rt) ((1 << 31) | 0x11000000 | (Rt << 5) | (0x1F)) +#define ARMV8_MOVFSP_32(Rt) (0x11000000 | (0x1f << 5) | (Rt)) +#define ARMV8_MOVTSP_32(Rt) (0x11000000 | (Rt << 5) | (0x1F)) + +#define ARMV8_SYS(System, Rt) (0xD5080000 | ((System) << 5) | Rt) + +enum armv8_opcode { + READ_REG_CTR, + READ_REG_CLIDR, + READ_REG_CSSELR, + READ_REG_CCSIDR, + WRITE_REG_CSSELR, + READ_REG_MPIDR, + READ_REG_DTRRX, + WRITE_REG_DTRTX, + WRITE_REG_DSPSR, + READ_REG_DSPSR, + ARMV8_OPC_DSB_SY, + ARMV8_OPC_DCPS, + ARMV8_OPC_DRPS, + ARMV8_OPC_ISB_SY, + ARMV8_OPC_DCCISW, + ARMV8_OPC_DCCIVAC, + ARMV8_OPC_ICIVAU, + ARMV8_OPC_HLT, + ARMV8_OPC_NUM, +}; + +extern uint32_t armv8_opcode(struct armv8_common *armv8, enum armv8_opcode); +extern void armv8_select_opcodes(struct armv8_common *armv8, bool state_is_aarch64); + +#endif /* OPENOCD_TARGET_ARMV8_OPCODES_H */ diff --git a/src/target/avr32_ap7k.c b/src/target/avr32_ap7k.c index e5634f2d..f8da8d5a 100644 --- a/src/target/avr32_ap7k.c +++ b/src/target/avr32_ap7k.c @@ -312,7 +312,7 @@ static int avr32_ap7k_deassert_reset(struct target *target) } static int avr32_ap7k_resume(struct target *target, int current, - uint32_t address, int handle_breakpoints, int debug_execution) + target_addr_t address, int handle_breakpoints, int debug_execution) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); struct breakpoint *breakpoint = NULL; @@ -348,7 +348,7 @@ static int avr32_ap7k_resume(struct target *target, int current, /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { - LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", breakpoint->address); + LOG_DEBUG("unset breakpoint at 0x%8.8" TARGET_PRIxADDR "", breakpoint->address); #if 0 avr32_ap7k_unset_breakpoint(target, breakpoint); avr32_ap7k_single_step_core(target); @@ -394,7 +394,7 @@ static int avr32_ap7k_resume(struct target *target, int current, } static int avr32_ap7k_step(struct target *target, int current, - uint32_t address, int handle_breakpoints) + target_addr_t address, int handle_breakpoints) { LOG_ERROR("%s: implement me", __func__); @@ -431,12 +431,12 @@ static int avr32_ap7k_remove_watchpoint(struct target *target, return ERROR_OK; } -static int avr32_ap7k_read_memory(struct target *target, uint32_t address, +static int avr32_ap7k_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); - LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); @@ -472,12 +472,12 @@ static int avr32_ap7k_read_memory(struct target *target, uint32_t address, return ERROR_OK; } -static int avr32_ap7k_write_memory(struct target *target, uint32_t address, +static int avr32_ap7k_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); - LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); diff --git a/src/target/avrt.c b/src/target/avrt.c index 40a12974..1e1898c7 100644 --- a/src/target/avrt.c +++ b/src/target/avrt.c @@ -33,9 +33,9 @@ static int avr_init_target(struct command_context *cmd_ctx, struct target *targe static int avr_arch_state(struct target *target); static int avr_poll(struct target *target); static int avr_halt(struct target *target); -static int avr_resume(struct target *target, int current, uint32_t address, +static int avr_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution); -static int avr_step(struct target *target, int current, uint32_t address, +static int avr_step(struct target *target, int current, target_addr_t address, int handle_breakpoints); static int avr_assert_reset(struct target *target); @@ -116,14 +116,14 @@ static int avr_halt(struct target *target) return ERROR_OK; } -static int avr_resume(struct target *target, int current, uint32_t address, +static int avr_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { LOG_DEBUG("%s", __func__); return ERROR_OK; } -static int avr_step(struct target *target, int current, uint32_t address, int handle_breakpoints) +static int avr_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { LOG_DEBUG("%s", __func__); return ERROR_OK; diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index c4a959df..7cf4a695 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -42,7 +42,7 @@ static const char * const watchpoint_rw_strings[] = { static int bpwp_unique_id; int breakpoint_add_internal(struct target *target, - uint32_t address, + target_addr_t address, uint32_t length, enum breakpoint_type type) { @@ -60,7 +60,7 @@ int breakpoint_add_internal(struct target *target, * breakpoint" ... check all the parameters before * succeeding. */ - LOG_DEBUG("Duplicate Breakpoint address: 0x%08" PRIx32 " (BP %" PRIu32 ")", + LOG_DEBUG("Duplicate Breakpoint address: " TARGET_ADDR_FMT " (BP %" PRIu32 ")", address, breakpoint->unique_id); return ERROR_OK; } @@ -98,7 +98,7 @@ int breakpoint_add_internal(struct target *target, return retval; } - LOG_DEBUG("added %s breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %" PRIu32 ")", + LOG_DEBUG("added %s breakpoint at " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")", breakpoint_type_strings[(*breakpoint_p)->type], (*breakpoint_p)->address, (*breakpoint_p)->length, (*breakpoint_p)->unique_id); @@ -159,7 +159,7 @@ int context_breakpoint_add_internal(struct target *target, } int hybrid_breakpoint_add_internal(struct target *target, - uint32_t address, + target_addr_t address, uint32_t asid, uint32_t length, enum breakpoint_type type) @@ -180,7 +180,7 @@ int hybrid_breakpoint_add_internal(struct target *target, asid, breakpoint->unique_id); return -1; } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) { - LOG_DEBUG("Duplicate Breakpoint IVA: 0x%08" PRIx32 " (BP %" PRIu32 ")", + LOG_DEBUG("Duplicate Breakpoint IVA: " TARGET_ADDR_FMT " (BP %" PRIu32 ")", address, breakpoint->unique_id); return -1; @@ -208,7 +208,7 @@ int hybrid_breakpoint_add_internal(struct target *target, return retval; } LOG_DEBUG( - "added %s Hybrid breakpoint at address 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %" PRIu32 ")", + "added %s Hybrid breakpoint at address " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")", breakpoint_type_strings[(*breakpoint_p)->type], (*breakpoint_p)->address, (*breakpoint_p)->length, @@ -218,7 +218,7 @@ int hybrid_breakpoint_add_internal(struct target *target, } int breakpoint_add(struct target *target, - uint32_t address, + target_addr_t address, uint32_t length, enum breakpoint_type type) { @@ -263,7 +263,7 @@ int context_breakpoint_add(struct target *target, return context_breakpoint_add_internal(target, asid, length, type); } int hybrid_breakpoint_add(struct target *target, - uint32_t address, + target_addr_t address, uint32_t asid, uint32_t length, enum breakpoint_type type) @@ -310,7 +310,7 @@ static void breakpoint_free(struct target *target, struct breakpoint *breakpoint free(breakpoint); } -int breakpoint_remove_internal(struct target *target, uint32_t address) +int breakpoint_remove_internal(struct target *target, target_addr_t address) { struct breakpoint *breakpoint = target->breakpoints; @@ -329,11 +329,11 @@ int breakpoint_remove_internal(struct target *target, uint32_t address) return 1; } else { if (!target->smp) - LOG_ERROR("no breakpoint at address 0x%8.8" PRIx32 " found", address); + LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address); return 0; } } -void breakpoint_remove(struct target *target, uint32_t address) +void breakpoint_remove(struct target *target, target_addr_t address) { int found = 0; if (target->smp) { @@ -346,7 +346,7 @@ void breakpoint_remove(struct target *target, uint32_t address) head = head->next; } if (found == 0) - LOG_ERROR("no breakpoint at address 0x%8.8" PRIx32 " found", address); + LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address); } else breakpoint_remove_internal(target, address); } @@ -375,7 +375,7 @@ void breakpoint_clear_target(struct target *target) } -struct breakpoint *breakpoint_find(struct target *target, uint32_t address) +struct breakpoint *breakpoint_find(struct target *target, target_addr_t address) { struct breakpoint *breakpoint = target->breakpoints; @@ -388,7 +388,7 @@ struct breakpoint *breakpoint_find(struct target *target, uint32_t address) return NULL; } -int watchpoint_add(struct target *target, uint32_t address, uint32_t length, +int watchpoint_add(struct target *target, target_addr_t address, uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask) { struct watchpoint *watchpoint = target->watchpoints; @@ -402,7 +402,7 @@ int watchpoint_add(struct target *target, uint32_t address, uint32_t length, || watchpoint->value != value || watchpoint->mask != mask || watchpoint->rw != rw) { - LOG_ERROR("address 0x%8.8" PRIx32 + LOG_ERROR("address " TARGET_ADDR_FMT " already has watchpoint %d", address, watchpoint->unique_id); return ERROR_FAIL; @@ -436,7 +436,7 @@ int watchpoint_add(struct target *target, uint32_t address, uint32_t length, default: reason = "unrecognized error"; bye: - LOG_ERROR("can't add %s watchpoint at 0x%8.8" PRIx32 ", %s", + LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT ", %s", watchpoint_rw_strings[(*watchpoint_p)->rw], address, reason); free(*watchpoint_p); @@ -444,7 +444,7 @@ int watchpoint_add(struct target *target, uint32_t address, uint32_t length, return retval; } - LOG_DEBUG("added %s watchpoint at 0x%8.8" PRIx32 + LOG_DEBUG("added %s watchpoint at " TARGET_ADDR_FMT " of length 0x%8.8" PRIx32 " (WPID: %d)", watchpoint_rw_strings[(*watchpoint_p)->rw], (*watchpoint_p)->address, @@ -475,7 +475,7 @@ static void watchpoint_free(struct target *target, struct watchpoint *watchpoint free(watchpoint); } -void watchpoint_remove(struct target *target, uint32_t address) +void watchpoint_remove(struct target *target, target_addr_t address) { struct watchpoint *watchpoint = target->watchpoints; @@ -488,7 +488,7 @@ void watchpoint_remove(struct target *target, uint32_t address) if (watchpoint) watchpoint_free(target, watchpoint); else - LOG_ERROR("no watchpoint at address 0x%8.8" PRIx32 " found", address); + LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " found", address); } void watchpoint_clear_target(struct target *target) @@ -499,7 +499,8 @@ void watchpoint_clear_target(struct target *target) watchpoint_free(target, target->watchpoints); } -int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, uint32_t *address) +int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, + target_addr_t *address) { int retval; struct watchpoint *hit_watchpoint; @@ -511,7 +512,7 @@ int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, uint32_t *addr *rw = hit_watchpoint->rw; *address = hit_watchpoint->address; - LOG_DEBUG("Found hit watchpoint at 0x%8.8" PRIx32 " (WPID: %d)", + LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)", hit_watchpoint->address, hit_watchpoint->unique_id); diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h index 842fc18a..51bd05ab 100644 --- a/src/target/breakpoints.h +++ b/src/target/breakpoints.h @@ -33,7 +33,7 @@ enum watchpoint_rw { }; struct breakpoint { - uint32_t address; + target_addr_t address; uint32_t asid; int length; enum breakpoint_type type; @@ -45,7 +45,7 @@ struct breakpoint { }; struct watchpoint { - uint32_t address; + target_addr_t address; uint32_t length; uint32_t mask; uint32_t value; @@ -57,22 +57,23 @@ struct watchpoint { void breakpoint_clear_target(struct target *target); int breakpoint_add(struct target *target, - uint32_t address, uint32_t length, enum breakpoint_type type); + target_addr_t address, uint32_t length, enum breakpoint_type type); int context_breakpoint_add(struct target *target, uint32_t asid, uint32_t length, enum breakpoint_type type); int hybrid_breakpoint_add(struct target *target, - uint32_t address, uint32_t asid, uint32_t length, enum breakpoint_type type); -void breakpoint_remove(struct target *target, uint32_t address); + target_addr_t address, uint32_t asid, uint32_t length, enum breakpoint_type type); +void breakpoint_remove(struct target *target, target_addr_t address); -struct breakpoint *breakpoint_find(struct target *target, uint32_t address); +struct breakpoint *breakpoint_find(struct target *target, target_addr_t address); void watchpoint_clear_target(struct target *target); int watchpoint_add(struct target *target, - uint32_t address, uint32_t length, + target_addr_t address, uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask); -void watchpoint_remove(struct target *target, uint32_t address); +void watchpoint_remove(struct target *target, target_addr_t address); /* report type and address of just hit watchpoint */ -int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, uint32_t *address); +int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, + target_addr_t *address); #endif /* OPENOCD_TARGET_BREAKPOINTS_H */ diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 8c8a2b79..5d90e341 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -75,7 +75,7 @@ static int cortex_a_dap_write_coreregister_u32(struct target *target, static int cortex_a_mmu(struct target *target, int *enabled); static int cortex_a_mmu_modify(struct target *target, int enable); static int cortex_a_virt2phys(struct target *target, - uint32_t virt, uint32_t *phys); + target_addr_t virt, target_addr_t *phys); static int cortex_a_read_cpu_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); @@ -879,12 +879,8 @@ static int cortex_a_poll(struct target *target) TARGET_EVENT_DEBUG_HALTED); } } - } else if (DSCR_RUN_MODE(dscr) == DSCR_CORE_RESTARTED) + } else target->state = TARGET_RUNNING; - else { - LOG_DEBUG("Unknown target state dscr = 0x%08" PRIx32, dscr); - target->state = TARGET_UNKNOWN; - } return retval; } @@ -937,7 +933,7 @@ static int cortex_a_halt(struct target *target) } static int cortex_a_internal_restore(struct target *target, int current, - uint32_t *address, int handle_breakpoints, int debug_execution) + target_addr_t *address, int handle_breakpoints, int debug_execution) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; @@ -992,6 +988,9 @@ static int cortex_a_internal_restore(struct target *target, int current, case ARM_STATE_JAZELLE: LOG_ERROR("How do I resume into Jazelle state??"); return ERROR_FAIL; + case ARM_STATE_AARCH64: + LOG_ERROR("Shoudn't be in AARCH64 state"); + return ERROR_FAIL; } LOG_DEBUG("resume pc = 0x%08" PRIx32, resume_pc); buf_set_u32(arm->pc->value, 0, 32, resume_pc); @@ -1092,7 +1091,7 @@ static int cortex_a_restore_smp(struct target *target, int handle_breakpoints) int retval = 0; struct target_list *head; struct target *curr; - uint32_t address; + target_addr_t address; head = target->head; while (head != (struct target_list *)NULL) { curr = head->target; @@ -1110,7 +1109,7 @@ static int cortex_a_restore_smp(struct target *target, int handle_breakpoints) } static int cortex_a_resume(struct target *target, int current, - uint32_t address, int handle_breakpoints, int debug_execution) + target_addr_t address, int handle_breakpoints, int debug_execution) { int retval = 0; /* dummy resume for smp toggle in order to reduce gdb impact */ @@ -1134,11 +1133,11 @@ static int cortex_a_resume(struct target *target, int current, if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - LOG_DEBUG("target resumed at 0x%" PRIx32, address); + LOG_DEBUG("target resumed at " TARGET_ADDR_FMT, address); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); - LOG_DEBUG("target debug resumed at 0x%" PRIx32, address); + LOG_DEBUG("target debug resumed at " TARGET_ADDR_FMT, address); } return ERROR_OK; @@ -1344,7 +1343,7 @@ int cortex_a_set_dscr_bits(struct target *target, unsigned long bit_mask, unsign return retval; } -static int cortex_a_step(struct target *target, int current, uint32_t address, +static int cortex_a_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { struct cortex_a_common *cortex_a = target_to_cortex_a(target); @@ -2639,7 +2638,7 @@ static int cortex_a_read_cpu_memory(struct target *target, */ static int cortex_a_read_phys_memory(struct target *target, - uint32_t address, uint32_t size, + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct armv7a_common *armv7a = target_to_armv7a(target); @@ -2650,7 +2649,7 @@ static int cortex_a_read_phys_memory(struct target *target, if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; - LOG_DEBUG("Reading memory at real address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, + LOG_DEBUG("Reading memory at real address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, address, size, count); if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap->ap_num)) @@ -2664,14 +2663,14 @@ static int cortex_a_read_phys_memory(struct target *target, return retval; } -static int cortex_a_read_memory(struct target *target, uint32_t address, +static int cortex_a_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval; /* cortex_a handles unaligned memory access */ - LOG_DEBUG("Reading memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address, - size, count); + LOG_DEBUG("Reading memory at address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, + address, size, count); cortex_a_prep_memaccess(target, 0); retval = cortex_a_read_cpu_memory(target, address, size, count, buffer); @@ -2680,11 +2679,11 @@ static int cortex_a_read_memory(struct target *target, uint32_t address, return retval; } -static int cortex_a_read_memory_ahb(struct target *target, uint32_t address, +static int cortex_a_read_memory_ahb(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int mmu_enabled = 0; - uint32_t virt, phys; + target_addr_t virt, phys; int retval; struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; @@ -2694,8 +2693,8 @@ static int cortex_a_read_memory_ahb(struct target *target, uint32_t address, return target_read_memory(target, address, size, count, buffer); /* cortex_a handles unaligned memory access */ - LOG_DEBUG("Reading memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address, - size, count); + LOG_DEBUG("Reading memory at address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, + address, size, count); /* determine if MMU was enabled on target stop */ if (!armv7a->is_armv7r) { @@ -2710,7 +2709,8 @@ static int cortex_a_read_memory_ahb(struct target *target, uint32_t address, if (retval != ERROR_OK) return retval; - LOG_DEBUG("Reading at virtual address. Translating v:0x%" PRIx32 " to r:0x%" PRIx32, + LOG_DEBUG("Reading at virtual address. " + "Translating v:" TARGET_ADDR_FMT " to r:" TARGET_ADDR_FMT, virt, phys); address = phys; } @@ -2724,7 +2724,7 @@ static int cortex_a_read_memory_ahb(struct target *target, uint32_t address, } static int cortex_a_write_phys_memory(struct target *target, - uint32_t address, uint32_t size, + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct armv7a_common *armv7a = target_to_armv7a(target); @@ -2735,8 +2735,8 @@ static int cortex_a_write_phys_memory(struct target *target, if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; - LOG_DEBUG("Writing memory to real address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address, - size, count); + LOG_DEBUG("Writing memory to real address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, + address, size, count); if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap->ap_num)) return mem_ap_write_buf(armv7a->memory_ap, buffer, size, count, address); @@ -2749,14 +2749,14 @@ static int cortex_a_write_phys_memory(struct target *target, return retval; } -static int cortex_a_write_memory(struct target *target, uint32_t address, +static int cortex_a_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval; /* cortex_a handles unaligned memory access */ - LOG_DEBUG("Writing memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address, - size, count); + LOG_DEBUG("Writing memory at address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, + address, size, count); /* memory writes bypass the caches, must flush before writing */ armv7a_cache_auto_flush_on_write(target, address, size * count); @@ -2767,11 +2767,11 @@ static int cortex_a_write_memory(struct target *target, uint32_t address, return retval; } -static int cortex_a_write_memory_ahb(struct target *target, uint32_t address, +static int cortex_a_write_memory_ahb(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int mmu_enabled = 0; - uint32_t virt, phys; + target_addr_t virt, phys; int retval; struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; @@ -2781,8 +2781,8 @@ static int cortex_a_write_memory_ahb(struct target *target, uint32_t address, return target_write_memory(target, address, size, count, buffer); /* cortex_a handles unaligned memory access */ - LOG_DEBUG("Writing memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address, - size, count); + LOG_DEBUG("Writing memory at address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, + address, size, count); /* determine if MMU was enabled on target stop */ if (!armv7a->is_armv7r) { @@ -2797,7 +2797,8 @@ static int cortex_a_write_memory_ahb(struct target *target, uint32_t address, if (retval != ERROR_OK) return retval; - LOG_DEBUG("Writing to virtual address. Translating v:0x%" PRIx32 " to r:0x%" PRIx32, + LOG_DEBUG("Writing to virtual address. " + "Translating v:" TARGET_ADDR_FMT " to r:" TARGET_ADDR_FMT, virt, phys); address = phys; @@ -2811,7 +2812,7 @@ static int cortex_a_write_memory_ahb(struct target *target, uint32_t address, return retval; } -static int cortex_a_read_buffer(struct target *target, uint32_t address, +static int cortex_a_read_buffer(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer) { uint32_t size; @@ -2845,7 +2846,7 @@ static int cortex_a_read_buffer(struct target *target, uint32_t address, return ERROR_OK; } -static int cortex_a_write_buffer(struct target *target, uint32_t address, +static int cortex_a_write_buffer(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer) { uint32_t size; @@ -3202,7 +3203,7 @@ static int cortex_a_mmu(struct target *target, int *enabled) } static int cortex_a_virt2phys(struct target *target, - uint32_t virt, uint32_t *phys) + target_addr_t virt, target_addr_t *phys) { int retval = ERROR_FAIL; struct armv7a_common *armv7a = target_to_armv7a(target); @@ -3220,7 +3221,8 @@ static int cortex_a_virt2phys(struct target *target, retval = cortex_a_mmu_modify(target, 1); if (retval != ERROR_OK) goto done; - retval = armv7a_mmu_translate_va_pa(target, virt, phys, 1); + retval = armv7a_mmu_translate_va_pa(target, (uint32_t)virt, + (uint32_t *)phys, 1); } done: return retval; diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 36a77467..e80cd235 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -682,7 +682,7 @@ void cortex_m_enable_breakpoints(struct target *target) } static int cortex_m_resume(struct target *target, int current, - uint32_t address, int handle_breakpoints, int debug_execution) + target_addr_t address, int handle_breakpoints, int debug_execution) { struct armv7m_common *armv7m = target_to_armv7m(target); struct breakpoint *breakpoint = NULL; @@ -750,7 +750,7 @@ static int cortex_m_resume(struct target *target, int current, /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { - LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 " (ID: %" PRIu32 ")", + LOG_DEBUG("unset breakpoint at " TARGET_ADDR_FMT " (ID: %" PRIu32 ")", breakpoint->address, breakpoint->unique_id); cortex_m_unset_breakpoint(target, breakpoint); @@ -782,7 +782,7 @@ static int cortex_m_resume(struct target *target, int current, /* int irqstepcount = 0; */ static int cortex_m_step(struct target *target, int current, - uint32_t address, int handle_breakpoints) + target_addr_t address, int handle_breakpoints) { struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = &cortex_m->armv7m; @@ -1198,7 +1198,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint breakpoint->set = true; } - LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: 0x%08" PRIx32 " Length: %d (set=%d)", + LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)", breakpoint->unique_id, (int)(breakpoint->type), breakpoint->address, @@ -1219,7 +1219,7 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi return ERROR_OK; } - LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: 0x%08" PRIx32 " Length: %d (set=%d)", + LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)", breakpoint->unique_id, (int)(breakpoint->type), breakpoint->address, @@ -1664,7 +1664,7 @@ static int cortex_m_store_core_reg_u32(struct target *target, return ERROR_OK; } -static int cortex_m_read_memory(struct target *target, uint32_t address, +static int cortex_m_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct armv7m_common *armv7m = target_to_armv7m(target); @@ -1678,7 +1678,7 @@ static int cortex_m_read_memory(struct target *target, uint32_t address, return mem_ap_read_buf(armv7m->debug_ap, buffer, size, count, address); } -static int cortex_m_write_memory(struct target *target, uint32_t address, +static int cortex_m_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct armv7m_common *armv7m = target_to_armv7m(target); diff --git a/src/target/dsp563xx.c b/src/target/dsp563xx.c index 783a0198..1d728dff 100644 --- a/src/target/dsp563xx.c +++ b/src/target/dsp563xx.c @@ -1117,7 +1117,7 @@ static int dsp563xx_halt(struct target *target) static int dsp563xx_resume(struct target *target, int current, - uint32_t address, + target_addr_t address, int handle_breakpoints, int debug_execution) { @@ -1290,7 +1290,7 @@ static int dsp563xx_step_ex(struct target *target, static int dsp563xx_step(struct target *target, int current, - uint32_t address, + target_addr_t address, int handle_breakpoints) { int err; @@ -1374,7 +1374,7 @@ static int dsp563xx_deassert_reset(struct target *target) static int dsp563xx_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - uint32_t entry_point, uint32_t exit_point, + target_addr_t entry_point, target_addr_t exit_point, int timeout_ms, void *arch_info) { int i; @@ -1592,7 +1592,7 @@ static int dsp563xx_read_memory_core(struct target *target, static int dsp563xx_read_memory(struct target *target, int mem_type, - uint32_t address, + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) @@ -1660,7 +1660,7 @@ static int dsp563xx_read_memory(struct target *target, } static int dsp563xx_read_memory_default(struct target *target, - uint32_t address, + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) @@ -1671,7 +1671,7 @@ static int dsp563xx_read_memory_default(struct target *target, } static int dsp563xx_read_buffer_default(struct target *target, - uint32_t address, + target_addr_t address, uint32_t size, uint8_t *buffer) { @@ -1682,7 +1682,7 @@ static int dsp563xx_read_buffer_default(struct target *target, static int dsp563xx_write_memory_core(struct target *target, int mem_type, - uint32_t address, + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) @@ -1694,7 +1694,7 @@ static int dsp563xx_write_memory_core(struct target *target, const uint8_t *b; LOG_DEBUG( - "memtype: %d address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + "memtype: %d address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", mem_type, address, size, @@ -1766,7 +1766,7 @@ static int dsp563xx_write_memory_core(struct target *target, static int dsp563xx_write_memory(struct target *target, int mem_type, - uint32_t address, + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) @@ -1834,7 +1834,7 @@ static int dsp563xx_write_memory(struct target *target, } static int dsp563xx_write_memory_default(struct target *target, - uint32_t address, + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) @@ -1844,7 +1844,7 @@ static int dsp563xx_write_memory_default(struct target *target, } static int dsp563xx_write_buffer_default(struct target *target, - uint32_t address, + target_addr_t address, uint32_t size, const uint8_t *buffer) { diff --git a/src/target/dsp5680xx.c b/src/target/dsp5680xx.c index 205d8fe4..a50f2cd4 100644 --- a/src/target/dsp5680xx.c +++ b/src/target/dsp5680xx.c @@ -1011,7 +1011,7 @@ static int dsp5680xx_poll(struct target *target) } static int dsp5680xx_resume(struct target *target, int current, - uint32_t address, int hb, int d) + target_addr_t address, int hb, int d) { if (target->state == TARGET_RUNNING) { LOG_USER("Target already running."); @@ -1168,7 +1168,7 @@ static int dsp5680xx_read_32_single(struct target *t, uint32_t a, return retval; } -static int dsp5680xx_read(struct target *t, uint32_t a, uint32_t size, +static int dsp5680xx_read(struct target *t, target_addr_t a, uint32_t size, uint32_t count, uint8_t *buf) { struct target *target = t; @@ -1423,7 +1423,7 @@ static int dsp5680xx_write_32(struct target *t, uint32_t a, uint32_t c, * * @return */ -static int dsp5680xx_write(struct target *t, uint32_t a, uint32_t s, uint32_t c, +static int dsp5680xx_write(struct target *t, target_addr_t a, uint32_t s, uint32_t c, const uint8_t *b) { /* TODO Cannot write 32bit to odd address, will write 0x12345678 as 0x5678 0x0012 */ @@ -1468,7 +1468,7 @@ static int dsp5680xx_write(struct target *t, uint32_t a, uint32_t s, uint32_t c, return retval; } -static int dsp5680xx_write_buffer(struct target *t, uint32_t a, uint32_t size, +static int dsp5680xx_write_buffer(struct target *t, target_addr_t a, uint32_t size, const uint8_t *b) { check_halt_and_debug(t); @@ -1485,7 +1485,7 @@ static int dsp5680xx_write_buffer(struct target *t, uint32_t a, uint32_t size, * * @return */ -static int dsp5680xx_read_buffer(struct target *t, uint32_t a, uint32_t size, +static int dsp5680xx_read_buffer(struct target *t, target_addr_t a, uint32_t size, uint8_t *buf) { check_halt_and_debug(t); @@ -1505,7 +1505,7 @@ static int dsp5680xx_read_buffer(struct target *t, uint32_t a, uint32_t size, * * @return */ -static int dsp5680xx_checksum_memory(struct target *t, uint32_t a, uint32_t s, +static int dsp5680xx_checksum_memory(struct target *t, target_addr_t a, uint32_t s, uint32_t *checksum) { return ERROR_FAIL; @@ -2262,7 +2262,7 @@ int dsp5680xx_f_lock(struct target *target) return retval; } -static int dsp5680xx_step(struct target *target, int current, uint32_t address, +static int dsp5680xx_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { err_check(ERROR_FAIL, DSP5680XX_ERROR_NOT_IMPLEMENTED_STEP, diff --git a/src/target/feroceon.c b/src/target/feroceon.c index f12e4e45..6b14ab6a 100644 --- a/src/target/feroceon.c +++ b/src/target/feroceon.c @@ -460,7 +460,7 @@ static int feroceon_examine_debug_reason(struct target *target) } static int feroceon_bulk_write_memory(struct target *target, - uint32_t address, uint32_t count, const uint8_t *buffer) + target_addr_t address, uint32_t count, const uint8_t *buffer) { int retval; struct arm *arm = target->arch_info; @@ -565,7 +565,7 @@ static int feroceon_bulk_write_memory(struct target *target, buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32); if (endaddress != address + count*4) { LOG_ERROR("DCC write failed," - " expected end address 0x%08" PRIx32 + " expected end address 0x%08" TARGET_PRIxADDR " got 0x%0" PRIx32 "", address + count*4, endaddress); retval = ERROR_FAIL; diff --git a/src/target/hla_target.c b/src/target/hla_target.c index feeb11f6..78dc8c51 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -584,7 +584,7 @@ static int adapter_halt(struct target *target) } static int adapter_resume(struct target *target, int current, - uint32_t address, int handle_breakpoints, + target_addr_t address, int handle_breakpoints, int debug_execution) { int res; @@ -594,8 +594,8 @@ static int adapter_resume(struct target *target, int current, struct breakpoint *breakpoint = NULL; struct reg *pc; - LOG_DEBUG("%s %d 0x%08" PRIx32 " %d %d", __func__, current, address, - handle_breakpoints, debug_execution); + LOG_DEBUG("%s %d " TARGET_ADDR_FMT " %d %d", __func__, current, + address, handle_breakpoints, debug_execution); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); @@ -642,7 +642,7 @@ static int adapter_resume(struct target *target, int current, /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { - LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 " (ID: %" PRIu32 ")", + LOG_DEBUG("unset breakpoint at " TARGET_ADDR_FMT " (ID: %" PRIu32 ")", breakpoint->address, breakpoint->unique_id); cortex_m_unset_breakpoint(target, breakpoint); @@ -675,7 +675,7 @@ static int adapter_resume(struct target *target, int current, } static int adapter_step(struct target *target, int current, - uint32_t address, int handle_breakpoints) + target_addr_t address, int handle_breakpoints) { int res; struct hl_interface_s *adapter = target_to_adapter(target); @@ -738,7 +738,7 @@ static int adapter_step(struct target *target, int current, return ERROR_OK; } -static int adapter_read_memory(struct target *target, uint32_t address, +static int adapter_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { @@ -747,12 +747,13 @@ static int adapter_read_memory(struct target *target, uint32_t address, if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; - LOG_DEBUG("%s 0x%08" PRIx32 " %" PRIu32 " %" PRIu32, __func__, address, size, count); + LOG_DEBUG("%s " TARGET_ADDR_FMT " %" PRIu32 " %" PRIu32, + __func__, address, size, count); return adapter->layout->api->read_mem(adapter->handle, address, size, count, buffer); } -static int adapter_write_memory(struct target *target, uint32_t address, +static int adapter_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { @@ -761,7 +762,8 @@ static int adapter_write_memory(struct target *target, uint32_t address, if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; - LOG_DEBUG("%s 0x%08" PRIx32 " %" PRIu32 " %" PRIu32, __func__, address, size, count); + LOG_DEBUG("%s " TARGET_ADDR_FMT " %" PRIu32 " %" PRIu32, + __func__, address, size, count); return adapter->layout->api->write_mem(adapter->handle, address, size, count, buffer); } diff --git a/src/target/image.h b/src/target/image.h index 9bf7af35..9907a5f3 100644 --- a/src/target/image.h +++ b/src/target/image.h @@ -46,7 +46,7 @@ enum image_type { }; struct imagesection { - uint32_t base_address; + target_addr_t base_address; uint32_t size; int flags; void *private; /* private data */ diff --git a/src/target/lakemont.c b/src/target/lakemont.c index 27efc694..2bd12fd4 100644 --- a/src/target/lakemont.c +++ b/src/target/lakemont.c @@ -994,7 +994,7 @@ int lakemont_halt(struct target *t) } } -int lakemont_resume(struct target *t, int current, uint32_t address, +int lakemont_resume(struct target *t, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { struct breakpoint *bp = NULL; @@ -1036,7 +1036,7 @@ int lakemont_resume(struct target *t, int current, uint32_t address, } int lakemont_step(struct target *t, int current, - uint32_t address, int handle_breakpoints) + target_addr_t address, int handle_breakpoints) { struct x86_32_common *x86_32 = target_to_x86_32(t); uint32_t eflags = buf_get_u32(x86_32->cache->reg_list[EFLAGS].value, 0, 32); diff --git a/src/target/lakemont.h b/src/target/lakemont.h index b07a0561..98efd44a 100644 --- a/src/target/lakemont.h +++ b/src/target/lakemont.h @@ -95,10 +95,10 @@ int lakemont_init_arch_info(struct target *t, struct x86_32_common *x86_32); int lakemont_poll(struct target *t); int lakemont_arch_state(struct target *t); int lakemont_halt(struct target *t); -int lakemont_resume(struct target *t, int current, uint32_t address, +int lakemont_resume(struct target *t, int current, target_addr_t address, int handle_breakpoints, int debug_execution); int lakemont_step(struct target *t, int current, - uint32_t address, int handle_breakpoints); + target_addr_t address, int handle_breakpoints); int lakemont_reset_assert(struct target *t); int lakemont_reset_deassert(struct target *t); int lakemont_update_after_probemode_entry(struct target *t); diff --git a/src/target/ls1_sap.c b/src/target/ls1_sap.c index b4d814bb..bc46ed4d 100644 --- a/src/target/ls1_sap.c +++ b/src/target/ls1_sap.c @@ -64,14 +64,14 @@ static int ls1_sap_halt(struct target *target) return ERROR_OK; } -static int ls1_sap_resume(struct target *target, int current, uint32_t address, +static int ls1_sap_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { LOG_DEBUG("%s", __func__); return ERROR_OK; } -static int ls1_sap_step(struct target *target, int current, uint32_t address, +static int ls1_sap_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { LOG_DEBUG("%s", __func__); @@ -178,10 +178,10 @@ static void ls1_sap_memory_write(struct jtag_tap *tap, uint32_t size, jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); } -static int ls1_sap_read_memory(struct target *target, uint32_t address, +static int ls1_sap_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { - LOG_DEBUG("Reading memory at physical address 0x%" PRIx32 + LOG_DEBUG("Reading memory at physical address 0x%" TARGET_PRIxADDR "; size %" PRId32 "; count %" PRId32, address, size, count); if (count == 0 || buffer == NULL) @@ -199,11 +199,11 @@ static int ls1_sap_read_memory(struct target *target, uint32_t address, return jtag_execute_queue(); } -static int ls1_sap_write_memory(struct target *target, uint32_t address, +static int ls1_sap_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { - LOG_DEBUG("Writing memory at physical address 0x%" PRIx32 + LOG_DEBUG("Writing memory at physical address 0x%" TARGET_PRIxADDR "; size %" PRId32 "; count %" PRId32, address, size, count); diff --git a/src/target/mips32.c b/src/target/mips32.c index 27caebee..93fb4e64 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -34,7 +34,7 @@ #include "register.h" static const char *mips_isa_strings[] = { - "MIPS32", "MIPS16" + "MIPS32", "MIPS16", "", "MICRO MIPS32", }; #define MIPS32_GDB_DUMMY_FP_REG 1 @@ -375,6 +375,7 @@ int mips32_init_arch_info(struct target *target, struct mips32_common *mips32, s target->arch_info = mips32; mips32->common_magic = MIPS32_COMMON_MAGIC; mips32->fast_data_area = NULL; + mips32->isa_imp = MIPS32_ONLY; /* default */ /* has breakpoint/watchpoint unit been scanned */ mips32->bp_scanned = 0; @@ -383,16 +384,18 @@ int mips32_init_arch_info(struct target *target, struct mips32_common *mips32, s mips32->ejtag_info.tap = tap; mips32->read_core_reg = mips32_read_core_reg; mips32->write_core_reg = mips32_write_core_reg; - - mips32->ejtag_info.scan_delay = MIPS32_SCAN_DELAY_LEGACY_MODE; /* Initial default value */ + /* if unknown endianness defaults to little endian, 1 */ + mips32->ejtag_info.endianness = target->endianness == TARGET_BIG_ENDIAN ? 0 : 1; + mips32->ejtag_info.scan_delay = MIPS32_SCAN_DELAY_LEGACY_MODE; mips32->ejtag_info.mode = 0; /* Initial default value */ - + mips32->ejtag_info.isa = 0; /* isa on debug mips32, updated by poll function */ + mips32->ejtag_info.config_regs = 0; /* no config register read */ return ERROR_OK; } /* run to exit point. return error if exit point was not reached. */ -static int mips32_run_and_wait(struct target *target, uint32_t entry_point, - int timeout_ms, uint32_t exit_point, struct mips32_common *mips32) +static int mips32_run_and_wait(struct target *target, target_addr_t entry_point, + int timeout_ms, target_addr_t exit_point, struct mips32_common *mips32) { uint32_t pc; int retval; @@ -425,8 +428,8 @@ static int mips32_run_and_wait(struct target *target, uint32_t entry_point, int mips32_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, - struct reg_param *reg_params, uint32_t entry_point, - uint32_t exit_point, int timeout_ms, void *arch_info) + struct reg_param *reg_params, target_addr_t entry_point, + target_addr_t exit_point, int timeout_ms, void *arch_info) { struct mips32_common *mips32 = target_to_mips32(target); struct mips32_algorithm *mips32_algorithm_info = arch_info; @@ -696,57 +699,109 @@ int mips32_enable_interrupts(struct target *target, int enable) return ERROR_OK; } -int mips32_checksum_memory(struct target *target, uint32_t address, +/* read config to config3 cp0 registers and log isa implementation */ +int mips32_read_config_regs(struct target *target) +{ + struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; + + if (ejtag_info->config_regs == 0) + for (int i = 0; i != 4; i++) { + int retval = mips32_cp0_read(ejtag_info, &ejtag_info->config[i], 16, i); + if (retval != ERROR_OK) { + LOG_ERROR("isa info not available, failed to read cp0 config register: %" PRId32, i); + ejtag_info->config_regs = 0; + return retval; + } + ejtag_info->config_regs = i + 1; + if ((ejtag_info->config[i] & (1 << 31)) == 0) + break; /* no more config registers implemented */ + } + else + return ERROR_OK; /* already succesfully read */ + + LOG_DEBUG("read %"PRId32" config registers", ejtag_info->config_regs); + + if (ejtag_info->impcode & EJTAG_IMP_MIPS16) { + mips32->isa_imp = MIPS32_MIPS16; + LOG_USER("MIPS32 with MIPS16 support implemented"); + + } else if (ejtag_info->config_regs >= 4) { /* config3 implemented */ + unsigned isa_imp = (ejtag_info->config[3] & MIPS32_CONFIG3_ISA_MASK) >> MIPS32_CONFIG3_ISA_SHIFT; + if (isa_imp == 1) { + mips32->isa_imp = MMIPS32_ONLY; + LOG_USER("MICRO MIPS32 only implemented"); + + } else if (isa_imp != 0) { + mips32->isa_imp = MIPS32_MMIPS32; + LOG_USER("MIPS32 and MICRO MIPS32 implemented"); + } + } + + if (mips32->isa_imp == MIPS32_ONLY) /* initial default value */ + LOG_USER("MIPS32 only implemented"); + + return ERROR_OK; +} +int mips32_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum) { struct working_area *crc_algorithm; struct reg_param reg_params[2]; struct mips32_algorithm mips32_info; - /* see contrib/loaders/checksum/mips32.s for src */ + struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; - static const uint32_t mips_crc_code[] = { - 0x248C0000, /* addiu $t4, $a0, 0 */ - 0x24AA0000, /* addiu $t2, $a1, 0 */ - 0x2404FFFF, /* addiu $a0, $zero, 0xffffffff */ - 0x10000010, /* beq $zero, $zero, ncomp */ - 0x240B0000, /* addiu $t3, $zero, 0 */ + /* see contrib/loaders/checksum/mips32.s for src */ + uint32_t isa = ejtag_info->isa ? 1 : 0; + + uint32_t mips_crc_code[] = { + MIPS32_ADDIU(isa, 12, 4, 0), /* addiu $t4, $a0, 0 */ + MIPS32_ADDIU(isa, 10, 5, 0), /* addiu $t2, $a1, 0 */ + MIPS32_ADDIU(isa, 4, 0, 0xFFFF), /* addiu $a0, $zero, 0xffff */ + MIPS32_BEQ(isa, 0, 0, 0x10 << isa), /* beq $zero, $zero, ncomp */ + MIPS32_ADDIU(isa, 11, 0, 0), /* addiu $t3, $zero, 0 */ /* nbyte: */ - 0x81850000, /* lb $a1, ($t4) */ - 0x218C0001, /* addi $t4, $t4, 1 */ - 0x00052E00, /* sll $a1, $a1, 24 */ - 0x3C0204C1, /* lui $v0, 0x04c1 */ - 0x00852026, /* xor $a0, $a0, $a1 */ - 0x34471DB7, /* ori $a3, $v0, 0x1db7 */ - 0x00003021, /* addu $a2, $zero, $zero */ - /* loop: */ - 0x00044040, /* sll $t0, $a0, 1 */ - 0x24C60001, /* addiu $a2, $a2, 1 */ - 0x28840000, /* slti $a0, $a0, 0 */ - 0x01074826, /* xor $t1, $t0, $a3 */ - 0x0124400B, /* movn $t0, $t1, $a0 */ - 0x28C30008, /* slti $v1, $a2, 8 */ - 0x1460FFF9, /* bne $v1, $zero, loop */ - 0x01002021, /* addu $a0, $t0, $zero */ - /* ncomp: */ - 0x154BFFF0, /* bne $t2, $t3, nbyte */ - 0x256B0001, /* addiu $t3, $t3, 1 */ - 0x7000003F, /* sdbbp */ + MIPS32_LB(isa, 5, 0, 12), /* lb $a1, ($t4) */ + MIPS32_ADDI(isa, 12, 12, 1), /* addi $t4, $t4, 1 */ + MIPS32_SLL(isa, 5, 5, 24), /* sll $a1, $a1, 24 */ + MIPS32_LUI(isa, 2, 0x04c1), /* lui $v0, 0x04c1 */ + MIPS32_XOR(isa, 4, 4, 5), /* xor $a0, $a0, $a1 */ + MIPS32_ORI(isa, 7, 2, 0x1db7), /* ori $a3, $v0, 0x1db7 */ + MIPS32_ADDU(isa, 6, 0, 0), /* addu $a2, $zero, $zero */ + /* loop */ + MIPS32_SLL(isa, 8, 4, 1), /* sll $t0, $a0, 1 */ + MIPS32_ADDIU(isa, 6, 6, 1), /* addiu $a2, $a2, 1 */ + MIPS32_SLTI(isa, 4, 4, 0), /* slti $a0, $a0, 0 */ + MIPS32_XOR(isa, 9, 8, 7), /* xor $t1, $t0, $a3 */ + MIPS32_MOVN(isa, 8, 9, 4), /* movn $t0, $t1, $a0 */ + MIPS32_SLTI(isa, 3, 6, 8), /* slti $v1, $a2, 8 */ + MIPS32_BNE(isa, 3, 0, NEG16(7 << isa)), /* bne $v1, $zero, loop */ + MIPS32_ADDU(isa, 4, 8, 0), /* addu $a0, $t0, $zero */ + /* ncomp */ + MIPS32_BNE(isa, 10, 11, NEG16(16 << isa)), /* bne $t2, $t3, nbyte */ + MIPS32_ADDIU(isa, 11, 11, 1), /* addiu $t3, $t3, 1 */ + MIPS32_SDBBP(isa), }; /* make sure we have a working area */ if (target_alloc_working_area(target, sizeof(mips_crc_code), &crc_algorithm) != ERROR_OK) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + pracc_swap16_array(ejtag_info, mips_crc_code, ARRAY_SIZE(mips_crc_code)); + /* convert mips crc code into a buffer in target endianness */ uint8_t mips_crc_code_8[sizeof(mips_crc_code)]; target_buffer_set_u32_array(target, mips_crc_code_8, ARRAY_SIZE(mips_crc_code), mips_crc_code); - target_write_buffer(target, crc_algorithm->address, sizeof(mips_crc_code), mips_crc_code_8); + int retval = target_write_buffer(target, crc_algorithm->address, sizeof(mips_crc_code), mips_crc_code_8); + if (retval != ERROR_OK) + return retval; mips32_info.common_magic = MIPS32_COMMON_MAGIC; - mips32_info.isa_mode = MIPS32_ISA_MIPS32; + mips32_info.isa_mode = isa ? MIPS32_ISA_MMIPS32 : MIPS32_ISA_MIPS32; /* run isa as in debug mode */ init_reg_param(®_params[0], "r4", 32, PARAM_IN_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); @@ -756,9 +811,8 @@ int mips32_checksum_memory(struct target *target, uint32_t address, int timeout = 20000 * (1 + (count / (1024 * 1024))); - int retval = target_run_algorithm(target, 0, NULL, 2, reg_params, - crc_algorithm->address, crc_algorithm->address + (sizeof(mips_crc_code) - 4), timeout, - &mips32_info); + retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, + crc_algorithm->address + (sizeof(mips_crc_code) - 4), timeout, &mips32_info); if (retval == ERROR_OK) *checksum = buf_get_u32(reg_params[0].value, 0, 32); @@ -773,41 +827,49 @@ int mips32_checksum_memory(struct target *target, uint32_t address, /** Checks whether a memory region is erased. */ int mips32_blank_check_memory(struct target *target, - uint32_t address, uint32_t count, uint32_t *blank, uint8_t erased_value) + target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value) { struct working_area *erase_check_algorithm; struct reg_param reg_params[3]; struct mips32_algorithm mips32_info; - static const uint32_t erase_check_code[] = { - /* nbyte: */ - 0x80880000, /* lb $t0, ($a0) */ - 0x00C83024, /* and $a2, $a2, $t0 */ - 0x24A5FFFF, /* addiu $a1, $a1, -1 */ - 0x14A0FFFC, /* bne $a1, $zero, nbyte */ - 0x24840001, /* addiu $a0, $a0, 1 */ - 0x7000003F /* sdbbp */ - }; + struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; if (erased_value != 0xff) { LOG_ERROR("Erase value 0x%02" PRIx8 " not yet supported for MIPS32", erased_value); return ERROR_FAIL; } + uint32_t isa = ejtag_info->isa ? 1 : 0; + uint32_t erase_check_code[] = { + /* nbyte: */ + MIPS32_LB(isa, 8, 0, 4), /* lb $t0, ($a0) */ + MIPS32_AND(isa, 6, 6, 8), /* and $a2, $a2, $t0 */ + MIPS32_ADDIU(isa, 5, 5, NEG16(1)), /* addiu $a1, $a1, -1 */ + MIPS32_BNE(isa, 5, 0, NEG16(4 << isa)), /* bne $a1, $zero, nbyte */ + MIPS32_ADDIU(isa, 4, 4, 1), /* addiu $a0, $a0, 1 */ + MIPS32_SDBBP(isa) /* sdbbp */ + }; /* make sure we have a working area */ if (target_alloc_working_area(target, sizeof(erase_check_code), &erase_check_algorithm) != ERROR_OK) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + pracc_swap16_array(ejtag_info, erase_check_code, ARRAY_SIZE(erase_check_code)); + /* convert erase check code into a buffer in target endianness */ uint8_t erase_check_code_8[sizeof(erase_check_code)]; target_buffer_set_u32_array(target, erase_check_code_8, ARRAY_SIZE(erase_check_code), erase_check_code); - target_write_buffer(target, erase_check_algorithm->address, sizeof(erase_check_code), erase_check_code_8); + int retval = target_write_buffer(target, erase_check_algorithm->address, + sizeof(erase_check_code), erase_check_code_8); + if (retval != ERROR_OK) + return retval; mips32_info.common_magic = MIPS32_COMMON_MAGIC; - mips32_info.isa_mode = MIPS32_ISA_MIPS32; + mips32_info.isa_mode = isa ? MIPS32_ISA_MMIPS32 : MIPS32_ISA_MIPS32; init_reg_param(®_params[0], "r4", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); @@ -818,10 +880,8 @@ int mips32_blank_check_memory(struct target *target, init_reg_param(®_params[2], "r6", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, erased_value); - int retval = target_run_algorithm(target, 0, NULL, 3, reg_params, - erase_check_algorithm->address, - erase_check_algorithm->address + (sizeof(erase_check_code) - 4), - 10000, &mips32_info); + retval = target_run_algorithm(target, 0, NULL, 3, reg_params, erase_check_algorithm->address, + erase_check_algorithm->address + (sizeof(erase_check_code) - 4), 10000, &mips32_info); if (retval == ERROR_OK) *blank = buf_get_u32(reg_params[2].value, 0, 32); diff --git a/src/target/mips32.h b/src/target/mips32.h index d493b39e..928598f4 100644 --- a/src/target/mips32.h +++ b/src/target/mips32.h @@ -58,6 +58,9 @@ #define MIPS32_CONFIG1_DL_SHIFT 10 #define MIPS32_CONFIG1_DL_MASK (0x7 << MIPS32_CONFIG1_DL_SHIFT) +#define MIPS32_CONFIG3_ISA_SHIFT 14 +#define MIPS32_CONFIG3_ISA_MASK (3 << MIPS32_CONFIG3_ISA_SHIFT) + #define MIPS32_ARCH_REL1 0x0 #define MIPS32_ARCH_REL2 0x1 @@ -73,6 +76,14 @@ enum { enum mips32_isa_mode { MIPS32_ISA_MIPS32 = 0, MIPS32_ISA_MIPS16E = 1, + MIPS32_ISA_MMIPS32 = 3, +}; + +enum mips32_isa_imp { + MIPS32_ONLY = 0, + MMIPS32_ONLY = 1, + MIPS32_MIPS16 = 2, + MIPS32_MMIPS32 = 3, }; struct mips32_comparator { @@ -88,6 +99,7 @@ struct mips32_common { struct mips_ejtag ejtag_info; uint32_t core_regs[MIPS32NUMCOREREGS]; enum mips32_isa_mode isa_mode; + enum mips32_isa_imp isa_imp; /* working area for fastdata access */ struct working_area *fast_data_area; @@ -122,44 +134,49 @@ struct mips32_algorithm { enum mips32_isa_mode isa_mode; }; -#define MIPS32_OP_ADDIU 0x21 -#define MIPS32_OP_ANDI 0x0C -#define MIPS32_OP_BEQ 0x04 -#define MIPS32_OP_BGTZ 0x07 -#define MIPS32_OP_BNE 0x05 -#define MIPS32_OP_ADDI 0x08 -#define MIPS32_OP_AND 0x24 -#define MIPS32_OP_CACHE 0x2F -#define MIPS32_OP_COP0 0x10 -#define MIPS32_OP_J 0x02 -#define MIPS32_OP_JR 0x08 -#define MIPS32_OP_LUI 0x0F -#define MIPS32_OP_LW 0x23 -#define MIPS32_OP_LBU 0x24 -#define MIPS32_OP_LHU 0x25 -#define MIPS32_OP_MFHI 0x10 -#define MIPS32_OP_MTHI 0x11 -#define MIPS32_OP_MFLO 0x12 -#define MIPS32_OP_MTLO 0x13 -#define MIPS32_OP_RDHWR 0x3B -#define MIPS32_OP_SB 0x28 -#define MIPS32_OP_SH 0x29 -#define MIPS32_OP_SW 0x2B -#define MIPS32_OP_ORI 0x0D -#define MIPS32_OP_XORI 0x0E -#define MIPS32_OP_XOR 0x26 -#define MIPS32_OP_SLTU 0x2B -#define MIPS32_OP_SRL 0x03 -#define MIPS32_OP_SYNCI 0x1F - -#define MIPS32_OP_REGIMM 0x01 -#define MIPS32_OP_SDBBP 0x3F -#define MIPS32_OP_SPECIAL 0x00 -#define MIPS32_OP_SPECIAL2 0x07 -#define MIPS32_OP_SPECIAL3 0x1F - -#define MIPS32_COP0_MF 0x00 -#define MIPS32_COP0_MT 0x04 +#define MIPS32_OP_ADDU 0x21u +#define MIPS32_OP_ADDIU 0x09u +#define MIPS32_OP_ANDI 0x0Cu +#define MIPS32_OP_BEQ 0x04u +#define MIPS32_OP_BGTZ 0x07u +#define MIPS32_OP_BNE 0x05u +#define MIPS32_OP_ADDI 0x08u +#define MIPS32_OP_AND 0x24u +#define MIPS32_OP_CACHE 0x2Fu +#define MIPS32_OP_COP0 0x10u +#define MIPS32_OP_J 0x02u +#define MIPS32_OP_JR 0x08u +#define MIPS32_OP_LUI 0x0Fu +#define MIPS32_OP_LW 0x23u +#define MIPS32_OP_LB 0x20u +#define MIPS32_OP_LBU 0x24u +#define MIPS32_OP_LHU 0x25u +#define MIPS32_OP_MFHI 0x10u +#define MIPS32_OP_MTHI 0x11u +#define MIPS32_OP_MFLO 0x12u +#define MIPS32_OP_MTLO 0x13u +#define MIPS32_OP_RDHWR 0x3Bu +#define MIPS32_OP_SB 0x28u +#define MIPS32_OP_SH 0x29u +#define MIPS32_OP_SW 0x2Bu +#define MIPS32_OP_ORI 0x0Du +#define MIPS32_OP_XORI 0x0Eu +#define MIPS32_OP_XOR 0x26u +#define MIPS32_OP_SLTU 0x2Bu +#define MIPS32_OP_SRL 0x03u +#define MIPS32_OP_SYNCI 0x1Fu +#define MIPS32_OP_SLL 0x00u +#define MIPS32_OP_SLTI 0x0Au +#define MIPS32_OP_MOVN 0x0Bu + +#define MIPS32_OP_REGIMM 0x01u +#define MIPS32_OP_SDBBP 0x3Fu +#define MIPS32_OP_SPECIAL 0x00u +#define MIPS32_OP_SPECIAL2 0x07u +#define MIPS32_OP_SPECIAL3 0x1Fu + +#define MIPS32_COP0_MF 0x00u +#define MIPS32_COP0_MT 0x04u #define MIPS32_R_INST(opcode, rs, rt, rd, shamt, funct) \ (((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | ((rd) << 11) | ((shamt) << 6) | (funct)) @@ -167,41 +184,52 @@ struct mips32_algorithm { (((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | (immd)) #define MIPS32_J_INST(opcode, addr) (((opcode) << 26) | (addr)) -#define MIPS32_NOP 0 -#define MIPS32_ADDI(tar, src, val) MIPS32_I_INST(MIPS32_OP_ADDI, src, tar, val) -#define MIPS32_ADDU(dst, src, tar) MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_ADDIU) -#define MIPS32_AND(reg, off, val) MIPS32_R_INST(0, off, val, reg, 0, MIPS32_OP_AND) -#define MIPS32_ANDI(tar, src, val) MIPS32_I_INST(MIPS32_OP_ANDI, src, tar, val) -#define MIPS32_B(off) MIPS32_BEQ(0, 0, off) -#define MIPS32_BEQ(src, tar, off) MIPS32_I_INST(MIPS32_OP_BEQ, src, tar, off) -#define MIPS32_BGTZ(reg, off) MIPS32_I_INST(MIPS32_OP_BGTZ, reg, 0, off) -#define MIPS32_BNE(src, tar, off) MIPS32_I_INST(MIPS32_OP_BNE, src, tar, off) -#define MIPS32_CACHE(op, off, base) MIPS32_I_INST(MIPS32_OP_CACHE, base, op, off) -#define MIPS32_J(tar) MIPS32_J_INST(MIPS32_OP_J, tar) -#define MIPS32_JR(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_JR) -#define MIPS32_MFC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP0_MF, gpr, cpr, 0, sel) -#define MIPS32_MTC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP0_MT, gpr, cpr, 0, sel) -#define MIPS32_LBU(reg, off, base) MIPS32_I_INST(MIPS32_OP_LBU, base, reg, off) -#define MIPS32_LHU(reg, off, base) MIPS32_I_INST(MIPS32_OP_LHU, base, reg, off) -#define MIPS32_LUI(reg, val) MIPS32_I_INST(MIPS32_OP_LUI, 0, reg, val) -#define MIPS32_LW(reg, off, base) MIPS32_I_INST(MIPS32_OP_LW, base, reg, off) -#define MIPS32_MFLO(reg) MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFLO) -#define MIPS32_MFHI(reg) MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFHI) -#define MIPS32_MTLO(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTLO) -#define MIPS32_MTHI(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTHI) -#define MIPS32_ORI(tar, src, val) MIPS32_I_INST(MIPS32_OP_ORI, src, tar, val) -#define MIPS32_XORI(tar, src, val) MIPS32_I_INST(MIPS32_OP_XORI, src, tar, val) -#define MIPS32_RDHWR(tar, dst) MIPS32_R_INST(MIPS32_OP_SPECIAL3, 0, tar, dst, 0, MIPS32_OP_RDHWR) -#define MIPS32_SB(reg, off, base) MIPS32_I_INST(MIPS32_OP_SB, base, reg, off) -#define MIPS32_SH(reg, off, base) MIPS32_I_INST(MIPS32_OP_SH, base, reg, off) -#define MIPS32_SW(reg, off, base) MIPS32_I_INST(MIPS32_OP_SW, base, reg, off) -#define MIPS32_XOR(reg, val1, val2) MIPS32_R_INST(0, val1, val2, reg, 0, MIPS32_OP_XOR) -#define MIPS32_SRL(reg, src, off) MIPS32_R_INST(0, 0, src, reg, off, MIPS32_OP_SRL) -#define MIPS32_SLTU(dst, src, tar) MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_SLTU) -#define MIPS32_SYNCI(off, base) MIPS32_I_INST(MIPS32_OP_REGIMM, base, MIPS32_OP_SYNCI, off) - -#define MIPS32_SYNC 0xF -#define MIPS32_SYNCI_STEP 0x1 /* reg num od address step size to be used with synci instruction */ +#define MIPS32_ISA_NOP 0 +#define MIPS32_ISA_ADDI(tar, src, val) MIPS32_I_INST(MIPS32_OP_ADDI, src, tar, val) +#define MIPS32_ISA_ADDIU(tar, src, val) MIPS32_I_INST(MIPS32_OP_ADDIU, src, tar, val) +#define MIPS32_ISA_ADDU(dst, src, tar) MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_ADDU) +#define MIPS32_ISA_AND(dst, src, tar) MIPS32_R_INST(0, src, tar, dst, 0, MIPS32_OP_AND) +#define MIPS32_ISA_ANDI(tar, src, val) MIPS32_I_INST(MIPS32_OP_ANDI, src, tar, val) + +#define MIPS32_ISA_B(off) MIPS32_ISA_BEQ(0, 0, off) +#define MIPS32_ISA_BEQ(src, tar, off) MIPS32_I_INST(MIPS32_OP_BEQ, src, tar, off) +#define MIPS32_ISA_BGTZ(reg, off) MIPS32_I_INST(MIPS32_OP_BGTZ, reg, 0, off) +#define MIPS32_ISA_BNE(src, tar, off) MIPS32_I_INST(MIPS32_OP_BNE, src, tar, off) +#define MIPS32_ISA_CACHE(op, off, base) MIPS32_I_INST(MIPS32_OP_CACHE, base, op, off) +#define MIPS32_ISA_J(tar) MIPS32_J_INST(MIPS32_OP_J, (0x0FFFFFFFu & (tar)) >> 2) +#define MIPS32_ISA_JR(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_JR) + +#define MIPS32_ISA_LB(reg, off, base) MIPS32_I_INST(MIPS32_OP_LB, base, reg, off) +#define MIPS32_ISA_LBU(reg, off, base) MIPS32_I_INST(MIPS32_OP_LBU, base, reg, off) +#define MIPS32_ISA_LHU(reg, off, base) MIPS32_I_INST(MIPS32_OP_LHU, base, reg, off) +#define MIPS32_ISA_LUI(reg, val) MIPS32_I_INST(MIPS32_OP_LUI, 0, reg, val) +#define MIPS32_ISA_LW(reg, off, base) MIPS32_I_INST(MIPS32_OP_LW, base, reg, off) + +#define MIPS32_ISA_MFC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP0_MF, gpr, cpr, 0, sel) +#define MIPS32_ISA_MTC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP0_MT, gpr, cpr, 0, sel) +#define MIPS32_ISA_MFLO(reg) MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFLO) +#define MIPS32_ISA_MFHI(reg) MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFHI) +#define MIPS32_ISA_MTLO(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTLO) +#define MIPS32_ISA_MTHI(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTHI) + +#define MIPS32_ISA_MOVN(dst, src, tar) MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_MOVN) +#define MIPS32_ISA_ORI(tar, src, val) MIPS32_I_INST(MIPS32_OP_ORI, src, tar, val) +#define MIPS32_ISA_RDHWR(tar, dst) MIPS32_R_INST(MIPS32_OP_SPECIAL3, 0, tar, dst, 0, MIPS32_OP_RDHWR) +#define MIPS32_ISA_SB(reg, off, base) MIPS32_I_INST(MIPS32_OP_SB, base, reg, off) +#define MIPS32_ISA_SH(reg, off, base) MIPS32_I_INST(MIPS32_OP_SH, base, reg, off) +#define MIPS32_ISA_SW(reg, off, base) MIPS32_I_INST(MIPS32_OP_SW, base, reg, off) + +#define MIPS32_ISA_SLL(dst, src, sa) MIPS32_R_INST(MIPS32_OP_SPECIAL, 0, src, dst, sa, MIPS32_OP_SLL) +#define MIPS32_ISA_SLTI(tar, src, val) MIPS32_I_INST(MIPS32_OP_SLTI, src, tar, val) +#define MIPS32_ISA_SLTU(dst, src, tar) MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_SLTU) +#define MIPS32_ISA_SRL(reg, src, off) MIPS32_R_INST(0, 0, src, reg, off, MIPS32_OP_SRL) +#define MIPS32_ISA_SYNC 0xFu +#define MIPS32_ISA_SYNCI(off, base) MIPS32_I_INST(MIPS32_OP_REGIMM, base, MIPS32_OP_SYNCI, off) + +#define MIPS32_ISA_XOR(reg, val1, val2) MIPS32_R_INST(0, val1, val2, reg, 0, MIPS32_OP_XOR) +#define MIPS32_ISA_XORI(tar, src, val) MIPS32_I_INST(MIPS32_OP_XORI, src, tar, val) + +#define MIPS32_ISA_SYNCI_STEP 0x1 /* reg num od address step size to be used with synci instruction */ /** * Cache operations definitions @@ -213,9 +241,158 @@ struct mips32_algorithm { #define MIPS32_CACHE_I_HIT_INVALIDATE ((0x0 << 0) | (0x4 << 2)) /* ejtag specific instructions */ -#define MIPS32_DRET 0x4200001F -#define MIPS32_SDBBP 0x7000003F /* MIPS32_J_INST(MIPS32_OP_SPECIAL2, MIPS32_OP_SDBBP) */ -#define MIPS16_SDBBP 0xE801 +#define MIPS32_ISA_DRET 0x4200001Fu +/* MIPS32_ISA_J_INST(MIPS32_ISA_OP_SPECIAL2, MIPS32_ISA_OP_SDBBP) */ +#define MIPS32_ISA_SDBBP 0x7000003Fu +#define MIPS16_ISA_SDBBP 0xE801u + +/*MICRO MIPS INSTRUCTIONS, see doc MD00582 */ +#define POOL32A 0X00u +#define POOL32AXf 0x3Cu +#define POOL32B 0x08u +#define POOL32I 0x10u +#define MMIPS32_OP_ADDI 0x04u +#define MMIPS32_OP_ADDIU 0x0Cu +#define MMIPS32_OP_ADDU 0x150u +#define MMIPS32_OP_AND 0x250u +#define MMIPS32_OP_ANDI 0x34u +#define MMIPS32_OP_BEQ 0x25u +#define MMIPS32_OP_BGTZ 0x06u +#define MMIPS32_OP_BNE 0x2Du +#define MMIPS32_OP_CACHE 0x06u +#define MMIPS32_OP_J 0x35u +#define MMIPS32_OP_JALR 0x03Cu +#define MMIPS32_OP_LB 0x07u +#define MMIPS32_OP_LBU 0x05u +#define MMIPS32_OP_LHU 0x0Du +#define MMIPS32_OP_LUI 0x0Du +#define MMIPS32_OP_LW 0x3Fu +#define MMIPS32_OP_MFC0 0x03u +#define MMIPS32_OP_MTC0 0x0Bu +#define MMIPS32_OP_MFLO 0x075u +#define MMIPS32_OP_MFHI 0x035u +#define MMIPS32_OP_MTLO 0x0F5u +#define MMIPS32_OP_MTHI 0x0B5u +#define MMIPS32_OP_MOVN 0x018u +#define MMIPS32_OP_ORI 0x14u +#define MMIPS32_OP_RDHWR 0x1ACu +#define MMIPS32_OP_SB 0x06u +#define MMIPS32_OP_SH 0x0Eu +#define MMIPS32_OP_SW 0x3Eu +#define MMIPS32_OP_SLTU 0x390u +#define MMIPS32_OP_SLL 0x000u +#define MMIPS32_OP_SLTI 0x24u +#define MMIPS32_OP_SRL 0x040u +#define MMIPS32_OP_SYNCI 0x10u +#define MMIPS32_OP_XOR 0x310u +#define MMIPS32_OP_XORI 0x1Cu + +#define MMIPS32_ADDI(tar, src, val) MIPS32_I_INST(MMIPS32_OP_ADDI, tar, src, val) +#define MMIPS32_ADDIU(tar, src, val) MIPS32_I_INST(MMIPS32_OP_ADDIU, tar, src, val) +#define MMIPS32_ADDU(dst, src, tar) MIPS32_R_INST(POOL32A, tar, src, dst, 0, MMIPS32_OP_ADDU) +#define MMIPS32_AND(dst, src, tar) MIPS32_R_INST(POOL32A, tar, src, dst, 0, MMIPS32_OP_AND) +#define MMIPS32_ANDI(tar, src, val) MIPS32_I_INST(MMIPS32_OP_ANDI, tar, src, val) + +#define MMIPS32_B(off) MMIPS32_BEQ(0, 0, off) +#define MMIPS32_BEQ(src, tar, off) MIPS32_I_INST(MMIPS32_OP_BEQ, tar, src, off) +#define MMIPS32_BGTZ(reg, off) MIPS32_I_INST(POOL32I, MMIPS32_OP_BGTZ, reg, off) +#define MMIPS32_BNE(src, tar, off) MIPS32_I_INST(MMIPS32_OP_BNE, tar, src, off) +#define MMIPS32_CACHE(op, off, base) MIPS32_R_INST(POOL32B, op, base, MMIPS32_OP_CACHE << 1, 0, off) + +#define MMIPS32_J(tar) MIPS32_J_INST(MMIPS32_OP_J, ((0x07FFFFFFu & ((tar) >> 1)))) +#define MMIPS32_JR(reg) MIPS32_R_INST(POOL32A, 0, reg, 0, MMIPS32_OP_JALR, POOL32AXf) +#define MMIPS32_LB(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LB, reg, base, off) +#define MMIPS32_LBU(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LBU, reg, base, off) +#define MMIPS32_LHU(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LHU, reg, base, off) +#define MMIPS32_LUI(reg, val) MIPS32_I_INST(POOL32I, MMIPS32_OP_LUI, reg, val) +#define MMIPS32_LW(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LW, reg, base, off) + +#define MMIPS32_MFC0(gpr, cpr, sel) MIPS32_R_INST(POOL32A, gpr, cpr, sel, MMIPS32_OP_MFC0, POOL32AXf) +#define MMIPS32_MFLO(reg) MIPS32_R_INST(POOL32A, 0, reg, 0, MMIPS32_OP_MFLO, POOL32AXf) +#define MMIPS32_MFHI(reg) MIPS32_R_INST(POOL32A, 0, reg, 0, MMIPS32_OP_MFHI, POOL32AXf) +#define MMIPS32_MTC0(gpr, cpr, sel) MIPS32_R_INST(POOL32A, gpr, cpr, sel, MMIPS32_OP_MTC0, POOL32AXf) +#define MMIPS32_MTLO(reg) MIPS32_R_INST(POOL32A, 0, reg, 0, MMIPS32_OP_MTLO, POOL32AXf) +#define MMIPS32_MTHI(reg) MIPS32_R_INST(POOL32A, 0, reg, 0, MMIPS32_OP_MTHI, POOL32AXf) + +#define MMIPS32_MOVN(dst, src, tar) MIPS32_R_INST(POOL32A, tar, src, dst, 0, MMIPS32_OP_MOVN) +#define MMIPS32_NOP 0 +#define MMIPS32_ORI(tar, src, val) MIPS32_I_INST(MMIPS32_OP_ORI, tar, src, val) +#define MMIPS32_RDHWR(tar, dst) MIPS32_R_INST(POOL32A, dst, tar, 0, MMIPS32_OP_RDHWR, POOL32AXf) +#define MMIPS32_SB(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SB, reg, base, off) +#define MMIPS32_SH(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SH, reg, base, off) +#define MMIPS32_SW(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SW, reg, base, off) + +#define MMIPS32_SRL(reg, src, off) MIPS32_R_INST(POOL32A, reg, src, off, 0, MMIPS32_OP_SRL) +#define MMIPS32_SLTU(dst, src, tar) MIPS32_R_INST(POOL32A, tar, src, dst, 0, MMIPS32_OP_SLTU) +#define MMIPS32_SYNCI(off, base) MIPS32_I_INST(POOL32I, MMIPS32_OP_SYNCI, base, off) +#define MMIPS32_SLL(dst, src, sa) MIPS32_R_INST(POOL32A, dst, src, sa, 0, MMIPS32_OP_SLL) +#define MMIPS32_SLTI(tar, src, val) MIPS32_I_INST(MMIPS32_OP_SLTI, tar, src, val) +#define MMIPS32_SYNC 0x00001A7Cu /* MIPS32_R_INST(POOL32A, 0, 0, 0, 0x1ADu, POOL32AXf) */ + +#define MMIPS32_XOR(reg, val1, val2) MIPS32_R_INST(POOL32A, val1, val2, reg, 0, MMIPS32_OP_XOR) +#define MMIPS32_XORI(tar, src, val) MIPS32_I_INST(MMIPS32_OP_XORI, tar, src, val) + +#define MMIPS32_SYNCI_STEP 0x1u /* reg num od address step size to be used with synci instruction */ + + +/* ejtag specific instructions */ +#define MMIPS32_DRET 0x0000E37Cu /* MIPS32_R_INST(POOL32A, 0, 0, 0, 0x38D, POOL32AXf) */ +#define MMIPS32_SDBBP 0x0000DB7Cu /* MIPS32_R_INST(POOL32A, 0, 0, 0, 0x1BD, POOL32AXf) */ +#define MMIPS16_SDBBP 0x46C0u /* POOL16C instr */ + +/* instruction code with isa selection */ +#define MIPS32_NOP 0 /* same for both isa's */ +#define MIPS32_ADDI(isa, tar, src, val) (isa ? MMIPS32_ADDI(tar, src, val) : MIPS32_ISA_ADDI(tar, src, val)) +#define MIPS32_ADDIU(isa, tar, src, val) (isa ? MMIPS32_ADDIU(tar, src, val) : MIPS32_ISA_ADDIU(tar, src, val)) +#define MIPS32_ADDU(isa, dst, src, tar) (isa ? MMIPS32_ADDU(dst, src, tar) : MIPS32_ISA_ADDU(dst, src, tar)) +#define MIPS32_AND(isa, dst, src, tar) (isa ? MMIPS32_AND(dst, src, tar) : MIPS32_ISA_AND(dst, src, tar)) +#define MIPS32_ANDI(isa, tar, src, val) (isa ? MMIPS32_ANDI(tar, src, val) : MIPS32_ISA_ANDI(tar, src, val)) + +#define MIPS32_B(isa, off) (isa ? MMIPS32_B(off) : MIPS32_ISA_B(off)) +#define MIPS32_BEQ(isa, src, tar, off) (isa ? MMIPS32_BEQ(src, tar, off) : MIPS32_ISA_BEQ(src, tar, off)) +#define MIPS32_BGTZ(isa, reg, off) (isa ? MMIPS32_BGTZ(reg, off) : MIPS32_ISA_BGTZ(reg, off)) +#define MIPS32_BNE(isa, src, tar, off) (isa ? MMIPS32_BNE(src, tar, off) : MIPS32_ISA_BNE(src, tar, off)) +#define MIPS32_CACHE(isa, op, off, base) (isa ? MMIPS32_CACHE(op, off, base) : MIPS32_ISA_CACHE(op, off, base)) + +#define MIPS32_J(isa, tar) (isa ? MMIPS32_J(tar) : MIPS32_ISA_J(tar)) +#define MIPS32_JR(isa, reg) (isa ? MMIPS32_JR(reg) : MIPS32_ISA_JR(reg)) +#define MIPS32_LB(isa, reg, off, base) (isa ? MMIPS32_LB(reg, off, base) : MIPS32_ISA_LB(reg, off, base)) +#define MIPS32_LBU(isa, reg, off, base) (isa ? MMIPS32_LBU(reg, off, base) : MIPS32_ISA_LBU(reg, off, base)) +#define MIPS32_LHU(isa, reg, off, base) (isa ? MMIPS32_LHU(reg, off, base) : MIPS32_ISA_LHU(reg, off, base)) +#define MIPS32_LW(isa, reg, off, base) (isa ? MMIPS32_LW(reg, off, base) : MIPS32_ISA_LW(reg, off, base)) +#define MIPS32_LUI(isa, reg, val) (isa ? MMIPS32_LUI(reg, val) : MIPS32_ISA_LUI(reg, val)) + +#define MIPS32_MFC0(isa, gpr, cpr, sel) (isa ? MMIPS32_MFC0(gpr, cpr, sel) : MIPS32_ISA_MFC0(gpr, cpr, sel)) +#define MIPS32_MTC0(isa, gpr, cpr, sel) (isa ? MMIPS32_MTC0(gpr, cpr, sel) : MIPS32_ISA_MTC0(gpr, cpr, sel)) +#define MIPS32_MFLO(isa, reg) (isa ? MMIPS32_MFLO(reg) : MIPS32_ISA_MFLO(reg)) +#define MIPS32_MFHI(isa, reg) (isa ? MMIPS32_MFHI(reg) : MIPS32_ISA_MFHI(reg)) +#define MIPS32_MTLO(isa, reg) (isa ? MMIPS32_MTLO(reg) : MIPS32_ISA_MTLO(reg)) +#define MIPS32_MTHI(isa, reg) (isa ? MMIPS32_MTHI(reg) : MIPS32_ISA_MTHI(reg)) + +#define MIPS32_MOVN(isa, dst, src, tar) (isa ? MMIPS32_MOVN(dst, src, tar) : MIPS32_ISA_MOVN(dst, src, tar)) +#define MIPS32_ORI(isa, tar, src, val) (isa ? MMIPS32_ORI(tar, src, val) : MIPS32_ISA_ORI(tar, src, val)) +#define MIPS32_RDHWR(isa, tar, dst) (isa ? MMIPS32_RDHWR(tar, dst) : MIPS32_ISA_RDHWR(tar, dst)) +#define MIPS32_SB(isa, reg, off, base) (isa ? MMIPS32_SB(reg, off, base) : MIPS32_ISA_SB(reg, off, base)) +#define MIPS32_SH(isa, reg, off, base) (isa ? MMIPS32_SH(reg, off, base) : MIPS32_ISA_SH(reg, off, base)) +#define MIPS32_SW(isa, reg, off, base) (isa ? MMIPS32_SW(reg, off, base) : MIPS32_ISA_SW(reg, off, base)) + +#define MIPS32_SLL(isa, dst, src, sa) (isa ? MMIPS32_SLL(dst, src, sa) : MIPS32_ISA_SLL(dst, src, sa)) +#define MIPS32_SLTI(isa, tar, src, val) (isa ? MMIPS32_SLTI(tar, src, val) : MIPS32_ISA_SLTI(tar, src, val)) +#define MIPS32_SLTU(isa, dst, src, tar) (isa ? MMIPS32_SLTU(dst, src, tar) : MIPS32_ISA_SLTU(dst, src, tar)) +#define MIPS32_SRL(isa, reg, src, off) (isa ? MMIPS32_SRL(reg, src, off) : MIPS32_ISA_SRL(reg, src, off)) + +#define MIPS32_SYNCI(isa, off, base) (isa ? MMIPS32_SYNCI(off, base) : MIPS32_ISA_SYNCI(off, base)) +#define MIPS32_SYNC(isa) (isa ? MMIPS32_SYNC : MIPS32_ISA_SYNC) +#define MIPS32_XOR(isa, reg, val1, val2) (isa ? MMIPS32_XOR(reg, val1, val2) : MIPS32_ISA_XOR(reg, val1, val2)) +#define MIPS32_XORI(isa, tar, src, val) (isa ? MMIPS32_XORI(tar, src, val) : MIPS32_ISA_XORI(tar, src, val)) + +#define MIPS32_SYNCI_STEP 0x1 + +/* ejtag specific instructions */ +#define MIPS32_DRET(isa) (isa ? MMIPS32_DRET : MIPS32_ISA_DRET) +#define MIPS32_SDBBP(isa) (isa ? MMIPS32_SDBBP : MIPS32_ISA_SDBBP) + +#define MIPS16_SDBBP(isa) (isa ? MMIPS16_SDBBP : MIPS16_ISA_SDBBP) extern const struct command_registration mips32_command_handlers[]; @@ -232,7 +409,7 @@ struct reg_cache *mips32_build_reg_cache(struct target *target); int mips32_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - uint32_t entry_point, uint32_t exit_point, + target_addr_t entry_point, target_addr_t exit_point, int timeout_ms, void *arch_info); int mips32_configure_break_unit(struct target *target); @@ -241,14 +418,16 @@ int mips32_enable_interrupts(struct target *target, int enable); int mips32_examine(struct target *target); +int mips32_read_config_regs(struct target *target); + int mips32_register_commands(struct command_context *cmd_ctx); int mips32_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); -int mips32_checksum_memory(struct target *target, uint32_t address, +int mips32_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); int mips32_blank_check_memory(struct target *target, - uint32_t address, uint32_t count, uint32_t *blank, uint8_t erased_value); + target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value); #endif /* OPENOCD_TARGET_MIPS32_H */ diff --git a/src/target/mips32_pracc.c b/src/target/mips32_pracc.c index 7cc0424f..790c8dc9 100644 --- a/src/target/mips32_pracc.c +++ b/src/target/mips32_pracc.c @@ -73,31 +73,20 @@ #include "mips32.h" #include "mips32_pracc.h" -struct mips32_pracc_context { - uint32_t *local_oparam; - int num_oparam; - const uint32_t *code; - int code_len; - uint32_t stack[32]; - int stack_offset; - struct mips_ejtag *ejtag_info; -}; - -static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl) +static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info) { - uint32_t ejtag_ctrl; int64_t then = timeval_ms(); /* wait for the PrAcc to become "1" */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); while (1) { - ejtag_ctrl = ejtag_info->ejtag_ctrl; - int retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); + ejtag_info->pa_ctrl = ejtag_info->ejtag_ctrl; + int retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_info->pa_ctrl); if (retval != ERROR_OK) return retval; - if (ejtag_ctrl & EJTAG_CTRL_PRACC) + if (ejtag_info->pa_ctrl & EJTAG_CTRL_PRACC) break; int64_t timeout = timeval_ms() - then; @@ -107,43 +96,38 @@ static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl) } } - *ctrl = ejtag_ctrl; return ERROR_OK; } /* Shift in control and address for a new processor access, save them in ejtag_info */ static int mips32_pracc_read_ctrl_addr(struct mips_ejtag *ejtag_info) { - int retval = wait_for_pracc_rw(ejtag_info, &ejtag_info->pa_ctrl); + int retval = wait_for_pracc_rw(ejtag_info); if (retval != ERROR_OK) return retval; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); - ejtag_info->pa_addr = 0; - retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_info->pa_addr); - return retval; + ejtag_info->pa_addr = 0; + return mips_ejtag_drscan_32(ejtag_info, &ejtag_info->pa_addr); } /* Finish processor access */ -static int mips32_pracc_finish(struct mips_ejtag *ejtag_info) +static void mips32_pracc_finish(struct mips_ejtag *ejtag_info) { uint32_t ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); mips_ejtag_drscan_32_out(ejtag_info, ctrl); - - return jtag_execute_queue(); } int mips32_pracc_clean_text_jump(struct mips_ejtag *ejtag_info) { - uint32_t jt_code = MIPS32_J((0x0FFFFFFF & MIPS32_PRACC_TEXT) >> 2); - int retval; - + uint32_t jt_code = MIPS32_J(ejtag_info->isa, MIPS32_PRACC_TEXT); + pracc_swap16_array(ejtag_info, &jt_code, 1); /* do 3 0/nops to clean pipeline before a jump to pracc text, NOP in delay slot */ for (int i = 0; i != 5; i++) { /* Wait for pracc */ - retval = wait_for_pracc_rw(ejtag_info, &ejtag_info->pa_ctrl); + int retval = wait_for_pracc_rw(ejtag_info); if (retval != ERROR_OK) return retval; @@ -153,25 +137,21 @@ int mips32_pracc_clean_text_jump(struct mips_ejtag *ejtag_info) mips_ejtag_drscan_32_out(ejtag_info, data); /* finish pa */ - retval = mips32_pracc_finish(ejtag_info); - if (retval != ERROR_OK) - return retval; + mips32_pracc_finish(ejtag_info); } if (ejtag_info->mode != 0) /* async mode support only for MIPS ... */ return ERROR_OK; for (int i = 0; i != 2; i++) { - retval = mips32_pracc_read_ctrl_addr(ejtag_info); + int retval = mips32_pracc_read_ctrl_addr(ejtag_info); if (retval != ERROR_OK) return retval; - if (ejtag_info->pa_addr != MIPS32_PRACC_TEXT) { /* LEXRA/BMIPS ?, shift out another NOP, max 2 */ + if (ejtag_info->pa_addr != MIPS32_PRACC_TEXT) { /* LEXRA/BMIPS ?, shift out another NOP, max 2 */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32_out(ejtag_info, MIPS32_NOP); - retval = mips32_pracc_finish(ejtag_info); - if (retval != ERROR_OK) - return retval; + mips32_pracc_finish(ejtag_info); } else break; } @@ -179,10 +159,11 @@ int mips32_pracc_clean_text_jump(struct mips_ejtag *ejtag_info) return ERROR_OK; } -int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx, uint32_t *param_out) +int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx, + uint32_t *param_out, bool check_last) { int code_count = 0; - int store_pending = 0; /* increases with every store instruction at dmseg, decreases with every store pa */ + int store_pending = 0; /* increases with every store instr at dmseg, decreases with every store pa */ uint32_t max_store_addr = 0; /* for store pa address testing */ bool restart = 0; /* restarting control */ int restart_count = 0; @@ -205,12 +186,12 @@ int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ct LOG_DEBUG("restarting code"); } - retval = mips32_pracc_read_ctrl_addr(ejtag_info); /* update current pa info: control and address */ + retval = mips32_pracc_read_ctrl_addr(ejtag_info); /* update current pa info: control and address */ if (retval != ERROR_OK) return retval; /* Check for read or write access */ - if (ejtag_info->pa_ctrl & EJTAG_CTRL_PRNW) { /* write/store access */ + if (ejtag_info->pa_ctrl & EJTAG_CTRL_PRNW) { /* write/store access */ /* Check for pending store from a previous store instruction at dmseg */ if (store_pending == 0) { LOG_DEBUG("unexpected write at address %" PRIx32, ejtag_info->pa_addr); @@ -221,8 +202,8 @@ int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ct return ERROR_JTAG_DEVICE_ERROR; } else { /* check address */ - if (ejtag_info->pa_addr < MIPS32_PRACC_PARAM_OUT || ejtag_info->pa_addr > max_store_addr) { - + if (ejtag_info->pa_addr < MIPS32_PRACC_PARAM_OUT || + ejtag_info->pa_addr > max_store_addr) { LOG_DEBUG("writing at unexpected address %" PRIx32, ejtag_info->pa_addr); return ERROR_JTAG_DEVICE_ERROR; } @@ -246,7 +227,8 @@ int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ct ejtag_info->pa_addr, MIPS32_PRACC_TEXT + code_count * 4); /* restart code execution only in some cases */ - if (code_count == 1 && ejtag_info->pa_addr == MIPS32_PRACC_TEXT && restart_count == 0) { + if (code_count == 1 && ejtag_info->pa_addr == MIPS32_PRACC_TEXT && + restart_count == 0) { LOG_DEBUG("restarting, without clean jump"); restart_count++; code_count = 0; @@ -255,18 +237,17 @@ int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ct restart = 1; continue; } - return ERROR_JTAG_DEVICE_ERROR; } /* check for store instruction at dmseg */ - uint32_t store_addr = ctx->pracc_list[ctx->max_code + code_count]; + uint32_t store_addr = ctx->pracc_list[code_count].addr; if (store_addr != 0) { if (store_addr > max_store_addr) max_store_addr = store_addr; store_pending++; } - instr = ctx->pracc_list[code_count++]; + instr = ctx->pracc_list[code_count++].instr; if (code_count == ctx->code_count) /* last instruction, start final check */ final_check = 1; @@ -284,13 +265,14 @@ int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ct } } else { if (ejtag_info->pa_addr != (MIPS32_PRACC_TEXT + code_count * 4)) { - LOG_DEBUG("unexpected read address in final check: %" PRIx32 ", expected: %x", - ejtag_info->pa_addr, MIPS32_PRACC_TEXT + code_count * 4); + LOG_DEBUG("unexpected read address in final check: %" + PRIx32 ", expected: %x", ejtag_info->pa_addr, + MIPS32_PRACC_TEXT + code_count * 4); return ERROR_JTAG_DEVICE_ERROR; } } if (!pass) { - if ((code_count - ctx->code_count) > 1) { /* allow max 2 instruction delay slot */ + if ((code_count - ctx->code_count) > 1) { /* allow max 2 instr delay slot */ LOG_DEBUG("failed to jump back to pracc text"); return ERROR_JTAG_DEVICE_ERROR; } @@ -308,12 +290,10 @@ int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ct mips_ejtag_drscan_32_out(ejtag_info, instr); } /* finish processor access, let the processor eat! */ - retval = mips32_pracc_finish(ejtag_info); - if (retval != ERROR_OK) - return retval; + mips32_pracc_finish(ejtag_info); - if (instr == MIPS32_DRET) /* after leaving debug mode nothing to do */ - return ERROR_OK; + if (final_check && !check_last) /* last instr, don't check, execute and exit */ + return jtag_execute_queue(); if (store_pending == 0 && pass) { /* store access done, but after passing pracc text */ LOG_DEBUG("warning: store access pass pracc text"); @@ -327,34 +307,63 @@ inline void pracc_queue_init(struct pracc_queue_info *ctx) ctx->retval = ERROR_OK; ctx->code_count = 0; ctx->store_count = 0; - - ctx->pracc_list = malloc(2 * ctx->max_code * sizeof(uint32_t)); - if (ctx->pracc_list == NULL) { - LOG_ERROR("Out of memory"); - ctx->retval = ERROR_FAIL; - } + ctx->max_code = 0; + ctx->pracc_list = NULL; + ctx->isa = ctx->ejtag_info->isa ? 1 : 0; } -inline void pracc_add(struct pracc_queue_info *ctx, uint32_t addr, uint32_t instr) +void pracc_add(struct pracc_queue_info *ctx, uint32_t addr, uint32_t instr) { - ctx->pracc_list[ctx->max_code + ctx->code_count] = addr; - ctx->pracc_list[ctx->code_count++] = instr; + if (ctx->retval != ERROR_OK) /* On previous out of memory, return */ + return; + if (ctx->code_count == ctx->max_code) { + void *p = realloc(ctx->pracc_list, sizeof(pa_list) * (ctx->max_code + PRACC_BLOCK)); + if (p) { + ctx->max_code += PRACC_BLOCK; + ctx->pracc_list = p; + } else { + ctx->retval = ERROR_FAIL; /* Out of memory */ + return; + } + } + ctx->pracc_list[ctx->code_count].instr = instr; + ctx->pracc_list[ctx->code_count++].addr = addr; if (addr) ctx->store_count++; } +void pracc_add_li32(struct pracc_queue_info *ctx, uint32_t reg_num, uint32_t data, bool optimize) +{ + if (LOWER16(data) == 0 && optimize) + pracc_add(ctx, 0, MIPS32_LUI(ctx->isa, reg_num, UPPER16(data))); /* load only upper value */ + else if (UPPER16(data) == 0 && optimize) + pracc_add(ctx, 0, MIPS32_ORI(ctx->isa, reg_num, 0, LOWER16(data))); /* load only lower */ + else { + pracc_add(ctx, 0, MIPS32_LUI(ctx->isa, reg_num, UPPER16(data))); /* load upper and lower */ + pracc_add(ctx, 0, MIPS32_ORI(ctx->isa, reg_num, reg_num, LOWER16(data))); + } +} + inline void pracc_queue_free(struct pracc_queue_info *ctx) { - if (ctx->code_count > ctx->max_code) /* Only for internal check, will be erased */ - LOG_ERROR("Internal error, code count: %d > max code: %d", ctx->code_count, ctx->max_code); if (ctx->pracc_list != NULL) free(ctx->pracc_list); } -int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx, uint32_t *buf) +int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx, + uint32_t *buf, bool check_last) { + if (ctx->retval != ERROR_OK) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + if (ejtag_info->isa && ejtag_info->endianness) + for (int i = 0; i != ctx->code_count; i++) + ctx->pracc_list[i].instr = SWAP16(ctx->pracc_list[i].instr); + if (ejtag_info->mode == 0) - return mips32_pracc_exec(ejtag_info, ctx, buf); + return mips32_pracc_exec(ejtag_info, ctx, buf, check_last); union scan_in { uint8_t scan_96[12]; @@ -377,16 +386,16 @@ int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_in mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ALL); int scan_count = 0; - for (int i = 0; i != 2 * ctx->code_count; i++) { - uint32_t data = 0; - if (i & 1u) { /* Check store address from previous instruction, if not the first */ - if (i < 2 || 0 == ctx->pracc_list[ctx->max_code + (i / 2) - 1]) - continue; - } else - data = ctx->pracc_list[i / 2]; - + for (int i = 0; i != ctx->code_count; i++) { jtag_add_clocks(num_clocks); - mips_ejtag_add_scan_96(ejtag_info, ejtag_ctrl, data, scan_in[scan_count++].scan_96); + mips_ejtag_add_scan_96(ejtag_info, ejtag_ctrl, ctx->pracc_list[i].instr, + scan_in[scan_count++].scan_96); + + /* Check store address from previous instruction, if not the first */ + if (i > 0 && ctx->pracc_list[i - 1].addr) { + jtag_add_clocks(num_clocks); + mips_ejtag_add_scan_96(ejtag_info, ejtag_ctrl, 0, scan_in[scan_count++].scan_96); + } } int retval = jtag_execute_queue(); /* execute queued scans */ @@ -395,24 +404,35 @@ int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_in uint32_t fetch_addr = MIPS32_PRACC_TEXT; /* start address */ scan_count = 0; - for (int i = 0; i != 2 * ctx->code_count; i++) { /* verify every pracc access */ - uint32_t store_addr = 0; - if (i & 1u) { /* Read store addres from previous instruction, if not the first */ - store_addr = ctx->pracc_list[ctx->max_code + (i / 2) - 1]; - if (i < 2 || 0 == store_addr) - continue; - } - + for (int i = 0; i != ctx->code_count; i++) { /* verify every pracc access */ + /* check pracc bit */ ejtag_ctrl = buf_get_u32(scan_in[scan_count].scan_32.ctrl, 0, 32); + uint32_t addr = buf_get_u32(scan_in[scan_count].scan_32.addr, 0, 32); if (!(ejtag_ctrl & EJTAG_CTRL_PRACC)) { LOG_ERROR("Error: access not pending count: %d", scan_count); retval = ERROR_FAIL; goto exit; } + if (ejtag_ctrl & EJTAG_CTRL_PRNW) { + LOG_ERROR("Not a fetch/read access, count: %d", scan_count); + retval = ERROR_FAIL; + goto exit; + } + if (addr != fetch_addr) { + LOG_ERROR("Fetch addr mismatch, read: %" PRIx32 " expected: %" PRIx32 " count: %d", + addr, fetch_addr, scan_count); + retval = ERROR_FAIL; + goto exit; + } + fetch_addr += 4; + scan_count++; - uint32_t addr = buf_get_u32(scan_in[scan_count].scan_32.addr, 0, 32); + /* check if previous intrucction is a store instruction at dmesg */ + if (i > 0 && ctx->pracc_list[i - 1].addr) { + uint32_t store_addr = ctx->pracc_list[i - 1].addr; + ejtag_ctrl = buf_get_u32(scan_in[scan_count].scan_32.ctrl, 0, 32); + addr = buf_get_u32(scan_in[scan_count].scan_32.addr, 0, 32); - if (store_addr != 0) { if (!(ejtag_ctrl & EJTAG_CTRL_PRNW)) { LOG_ERROR("Not a store/write access, count: %d", scan_count); retval = ERROR_FAIL; @@ -420,28 +440,14 @@ int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_in } if (addr != store_addr) { LOG_ERROR("Store address mismatch, read: %" PRIx32 " expected: %" PRIx32 " count: %d", - addr, store_addr, scan_count); + addr, store_addr, scan_count); retval = ERROR_FAIL; goto exit; } int buf_index = (addr - MIPS32_PRACC_PARAM_OUT) / 4; buf[buf_index] = buf_get_u32(scan_in[scan_count].scan_32.data, 0, 32); - - } else { - if (ejtag_ctrl & EJTAG_CTRL_PRNW) { - LOG_ERROR("Not a fetch/read access, count: %d", scan_count); - retval = ERROR_FAIL; - goto exit; - } - if (addr != fetch_addr) { - LOG_ERROR("Fetch addr mismatch, read: %" PRIx32 " expected: %" PRIx32 " count: %d", - addr, fetch_addr, scan_count); - retval = ERROR_FAIL; - goto exit; - } - fetch_addr += 4; + scan_count++; } - scan_count++; } exit: free(scan_in); @@ -450,23 +456,19 @@ int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_in int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *buf) { - struct pracc_queue_info ctx = {.max_code = 8}; + struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); - if (ctx.retval != ERROR_OK) - goto exit; - pracc_add(&ctx, 0, MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ - pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16((addr + 0x8000)))); /* load $8 with modified upper address */ - pracc_add(&ctx, 0, MIPS32_LW(8, LOWER16(addr), 8)); /* lw $8, LOWER16(addr)($8) */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 8, UPPER16((addr + 0x8000)))); /* load $8 with modified upper addr */ + pracc_add(&ctx, 0, MIPS32_LW(ctx.isa, 8, LOWER16(addr), 8)); /* lw $8, LOWER16(addr)($8) */ pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT, - MIPS32_SW(8, PRACC_OUT_OFFSET, 15)); /* sw $8,PRACC_OUT_OFFSET($15) */ - pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(ejtag_info->reg8))); /* restore upper 16 of $8 */ - pracc_add(&ctx, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 of $8 */ - pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */ - pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* move COP0 DeSave to $15 */ + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET, 15)); /* sw $8,PRACC_OUT_OFFSET($15) */ + pracc_add_li32(&ctx, 8, ejtag_info->reg8, 0); /* restore $8 */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ + pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* move COP0 DeSave to $15 */ - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, buf); -exit: + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, buf, 1); pracc_queue_free(&ctx); return ctx.retval; } @@ -476,12 +478,10 @@ int mips32_pracc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size if (count == 1 && size == 4) return mips32_pracc_read_u32(ejtag_info, addr, (uint32_t *)buf); - uint32_t *data = NULL; - struct pracc_queue_info ctx = {.max_code = 256 * 3 + 8 + 1}; /* alloc memory for the worst case */ + struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); - if (ctx.retval != ERROR_OK) - goto exit; + uint32_t *data = NULL; if (size != 4) { data = malloc(256 * sizeof(uint32_t)); if (data == NULL) { @@ -497,45 +497,44 @@ int mips32_pracc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size while (count) { ctx.code_count = 0; ctx.store_count = 0; + int this_round_count = (count > 256) ? 256 : count; uint32_t last_upper_base_addr = UPPER16((addr + 0x8000)); - pracc_add(&ctx, 0, MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ - pracc_add(&ctx, 0, MIPS32_LUI(9, last_upper_base_addr)); /* load the upper memory address in $9 */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 9, last_upper_base_addr)); /* upper memory addr to $9 */ for (int i = 0; i != this_round_count; i++) { /* Main code loop */ uint32_t upper_base_addr = UPPER16((addr + 0x8000)); - if (last_upper_base_addr != upper_base_addr) { /* if needed, change upper address in $9 */ - pracc_add(&ctx, 0, MIPS32_LUI(9, upper_base_addr)); + if (last_upper_base_addr != upper_base_addr) { /* if needed, change upper addr in $9 */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 9, upper_base_addr)); last_upper_base_addr = upper_base_addr; } - if (size == 4) - pracc_add(&ctx, 0, MIPS32_LW(8, LOWER16(addr), 9)); /* load from memory to $8 */ + if (size == 4) /* load from memory to $8 */ + pracc_add(&ctx, 0, MIPS32_LW(ctx.isa, 8, LOWER16(addr), 9)); else if (size == 2) - pracc_add(&ctx, 0, MIPS32_LHU(8, LOWER16(addr), 9)); + pracc_add(&ctx, 0, MIPS32_LHU(ctx.isa, 8, LOWER16(addr), 9)); else - pracc_add(&ctx, 0, MIPS32_LBU(8, LOWER16(addr), 9)); + pracc_add(&ctx, 0, MIPS32_LBU(ctx.isa, 8, LOWER16(addr), 9)); - pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + i * 4, - MIPS32_SW(8, PRACC_OUT_OFFSET + i * 4, 15)); /* store $8 at param out */ + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + i * 4, /* store $8 at param out */ + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + i * 4, 15)); addr += size; } - pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of reg 8 */ - pracc_add(&ctx, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of reg 8 */ - pracc_add(&ctx, 0, MIPS32_LUI(9, UPPER16(ejtag_info->reg9))); /* restore upper 16 bits of reg 9 */ - pracc_add(&ctx, 0, MIPS32_ORI(9, 9, LOWER16(ejtag_info->reg9))); /* restore lower 16 bits of reg 9 */ + pracc_add_li32(&ctx, 8, ejtag_info->reg8, 0); /* restore $8 */ + pracc_add_li32(&ctx, 9, ejtag_info->reg9, 0); /* restore $9 */ - pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */ - pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* restore $15 from DeSave */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ + pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave */ if (size == 4) { - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, buf32); + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, buf32, 1); if (ctx.retval != ERROR_OK) goto exit; buf32 += this_round_count; } else { - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, data); + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, data, 1); if (ctx.retval != ERROR_OK) goto exit; @@ -558,68 +557,37 @@ int mips32_pracc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size int mips32_cp0_read(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t cp0_reg, uint32_t cp0_sel) { - struct pracc_queue_info ctx = {.max_code = 7}; + struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); - if (ctx.retval != ERROR_OK) - goto exit; - pracc_add(&ctx, 0, MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ - pracc_add(&ctx, 0, MIPS32_MFC0(8, 0, 0) | (cp0_reg << 11) | cp0_sel); /* move COP0 [cp0_reg select] to $8 */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ + pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 8, cp0_reg, cp0_sel)); /* move cp0 reg / sel to $8 */ pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT, - MIPS32_SW(8, PRACC_OUT_OFFSET, 15)); /* store $8 to pracc_out */ - pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* move COP0 DeSave to $15 */ - pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of $8 */ - pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */ - pracc_add(&ctx, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of $8 */ + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET, 15)); /* store $8 to pracc_out */ + pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of $8 */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ + pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of $8 */ - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, val); -exit: + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, val, 1); pracc_queue_free(&ctx); return ctx.retval; - - /** - * Note that our input parametes cp0_reg and cp0_sel - * are numbers (not gprs) which make part of mfc0 instruction opcode. - * - * These are not fix, but can be different for each mips32_cp0_read() function call, - * and that is why we must insert them directly into opcode, - * i.e. we can not pass it on EJTAG microprogram stack (via param_in), - * and put them into the gprs later from MIPS32_PRACC_STACK - * because mfc0 do not use gpr as a parameter for the cp0_reg and select part, - * but plain (immediate) number. - * - * MIPS32_MTC0 is implemented via MIPS32_R_INST macro. - * In order to insert our parameters, we must change rd and funct fields. - * - * code[2] |= (cp0_reg << 11) | cp0_sel; change rd and funct of MIPS32_R_INST macro - **/ } int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_reg, uint32_t cp0_sel) { - struct pracc_queue_info ctx = {.max_code = 6}; + struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); - if (ctx.retval != ERROR_OK) - goto exit; - - pracc_add(&ctx, 0, MIPS32_LUI(15, UPPER16(val))); /* Load val to $15 */ - pracc_add(&ctx, 0, MIPS32_ORI(15, 15, LOWER16(val))); - pracc_add(&ctx, 0, MIPS32_MTC0(15, 0, 0) | (cp0_reg << 11) | cp0_sel); /* write cp0 reg / sel */ + pracc_add_li32(&ctx, 15, val, 0); /* Load val to $15 */ - pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */ - pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* move COP0 DeSave to $15 */ + pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, cp0_reg, cp0_sel)); /* write $15 to cp0 reg / sel */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ + pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave */ - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL); -exit: + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); pracc_queue_free(&ctx); return ctx.retval; - - /** - * Note that MIPS32_MTC0 macro is implemented via MIPS32_R_INST macro. - * In order to insert our parameters, we must change rd and funct fields. - * code[3] |= (cp0_reg << 11) | cp0_sel; change rd and funct fields of MIPS32_R_INST macro - **/ } /** @@ -652,26 +620,25 @@ int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_r static int mips32_pracc_synchronize_cache(struct mips_ejtag *ejtag_info, uint32_t start_addr, uint32_t end_addr, int cached, int rel) { - struct pracc_queue_info ctx = {.max_code = 256 * 2 + 5}; + struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); - if (ctx.retval != ERROR_OK) - goto exit; + /** Find cache line size in bytes */ uint32_t clsiz; if (rel) { /* Release 2 (rel = 1) */ - pracc_add(&ctx, 0, MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ - pracc_add(&ctx, 0, MIPS32_RDHWR(8, MIPS32_SYNCI_STEP)); /* load synci_step value to $8 */ + pracc_add(&ctx, 0, MIPS32_RDHWR(ctx.isa, 8, MIPS32_SYNCI_STEP)); /* load synci_step value to $8 */ pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT, - MIPS32_SW(8, PRACC_OUT_OFFSET, 15)); /* store $8 to pracc_out */ + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET, 15)); /* store $8 to pracc_out */ - pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of $8 */ - pracc_add(&ctx, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of $8 */ - pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */ - pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* move COP0 DeSave to $15 */ + pracc_add_li32(&ctx, 8, ejtag_info->reg8, 0); /* restore $8 */ - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, &clsiz); + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ + pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave */ + + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, &clsiz, 1); if (ctx.retval != ERROR_OK) goto exit; @@ -704,47 +671,50 @@ static int mips32_pracc_synchronize_cache(struct mips_ejtag *ejtag_info, end_addr |= clsiz - 1; ctx.code_count = 0; + ctx.store_count = 0; + int count = 0; uint32_t last_upper_base_addr = UPPER16((start_addr + 0x8000)); - pracc_add(&ctx, 0, MIPS32_LUI(15, last_upper_base_addr)); /* load upper memory base address to $15 */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, last_upper_base_addr)); /* load upper memory base addr to $15 */ while (start_addr <= end_addr) { /* main loop */ uint32_t upper_base_addr = UPPER16((start_addr + 0x8000)); - if (last_upper_base_addr != upper_base_addr) { /* if needed, change upper address in $15 */ - pracc_add(&ctx, 0, MIPS32_LUI(15, upper_base_addr)); + if (last_upper_base_addr != upper_base_addr) { /* if needed, change upper addr in $15 */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, upper_base_addr)); last_upper_base_addr = upper_base_addr; } - if (rel) - pracc_add(&ctx, 0, MIPS32_SYNCI(LOWER16(start_addr), 15)); /* synci instruction, offset($15) */ + if (rel) /* synci instruction, offset($15) */ + pracc_add(&ctx, 0, MIPS32_SYNCI(ctx.isa, LOWER16(start_addr), 15)); else { - if (cached == 3) - pracc_add(&ctx, 0, MIPS32_CACHE(MIPS32_CACHE_D_HIT_WRITEBACK, - LOWER16(start_addr), 15)); /* cache Hit_Writeback_D, offset($15) */ - - pracc_add(&ctx, 0, MIPS32_CACHE(MIPS32_CACHE_I_HIT_INVALIDATE, - LOWER16(start_addr), 15)); /* cache Hit_Invalidate_I, offset($15) */ + if (cached == 3) /* cache Hit_Writeback_D, offset($15) */ + pracc_add(&ctx, 0, MIPS32_CACHE(ctx.isa, MIPS32_CACHE_D_HIT_WRITEBACK, + LOWER16(start_addr), 15)); + /* cache Hit_Invalidate_I, offset($15) */ + pracc_add(&ctx, 0, MIPS32_CACHE(ctx.isa, MIPS32_CACHE_I_HIT_INVALIDATE, + LOWER16(start_addr), 15)); } start_addr += clsiz; count++; - if (count == 256 && start_addr <= end_addr) { /* more ?, then execute code list */ - pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */ - pracc_add(&ctx, 0, MIPS32_NOP); /* nop in delay slot */ + if (count == 256 && start_addr <= end_addr) { /* more ?, then execute code list */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* to start */ + pracc_add(&ctx, 0, MIPS32_NOP); /* nop in delay slot */ - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL); + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); if (ctx.retval != ERROR_OK) goto exit; - ctx.code_count = 0; + ctx.code_count = 0; /* reset counters for another loop */ + ctx.store_count = 0; count = 0; } } - pracc_add(&ctx, 0, MIPS32_SYNC); - pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */ - pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* restore $15 from DeSave*/ + pracc_add(&ctx, 0, MIPS32_SYNC(ctx.isa)); + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ + pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave*/ - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL); + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); exit: pracc_queue_free(&ctx); return ctx.retval; @@ -753,10 +723,8 @@ static int mips32_pracc_synchronize_cache(struct mips_ejtag *ejtag_info, static int mips32_pracc_write_mem_generic(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, const void *buf) { - struct pracc_queue_info ctx = {.max_code = 128 * 3 + 5 + 1}; /* alloc memory for the worst case */ + struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); - if (ctx.retval != ERROR_OK) - goto exit; const uint32_t *buf32 = buf; const uint16_t *buf16 = buf; @@ -765,50 +733,43 @@ static int mips32_pracc_write_mem_generic(struct mips_ejtag *ejtag_info, while (count) { ctx.code_count = 0; ctx.store_count = 0; + int this_round_count = (count > 128) ? 128 : count; uint32_t last_upper_base_addr = UPPER16((addr + 0x8000)); - - pracc_add(&ctx, 0, MIPS32_LUI(15, last_upper_base_addr)); /* load $15 with memory base address */ + /* load $15 with memory base address */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, last_upper_base_addr)); for (int i = 0; i != this_round_count; i++) { uint32_t upper_base_addr = UPPER16((addr + 0x8000)); - if (last_upper_base_addr != upper_base_addr) { - pracc_add(&ctx, 0, MIPS32_LUI(15, upper_base_addr)); /* if needed, change upper address in $15*/ + if (last_upper_base_addr != upper_base_addr) { /* if needed, change upper address in $15*/ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, upper_base_addr)); last_upper_base_addr = upper_base_addr; } - if (size == 4) { /* for word writes check if one half word is 0 and load it accordingly */ - if (LOWER16(*buf32) == 0) - pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(*buf32))); /* load only upper value */ - else if (UPPER16(*buf32) == 0) - pracc_add(&ctx, 0, MIPS32_ORI(8, 0, LOWER16(*buf32))); /* load only lower */ - else { - pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(*buf32))); /* load upper and lower */ - pracc_add(&ctx, 0, MIPS32_ORI(8, 8, LOWER16(*buf32))); - } - pracc_add(&ctx, 0, MIPS32_SW(8, LOWER16(addr), 15)); /* store word to memory */ + if (size == 4) { + pracc_add_li32(&ctx, 8, *buf32, 1); /* load with li32, optimize */ + pracc_add(&ctx, 0, MIPS32_SW(ctx.isa, 8, LOWER16(addr), 15)); /* store word to mem */ buf32++; } else if (size == 2) { - pracc_add(&ctx, 0, MIPS32_ORI(8, 0, *buf16)); /* load lower value */ - pracc_add(&ctx, 0, MIPS32_SH(8, LOWER16(addr), 15)); /* store half word to memory */ + pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 8, 0, *buf16)); /* load lower value */ + pracc_add(&ctx, 0, MIPS32_SH(ctx.isa, 8, LOWER16(addr), 15)); /* store half word */ buf16++; } else { - pracc_add(&ctx, 0, MIPS32_ORI(8, 0, *buf8)); /* load lower value */ - pracc_add(&ctx, 0, MIPS32_SB(8, LOWER16(addr), 15)); /* store byte to memory */ + pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 8, 0, *buf8)); /* load lower value */ + pracc_add(&ctx, 0, MIPS32_SB(ctx.isa, 8, LOWER16(addr), 15)); /* store byte */ buf8++; } addr += size; } - pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of reg 8 */ - pracc_add(&ctx, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of reg 8 */ + pracc_add_li32(&ctx, 8, ejtag_info->reg8, 0); /* restore $8 */ - pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */ - pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* restore $15 from DeSave */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ + pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave */ - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL); + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); if (ctx.retval != ERROR_OK) goto exit; count -= this_round_count; @@ -875,95 +836,77 @@ int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int siz int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs) { - static const uint32_t cp0_write_code[] = { - MIPS32_MTC0(1, 12, 0), /* move $1 to status */ - MIPS32_MTLO(1), /* move $1 to lo */ - MIPS32_MTHI(1), /* move $1 to hi */ - MIPS32_MTC0(1, 8, 0), /* move $1 to badvaddr */ - MIPS32_MTC0(1, 13, 0), /* move $1 to cause*/ - MIPS32_MTC0(1, 24, 0), /* move $1 to depc (pc) */ - }; - - struct pracc_queue_info ctx = {.max_code = 37 * 2 + 7 + 1}; + struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); - if (ctx.retval != ERROR_OK) - goto exit; - /* load registers 2 to 31 with lui and ori instructions, check if some instructions can be saved */ - for (int i = 2; i < 32; i++) { - if (LOWER16((regs[i])) == 0) /* if lower half word is 0, lui instruction only */ - pracc_add(&ctx, 0, MIPS32_LUI(i, UPPER16((regs[i])))); - else if (UPPER16((regs[i])) == 0) /* if upper half word is 0, ori with $0 only*/ - pracc_add(&ctx, 0, MIPS32_ORI(i, 0, LOWER16((regs[i])))); - else { /* default, load with lui and ori instructions */ - pracc_add(&ctx, 0, MIPS32_LUI(i, UPPER16((regs[i])))); - pracc_add(&ctx, 0, MIPS32_ORI(i, i, LOWER16((regs[i])))); - } - } + uint32_t cp0_write_code[] = { + MIPS32_MTC0(ctx.isa, 1, 12, 0), /* move $1 to status */ + MIPS32_MTLO(ctx.isa, 1), /* move $1 to lo */ + MIPS32_MTHI(ctx.isa, 1), /* move $1 to hi */ + MIPS32_MTC0(ctx.isa, 1, 8, 0), /* move $1 to badvaddr */ + MIPS32_MTC0(ctx.isa, 1, 13, 0), /* move $1 to cause*/ + MIPS32_MTC0(ctx.isa, 1, 24, 0), /* move $1 to depc (pc) */ + }; + + /* load registers 2 to 31 with li32, optimize */ + for (int i = 2; i < 32; i++) + pracc_add_li32(&ctx, i, regs[i], 1); for (int i = 0; i != 6; i++) { - pracc_add(&ctx, 0, MIPS32_LUI(1, UPPER16((regs[i + 32])))); /* load CPO value in $1, with lui and ori */ - pracc_add(&ctx, 0, MIPS32_ORI(1, 1, LOWER16((regs[i + 32])))); - pracc_add(&ctx, 0, cp0_write_code[i]); /* write value from $1 to CPO register */ + pracc_add_li32(&ctx, 1, regs[i + 32], 0); /* load CPO value in $1 */ + pracc_add(&ctx, 0, cp0_write_code[i]); /* write value from $1 to CPO register */ } - pracc_add(&ctx, 0, MIPS32_MTC0(15, 31, 0)); /* load $15 in DeSave */ - pracc_add(&ctx, 0, MIPS32_LUI(1, UPPER16((regs[1])))); /* load upper half word in $1 */ - pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */ - pracc_add(&ctx, 0, MIPS32_ORI(1, 1, LOWER16((regs[1])))); /* load lower half word in $1 */ + pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); /* load $15 in DeSave */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 1, UPPER16((regs[1])))); /* load upper half word in $1 */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ + pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 1, 1, LOWER16((regs[1])))); /* load lower half word in $1 */ - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL); + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); ejtag_info->reg8 = regs[8]; ejtag_info->reg9 = regs[9]; -exit: pracc_queue_free(&ctx); return ctx.retval; } int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs) { - static int cp0_read_code[] = { - MIPS32_MFC0(8, 12, 0), /* move status to $8 */ - MIPS32_MFLO(8), /* move lo to $8 */ - MIPS32_MFHI(8), /* move hi to $8 */ - MIPS32_MFC0(8, 8, 0), /* move badvaddr to $8 */ - MIPS32_MFC0(8, 13, 0), /* move cause to $8 */ - MIPS32_MFC0(8, 24, 0), /* move depc (pc) to $8 */ - }; - - struct pracc_queue_info ctx = {.max_code = 49}; + struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); - if (ctx.retval != ERROR_OK) - goto exit; - pracc_add(&ctx, 0, MIPS32_MTC0(1, 31, 0)); /* move $1 to COP0 DeSave */ - pracc_add(&ctx, 0, MIPS32_LUI(1, PRACC_UPPER_BASE_ADDR)); /* $1 = MIP32_PRACC_BASE_ADDR */ + uint32_t cp0_read_code[] = { + MIPS32_MFC0(ctx.isa, 8, 12, 0), /* move status to $8 */ + MIPS32_MFLO(ctx.isa, 8), /* move lo to $8 */ + MIPS32_MFHI(ctx.isa, 8), /* move hi to $8 */ + MIPS32_MFC0(ctx.isa, 8, 8, 0), /* move badvaddr to $8 */ + MIPS32_MFC0(ctx.isa, 8, 13, 0), /* move cause to $8 */ + MIPS32_MFC0(ctx.isa, 8, 24, 0), /* move depc (pc) to $8 */ + }; + + pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 1, 31, 0)); /* move $1 to COP0 DeSave */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 1, PRACC_UPPER_BASE_ADDR)); /* $1 = MIP32_PRACC_BASE_ADDR */ for (int i = 2; i != 32; i++) /* store GPR's 2 to 31 */ pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + (i * 4), - MIPS32_SW(i, PRACC_OUT_OFFSET + (i * 4), 1)); + MIPS32_SW(ctx.isa, i, PRACC_OUT_OFFSET + (i * 4), 1)); for (int i = 0; i != 6; i++) { pracc_add(&ctx, 0, cp0_read_code[i]); /* load COP0 needed registers to $8 */ pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + (i + 32) * 4, /* store $8 at PARAM OUT */ - MIPS32_SW(8, PRACC_OUT_OFFSET + (i + 32) * 4, 1)); + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + (i + 32) * 4, 1)); } - pracc_add(&ctx, 0, MIPS32_MFC0(8, 31, 0)); /* move DeSave to $8, reg1 value */ - pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + 4, /* store reg1 value from $8 to param out */ - MIPS32_SW(8, PRACC_OUT_OFFSET + 4, 1)); - - pracc_add(&ctx, 0, MIPS32_MFC0(1, 31, 0)); /* move COP0 DeSave to $1, restore reg1 */ - pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */ - pracc_add(&ctx, 0, MIPS32_MTC0(15, 31, 0)); /* load $15 in DeSave */ + pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 8, 31, 0)); /* move DeSave to $8, reg1 value */ + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + 4, /* store reg1 value from $8 to param out */ + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + 4, 1)); - if (ejtag_info->mode == 0) - ctx.store_count++; /* Needed by legacy code, due to offset from reg0 */ + pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 1, 31, 0)); /* move COP0 DeSave to $1, restore reg1 */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ + pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); /* load $15 in DeSave */ - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, regs); + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, regs, 1); ejtag_info->reg8 = regs[8]; /* reg8 is saved but not restored, next called function should restore it */ ejtag_info->reg9 = regs[9]; -exit: pracc_queue_free(&ctx); return ctx.retval; } @@ -978,70 +921,61 @@ int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs) int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_area *source, int write_t, uint32_t addr, int count, uint32_t *buf) { + uint32_t isa = ejtag_info->isa ? 1 : 0; uint32_t handler_code[] = { - /* caution when editing, table is modified below */ /* r15 points to the start of this code */ - MIPS32_SW(8, MIPS32_FASTDATA_HANDLER_SIZE - 4, 15), - MIPS32_SW(9, MIPS32_FASTDATA_HANDLER_SIZE - 8, 15), - MIPS32_SW(10, MIPS32_FASTDATA_HANDLER_SIZE - 12, 15), - MIPS32_SW(11, MIPS32_FASTDATA_HANDLER_SIZE - 16, 15), + MIPS32_SW(isa, 8, MIPS32_FASTDATA_HANDLER_SIZE - 4, 15), + MIPS32_SW(isa, 9, MIPS32_FASTDATA_HANDLER_SIZE - 8, 15), + MIPS32_SW(isa, 10, MIPS32_FASTDATA_HANDLER_SIZE - 12, 15), + MIPS32_SW(isa, 11, MIPS32_FASTDATA_HANDLER_SIZE - 16, 15), /* start of fastdata area in t0 */ - MIPS32_LUI(8, UPPER16(MIPS32_PRACC_FASTDATA_AREA)), - MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_FASTDATA_AREA)), - MIPS32_LW(9, 0, 8), /* start addr in t1 */ - MIPS32_LW(10, 0, 8), /* end addr to t2 */ - /* loop: */ - /* 8 */ MIPS32_LW(11, 0, 0), /* lw t3,[t8 | r9] */ - /* 9 */ MIPS32_SW(11, 0, 0), /* sw t3,[r9 | r8] */ - MIPS32_BNE(10, 9, NEG16(3)), /* bne $t2,t1,loop */ - MIPS32_ADDI(9, 9, 4), /* addi t1,t1,4 */ - - MIPS32_LW(8, MIPS32_FASTDATA_HANDLER_SIZE - 4, 15), - MIPS32_LW(9, MIPS32_FASTDATA_HANDLER_SIZE - 8, 15), - MIPS32_LW(10, MIPS32_FASTDATA_HANDLER_SIZE - 12, 15), - MIPS32_LW(11, MIPS32_FASTDATA_HANDLER_SIZE - 16, 15), - - MIPS32_LUI(15, UPPER16(MIPS32_PRACC_TEXT)), - MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_TEXT)), - MIPS32_JR(15), /* jr start */ - MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */ + MIPS32_LUI(isa, 8, UPPER16(MIPS32_PRACC_FASTDATA_AREA)), + MIPS32_ORI(isa, 8, 8, LOWER16(MIPS32_PRACC_FASTDATA_AREA)), + MIPS32_LW(isa, 9, 0, 8), /* start addr in t1 */ + MIPS32_LW(isa, 10, 0, 8), /* end addr to t2 */ + /* loop: */ + write_t ? MIPS32_LW(isa, 11, 0, 8) : MIPS32_LW(isa, 11, 0, 9), /* from xfer area : from memory */ + write_t ? MIPS32_SW(isa, 11, 0, 9) : MIPS32_SW(isa, 11, 0, 8), /* to memory : to xfer area */ + + MIPS32_BNE(isa, 10, 9, NEG16(3 << isa)), /* bne $t2,t1,loop */ + MIPS32_ADDI(isa, 9, 9, 4), /* addi t1,t1,4 */ + + MIPS32_LW(isa, 8, MIPS32_FASTDATA_HANDLER_SIZE - 4, 15), + MIPS32_LW(isa, 9, MIPS32_FASTDATA_HANDLER_SIZE - 8, 15), + MIPS32_LW(isa, 10, MIPS32_FASTDATA_HANDLER_SIZE - 12, 15), + MIPS32_LW(isa, 11, MIPS32_FASTDATA_HANDLER_SIZE - 16, 15), + + MIPS32_LUI(isa, 15, UPPER16(MIPS32_PRACC_TEXT)), + MIPS32_ORI(isa, 15, 15, LOWER16(MIPS32_PRACC_TEXT) | isa), /* isa bit for JR instr */ + MIPS32_JR(isa, 15), /* jr start */ + MIPS32_MFC0(isa, 15, 31, 0), /* move COP0 DeSave to $15 */ }; - uint32_t jmp_code[] = { - /* 0 */ MIPS32_LUI(15, 0), /* addr of working area added below */ - /* 1 */ MIPS32_ORI(15, 15, 0), /* addr of working area added below */ - MIPS32_JR(15), /* jump to ram program */ - MIPS32_NOP, - }; - - int retval, i; - uint32_t val, ejtag_ctrl, address; - if (source->size < MIPS32_FASTDATA_HANDLER_SIZE) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - if (write_t) { - handler_code[8] = MIPS32_LW(11, 0, 8); /* load data from probe at fastdata area */ - handler_code[9] = MIPS32_SW(11, 0, 9); /* store data to RAM @ r9 */ - } else { - handler_code[8] = MIPS32_LW(11, 0, 9); /* load data from RAM @ r9 */ - handler_code[9] = MIPS32_SW(11, 0, 8); /* store data to probe at fastdata area */ - } - - /* write program into RAM */ + pracc_swap16_array(ejtag_info, handler_code, ARRAY_SIZE(handler_code)); + /* write program into RAM */ if (write_t != ejtag_info->fast_access_save) { mips32_pracc_write_mem(ejtag_info, source->address, 4, ARRAY_SIZE(handler_code), handler_code); /* save previous operation to speed to any consecutive read/writes */ ejtag_info->fast_access_save = write_t; } - LOG_DEBUG("%s using 0x%.8" PRIx32 " for write handler", __func__, source->address); + LOG_DEBUG("%s using 0x%.8" TARGET_PRIxADDR " for write handler", __func__, source->address); + + uint32_t jmp_code[] = { + MIPS32_LUI(isa, 15, UPPER16(source->address)), /* load addr of jump in $15 */ + MIPS32_ORI(isa, 15, 15, LOWER16(source->address) | isa), /* isa bit for JR instr */ + MIPS32_JR(isa, 15), /* jump to ram program */ + isa ? MIPS32_XORI(isa, 15, 15, 1) : MIPS32_NOP, /* drop isa bit, needed for LW/SW instructions */ + }; - jmp_code[0] |= UPPER16(source->address); - jmp_code[1] |= LOWER16(source->address); + pracc_swap16_array(ejtag_info, jmp_code, ARRAY_SIZE(jmp_code)); - for (i = 0; i < (int) ARRAY_SIZE(jmp_code); i++) { - retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); + /* execute jump code, with no address check */ + for (unsigned i = 0; i < ARRAY_SIZE(jmp_code); i++) { + int retval = wait_for_pracc_rw(ejtag_info); if (retval != ERROR_OK) return retval; @@ -1049,32 +983,24 @@ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_are mips_ejtag_drscan_32_out(ejtag_info, jmp_code[i]); /* Clear the access pending bit (let the processor eat!) */ - ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; - mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); - mips_ejtag_drscan_32_out(ejtag_info, ejtag_ctrl); + mips32_pracc_finish(ejtag_info); } - /* wait PrAcc pending bit for FASTDATA write */ - retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); + /* wait PrAcc pending bit for FASTDATA write, read address */ + int retval = mips32_pracc_read_ctrl_addr(ejtag_info); if (retval != ERROR_OK) return retval; /* next fetch to dmseg should be in FASTDATA_AREA, check */ - address = 0; - mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); - retval = mips_ejtag_drscan_32(ejtag_info, &address); - if (retval != ERROR_OK) - return retval; - - if (address != MIPS32_PRACC_FASTDATA_AREA) + if (ejtag_info->pa_addr != MIPS32_PRACC_FASTDATA_AREA) return ERROR_FAIL; /* Send the load start address */ - val = addr; + uint32_t val = addr; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA); mips_ejtag_fastdata_scan(ejtag_info, 1, &val); - retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); + retval = wait_for_pracc_rw(ejtag_info); if (retval != ERROR_OK) return retval; @@ -1087,11 +1013,9 @@ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_are if (ejtag_info->mode != 0) num_clocks = ((uint64_t)(ejtag_info->scan_delay) * jtag_get_speed_khz() + 500000) / 1000000; - for (i = 0; i < count; i++) { + for (int i = 0; i < count; i++) { jtag_add_clocks(num_clocks); - retval = mips_ejtag_fastdata_scan(ejtag_info, write_t, buf++); - if (retval != ERROR_OK) - return retval; + mips_ejtag_fastdata_scan(ejtag_info, write_t, buf++); } retval = jtag_execute_queue(); @@ -1100,17 +1024,11 @@ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_are return retval; } - retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); - if (retval != ERROR_OK) - return retval; - - address = 0; - mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); - retval = mips_ejtag_drscan_32(ejtag_info, &address); + retval = mips32_pracc_read_ctrl_addr(ejtag_info); if (retval != ERROR_OK) return retval; - if (address != MIPS32_PRACC_TEXT) + if (ejtag_info->pa_addr != MIPS32_PRACC_TEXT) LOG_ERROR("mini program did not return to start"); return retval; diff --git a/src/target/mips32_pracc.h b/src/target/mips32_pracc.h index 2ede5b28..b8b93c64 100644 --- a/src/target/mips32_pracc.h +++ b/src/target/mips32_pracc.h @@ -34,26 +34,40 @@ #define MIPS32_PRACC_PARAM_OUT 0xFF202000 #define PRACC_UPPER_BASE_ADDR (MIPS32_PRACC_BASE_ADDR >> 16) +#define PRACC_MAX_CODE (MIPS32_PRACC_PARAM_OUT - MIPS32_PRACC_TEXT) +#define PRACC_MAX_INSTRUCTIONS (PRACC_MAX_CODE / 4) #define PRACC_OUT_OFFSET (MIPS32_PRACC_PARAM_OUT - MIPS32_PRACC_BASE_ADDR) #define MIPS32_FASTDATA_HANDLER_SIZE 0x80 #define UPPER16(uint32_t) (uint32_t >> 16) #define LOWER16(uint32_t) (uint32_t & 0xFFFF) #define NEG16(v) (((~(v)) + 1) & 0xFFFF) +#define SWAP16(v) ((LOWER16(v) << 16) | (UPPER16(v))) /*#define NEG18(v) (((~(v)) + 1) & 0x3FFFF)*/ +#define PRACC_BLOCK 128 /* 1 Kbyte */ + +typedef struct { + uint32_t instr; + uint32_t addr; +} pa_list; + struct pracc_queue_info { + struct mips_ejtag *ejtag_info; + unsigned isa; int retval; - const int max_code; int code_count; int store_count; - uint32_t *pracc_list; /* Code and store addresses */ + int max_code; /* max intstructions with currently allocated memory */ + pa_list *pracc_list; /* Code and store addresses at dmseg */ }; + void pracc_queue_init(struct pracc_queue_info *ctx); void pracc_add(struct pracc_queue_info *ctx, uint32_t addr, uint32_t instr); +void pracc_add_li32(struct pracc_queue_info *ctx, uint32_t reg_num, uint32_t data, bool optimize); void pracc_queue_free(struct pracc_queue_info *ctx); int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, - struct pracc_queue_info *ctx, uint32_t *buf); + struct pracc_queue_info *ctx, uint32_t *buf, bool check_last); int mips32_pracc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf); @@ -65,7 +79,8 @@ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_are int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs); int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs); -int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx, uint32_t *param_out); +int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx, + uint32_t *param_out, bool check_last); /** * \b mips32_cp0_read @@ -99,4 +114,11 @@ int mips32_cp0_read(struct mips_ejtag *ejtag_info, int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_reg, uint32_t cp0_sel); +inline void pracc_swap16_array(struct mips_ejtag *ejtag_info, uint32_t *buf, int count) +{ + if (ejtag_info->isa && ejtag_info->endianness) + for (int i = 0; i != count; i++) + buf[i] = SWAP16(buf[i]); +} + #endif /* OPENOCD_TARGET_MIPS32_PRACC_H */ diff --git a/src/target/mips_ejtag.c b/src/target/mips_ejtag.c index 594711fb..03a09529 100644 --- a/src/target/mips_ejtag.c +++ b/src/target/mips_ejtag.c @@ -28,74 +28,40 @@ #include "mips_ejtag.h" #include "mips32_dmaacc.h" -void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, int new_instr) +void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, uint32_t new_instr) { - struct jtag_tap *tap; + assert(ejtag_info->tap != NULL); + struct jtag_tap *tap = ejtag_info->tap; - tap = ejtag_info->tap; - assert(tap != NULL); + if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { - if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != (uint32_t)new_instr) { struct scan_field field; - uint8_t t[4]; - field.num_bits = tap->ir_length; + + uint8_t t[4]; field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); + field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); } } -int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info, uint32_t *idcode) +int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info) { - struct scan_field field; - uint8_t r[4]; - mips_ejtag_set_instr(ejtag_info, EJTAG_INST_IDCODE); - field.num_bits = 32; - field.out_value = NULL; - field.in_value = r; - - jtag_add_dr_scan(ejtag_info->tap, 1, &field, TAP_IDLE); - - int retval; - retval = jtag_execute_queue(); - if (retval != ERROR_OK) { - LOG_ERROR("register read failed"); - return retval; - } - - *idcode = buf_get_u32(field.in_value, 0, 32); - - return ERROR_OK; + ejtag_info->idcode = 0; + return mips_ejtag_drscan_32(ejtag_info, &ejtag_info->idcode); } -static int mips_ejtag_get_impcode(struct mips_ejtag *ejtag_info, uint32_t *impcode) +int mips_ejtag_get_impcode(struct mips_ejtag *ejtag_info) { - struct scan_field field; - uint8_t r[4]; - mips_ejtag_set_instr(ejtag_info, EJTAG_INST_IMPCODE); - field.num_bits = 32; - field.out_value = NULL; - field.in_value = r; - - jtag_add_dr_scan(ejtag_info->tap, 1, &field, TAP_IDLE); - - int retval; - retval = jtag_execute_queue(); - if (retval != ERROR_OK) { - LOG_ERROR("register read failed"); - return retval; - } - - *impcode = buf_get_u32(field.in_value, 0, 32); - - return ERROR_OK; + ejtag_info->impcode = 0; + return mips_ejtag_drscan_32(ejtag_info, &ejtag_info->impcode); } void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info, uint32_t ctrl, uint32_t data, uint8_t *in_scan_buf) @@ -121,91 +87,73 @@ void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info, uint32_t ctrl, uint32 keep_alive(); } -int mips_ejtag_drscan_32(struct mips_ejtag *ejtag_info, uint32_t *data) +void mips_ejtag_drscan_32_queued(struct mips_ejtag *ejtag_info, uint32_t data_out, uint8_t *data_in) { - struct jtag_tap *tap; - tap = ejtag_info->tap; - assert(tap != NULL); + assert(ejtag_info->tap != NULL); + struct jtag_tap *tap = ejtag_info->tap; struct scan_field field; - uint8_t t[4], r[4]; - int retval; - field.num_bits = 32; - field.out_value = t; - buf_set_u32(t, 0, field.num_bits, *data); - field.in_value = r; + uint8_t scan_out[4]; + field.out_value = scan_out; + buf_set_u32(scan_out, 0, field.num_bits, data_out); + + field.in_value = data_in; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); - retval = jtag_execute_queue(); + keep_alive(); +} + +int mips_ejtag_drscan_32(struct mips_ejtag *ejtag_info, uint32_t *data) +{ + uint8_t scan_in[4]; + mips_ejtag_drscan_32_queued(ejtag_info, *data, scan_in); + + int retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("register read failed"); return retval; } - *data = buf_get_u32(field.in_value, 0, 32); - - keep_alive(); - + *data = buf_get_u32(scan_in, 0, 32); return ERROR_OK; } void mips_ejtag_drscan_32_out(struct mips_ejtag *ejtag_info, uint32_t data) { - uint8_t t[4]; - struct jtag_tap *tap; - tap = ejtag_info->tap; - assert(tap != NULL); - - struct scan_field field; - - field.num_bits = 32; - field.out_value = t; - buf_set_u32(t, 0, field.num_bits, data); - - field.in_value = NULL; - - jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + mips_ejtag_drscan_32_queued(ejtag_info, data, NULL); } -int mips_ejtag_drscan_8(struct mips_ejtag *ejtag_info, uint32_t *data) +int mips_ejtag_drscan_8(struct mips_ejtag *ejtag_info, uint8_t *data) { - struct jtag_tap *tap; - tap = ejtag_info->tap; - assert(tap != NULL); + assert(ejtag_info->tap != NULL); + struct jtag_tap *tap = ejtag_info->tap; struct scan_field field; - uint8_t t[4] = {0, 0, 0, 0}, r[4]; - int retval; - field.num_bits = 8; - field.out_value = t; - buf_set_u32(t, 0, field.num_bits, *data); - field.in_value = r; + + field.out_value = data; + field.in_value = data; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); - retval = jtag_execute_queue(); + int retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("register read failed"); return retval; } - - *data = buf_get_u32(field.in_value, 0, 32); - return ERROR_OK; } void mips_ejtag_drscan_8_out(struct mips_ejtag *ejtag_info, uint8_t data) { - struct jtag_tap *tap; - tap = ejtag_info->tap; - assert(tap != NULL); + assert(ejtag_info->tap != NULL); + struct jtag_tap *tap = ejtag_info->tap; struct scan_field field; - field.num_bits = 8; + field.out_value = &data; field.in_value = NULL; @@ -215,23 +163,20 @@ void mips_ejtag_drscan_8_out(struct mips_ejtag *ejtag_info, uint8_t data) /* Set (to enable) or clear (to disable stepping) the SSt bit (bit 8) in Cp0 Debug reg (reg 23, sel 0) */ int mips_ejtag_config_step(struct mips_ejtag *ejtag_info, int enable_step) { - struct pracc_queue_info ctx = {.max_code = 7}; + struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); - if (ctx.retval != ERROR_OK) - goto exit; - pracc_add(&ctx, 0, MIPS32_MFC0(8, 23, 0)); /* move COP0 Debug to $8 */ - pracc_add(&ctx, 0, MIPS32_ORI(8, 8, 0x0100)); /* set SSt bit in debug reg */ + pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 8, 23, 0)); /* move COP0 Debug to $8 */ + pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 8, 8, 0x0100)); /* set SSt bit in debug reg */ if (!enable_step) - pracc_add(&ctx, 0, MIPS32_XORI(8, 8, 0x0100)); /* clear SSt bit in debug reg */ + pracc_add(&ctx, 0, MIPS32_XORI(ctx.isa, 8, 8, 0x0100)); /* clear SSt bit in debug reg */ - pracc_add(&ctx, 0, MIPS32_MTC0(8, 23, 0)); /* move $8 to COP0 Debug */ - pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of $8 */ - pracc_add(&ctx, 0, MIPS32_B(NEG16((ctx.code_count + 1)))); /* jump to start */ - pracc_add(&ctx, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of $8 */ + pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 8, 23, 0)); /* move $8 to COP0 Debug */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of $8 */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ + pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of $8 */ - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL); -exit: + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); pracc_queue_free(&ctx); return ctx.retval; } @@ -290,11 +235,11 @@ int mips_ejtag_enter_debug(struct mips_ejtag *ejtag_info) int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info) { - uint32_t pracc_list[] = {MIPS32_DRET, 0}; - struct pracc_queue_info ctx = {.max_code = 1, .pracc_list = pracc_list, .code_count = 1, .store_count = 0}; + pa_list pracc_list = {.instr = MIPS32_DRET(ejtag_info->isa), .addr = 0}; + struct pracc_queue_info ctx = {.max_code = 1, .pracc_list = &pracc_list, .code_count = 1, .store_count = 0}; /* execute our dret instruction */ - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL); + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 0); /* shift out instr, omit last check */ /* pic32mx workaround, false pending at low core clock */ jtag_add_sleep(1000); @@ -389,12 +334,11 @@ static void ejtag_main_print_imp(struct mips_ejtag *ejtag_info) int mips_ejtag_init(struct mips_ejtag *ejtag_info) { - int retval; - - retval = mips_ejtag_get_impcode(ejtag_info, &ejtag_info->impcode); - if (retval != ERROR_OK) + int retval = mips_ejtag_get_impcode(ejtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("impcode read failed"); return retval; - LOG_DEBUG("impcode: 0x%8.8" PRIx32 "", ejtag_info->impcode); + } /* get ejtag version */ ejtag_info->ejtag_version = ((ejtag_info->impcode >> 29) & 0x07); @@ -444,22 +388,22 @@ int mips_ejtag_init(struct mips_ejtag *ejtag_info) int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_t *data) { - struct jtag_tap *tap; - - tap = ejtag_info->tap; - assert(tap != NULL); + assert(ejtag_info->tap != NULL); + struct jtag_tap *tap = ejtag_info->tap; struct scan_field fields[2]; - uint8_t spracc = 0; - uint8_t t[4] = {0, 0, 0, 0}; /* fastdata 1-bit register */ fields[0].num_bits = 1; + + uint8_t spracc = 0; fields[0].out_value = &spracc; fields[0].in_value = NULL; /* processor access data register 32 bit */ fields[1].num_bits = 32; + + uint8_t t[4] = {0, 0, 0, 0}; fields[1].out_value = t; if (write_t) { diff --git a/src/target/mips_ejtag.h b/src/target/mips_ejtag.h index 6ef08675..71f5c1b4 100644 --- a/src/target/mips_ejtag.h +++ b/src/target/mips_ejtag.h @@ -58,6 +58,7 @@ #define EJTAG_CTRL_DERR (1 << 10) #define EJTAG_CTRL_DSTRT (1 << 11) #define EJTAG_CTRL_JTAGBRK (1 << 12) +#define EJTAG_CTRL_DBGISA (1 << 13) #define EJTAG_CTRL_SETDEV (1 << 14) #define EJTAG_CTRL_PROBEN (1 << 15) #define EJTAG_CTRL_PRRST (1 << 16) @@ -182,6 +183,9 @@ struct mips_ejtag { uint32_t idcode; uint32_t ejtag_ctrl; int fast_access_save; + uint32_t config_regs; /* number of config registers read */ + uint32_t config[4]; /* cp0 config to config3 */ + uint32_t reg8; uint32_t reg9; unsigned scan_delay; @@ -189,6 +193,8 @@ struct mips_ejtag { uint32_t pa_ctrl; uint32_t pa_addr; unsigned int ejtag_version; + uint32_t isa; + uint32_t endianness; /* Memory-Mapped Registers. This addresses are not same on different * EJTAG versions. */ @@ -210,17 +216,16 @@ struct mips_ejtag { uint32_t ejtag_dba_step_size; /* size of step till next *DBAn register. */ }; -void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, - int new_instr); +void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, uint32_t new_instr); int mips_ejtag_enter_debug(struct mips_ejtag *ejtag_info); int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info); -int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info, uint32_t *idcode); +int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info); void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info, uint32_t ctrl, uint32_t data, uint8_t *in_scan_buf); void mips_ejtag_drscan_32_out(struct mips_ejtag *ejtag_info, uint32_t data); int mips_ejtag_drscan_32(struct mips_ejtag *ejtag_info, uint32_t *data); void mips_ejtag_drscan_8_out(struct mips_ejtag *ejtag_info, uint8_t data); -int mips_ejtag_drscan_8(struct mips_ejtag *ejtag_info, uint32_t *data); +int mips_ejtag_drscan_8(struct mips_ejtag *ejtag_info, uint8_t *data); int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_t *data); int mips_ejtag_init(struct mips_ejtag *ejtag_info); diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index db69b95b..7d1c06cf 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -41,10 +41,10 @@ static int mips_m4k_set_breakpoint(struct target *target, static int mips_m4k_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); static int mips_m4k_internal_restore(struct target *target, int current, - uint32_t address, int handle_breakpoints, + target_addr_t address, int handle_breakpoints, int debug_execution); static int mips_m4k_halt(struct target *target); -static int mips_m4k_bulk_write_memory(struct target *target, uint32_t address, +static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer); static int mips_m4k_examine_debug_reason(struct target *target) @@ -108,11 +108,14 @@ static int mips_m4k_debug_entry(struct target *target) /* attempt to find halt reason */ mips_m4k_examine_debug_reason(target); + mips32_read_config_regs(target); + /* default to mips32 isa, it will be changed below if required */ mips32->isa_mode = MIPS32_ISA_MIPS32; - if (ejtag_info->impcode & EJTAG_IMP_MIPS16) - mips32->isa_mode = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1); + /* other than mips32 only and isa bit set ? */ + if (mips32->isa_imp && buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1)) + mips32->isa_mode = mips32->isa_imp == 2 ? MIPS32_ISA_MIPS16E : MIPS32_ISA_MMIPS32; LOG_DEBUG("entered debug state at PC 0x%" PRIx32 ", target->state: %s", buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32), @@ -195,6 +198,8 @@ static int mips_m4k_poll(struct target *target) if (retval != ERROR_OK) return retval; + ejtag_info->isa = (ejtag_ctrl & EJTAG_CTRL_DBGISA) ? 1 : 0; + /* clear this bit before handling polling * as after reset registers will read zero */ if (ejtag_ctrl & EJTAG_CTRL_ROCC) { @@ -429,7 +434,7 @@ static int mips_m4k_restore_smp(struct target *target, uint32_t address, int han } static int mips_m4k_internal_restore(struct target *target, int current, - uint32_t address, int handle_breakpoints, int debug_execution) + target_addr_t address, int handle_breakpoints, int debug_execution) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; @@ -449,12 +454,13 @@ static int mips_m4k_internal_restore(struct target *target, int current, /* current = 1: continue on current pc, otherwise continue at
*/ if (!current) { + mips_m4k_isa_filter(mips32->isa_imp, &address); buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address); mips32->core_cache->reg_list[MIPS32_PC].dirty = 1; mips32->core_cache->reg_list[MIPS32_PC].valid = 1; } - if (ejtag_info->impcode & EJTAG_IMP_MIPS16) + if ((mips32->isa_imp > 1) && debug_execution) /* if more than one isa supported */ buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1, mips32->isa_mode); if (!current) @@ -469,7 +475,8 @@ static int mips_m4k_internal_restore(struct target *target, int current, /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { - LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", breakpoint->address); + LOG_DEBUG("unset breakpoint at " TARGET_ADDR_FMT "", + breakpoint->address); mips_m4k_unset_breakpoint(target, breakpoint); mips_m4k_single_step_core(target); mips_m4k_set_breakpoint(target, breakpoint); @@ -500,7 +507,7 @@ static int mips_m4k_internal_restore(struct target *target, int current, } static int mips_m4k_resume(struct target *target, int current, - uint32_t address, int handle_breakpoints, int debug_execution) + target_addr_t address, int handle_breakpoints, int debug_execution) { int retval = ERROR_OK; @@ -527,7 +534,7 @@ static int mips_m4k_resume(struct target *target, int current, } static int mips_m4k_step(struct target *target, int current, - uint32_t address, int handle_breakpoints) + target_addr_t address, int handle_breakpoints) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); @@ -541,6 +548,7 @@ static int mips_m4k_step(struct target *target, int current, /* current = 1: continue on current pc, otherwise continue at
*/ if (!current) { + mips_m4k_isa_filter(mips32->isa_imp, &address); buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address); mips32->core_cache->reg_list[MIPS32_PC].dirty = 1; mips32->core_cache->reg_list[MIPS32_PC].valid = 1; @@ -623,6 +631,11 @@ static int mips_m4k_set_breakpoint(struct target *target, comparator_list[bp_num].used = 1; comparator_list[bp_num].bp_value = breakpoint->address; + if (breakpoint->length != 4) /* make sure isa bit set */ + comparator_list[bp_num].bp_value |= 1; + else /* make sure isa bit cleared */ + comparator_list[bp_num].bp_value &= ~1; + /* EJTAG 2.0 uses 30bit IBA. First 2 bits are reserved. * Warning: there is no IB ASID registers in 2.0. * Do not set it! :) */ @@ -640,41 +653,77 @@ static int mips_m4k_set_breakpoint(struct target *target, bp_num, comparator_list[bp_num].bp_value); } else if (breakpoint->type == BKPT_SOFT) { LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); - if (breakpoint->length == 4) { + + uint32_t isa_req = breakpoint->length & 1; /* micro mips request bit */ + uint32_t bplength = breakpoint->length & ~1; /* drop micro mips request bit for length */ + uint32_t bpaddr = breakpoint->address & ~1; /* drop isa bit from address, if set */ + + if (bplength == 4) { uint32_t verify = 0xffffffff; + uint32_t sdbbp32_instr = MIPS32_SDBBP(isa_req); + if (ejtag_info->endianness && isa_req) + sdbbp32_instr = SWAP16(sdbbp32_instr); - retval = target_read_memory(target, breakpoint->address, breakpoint->length, 1, - breakpoint->orig_instr); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, breakpoint->address, MIPS32_SDBBP); - if (retval != ERROR_OK) - return retval; + if ((breakpoint->address & 3) == 0) { /* word alligned */ - retval = target_read_u32(target, breakpoint->address, &verify); - if (retval != ERROR_OK) - return retval; - if (verify != MIPS32_SDBBP) { - LOG_ERROR("Unable to set 32bit breakpoint at address %08" PRIx32 - " - check that memory is read/writable", breakpoint->address); + retval = target_read_memory(target, bpaddr, bplength, 1, breakpoint->orig_instr); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, bpaddr, sdbbp32_instr); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, bpaddr, &verify); + if (retval != ERROR_OK) + return retval; + + if (verify != sdbbp32_instr) + verify = 0; + + } else { /* 16 bit aligned */ + retval = target_read_memory(target, bpaddr, 2, 2, breakpoint->orig_instr); + if (retval != ERROR_OK) + return retval; + + uint8_t sdbbp_buf[4]; + target_buffer_set_u32(target, sdbbp_buf, sdbbp32_instr); + + retval = target_write_memory(target, bpaddr, 2, 2, sdbbp_buf); + if (retval != ERROR_OK) + return retval; + + retval = target_read_memory(target, bpaddr, 2, 2, sdbbp_buf); + if (retval != ERROR_OK) + return retval; + + if (target_buffer_get_u32(target, sdbbp_buf) != sdbbp32_instr) + verify = 0; + } + + if (verify == 0) { + LOG_ERROR("Unable to set 32bit breakpoint at address %08" PRIx64 + " - check that memory is read/writable", breakpoint->address); return ERROR_OK; } + } else { uint16_t verify = 0xffff; - retval = target_read_memory(target, breakpoint->address, breakpoint->length, 1, - breakpoint->orig_instr); + retval = target_read_memory(target, bpaddr, bplength, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; - retval = target_write_u16(target, breakpoint->address, MIPS16_SDBBP); + + retval = target_write_u16(target, bpaddr, MIPS16_SDBBP(isa_req)); if (retval != ERROR_OK) return retval; - retval = target_read_u16(target, breakpoint->address, &verify); + retval = target_read_u16(target, bpaddr, &verify); if (retval != ERROR_OK) return retval; - if (verify != MIPS16_SDBBP) { - LOG_ERROR("Unable to set 16bit breakpoint at address %08" PRIx32 + + if (verify != MIPS16_SDBBP(isa_req)) { + LOG_ERROR("Unable to set 16bit breakpoint at address %08" PRIx64 " - check that memory is read/writable", breakpoint->address); return ERROR_OK; } @@ -717,46 +766,58 @@ static int mips_m4k_unset_breakpoint(struct target *target, } else { /* restore original instruction (kept in target endianness) */ + uint32_t isa_req = breakpoint->length & 1; + uint32_t bplength = breakpoint->length & ~1; + uint8_t current_instr[4]; LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); - if (breakpoint->length == 4) { - uint32_t current_instr; - - /* check that user program has not modified breakpoint instruction */ - retval = target_read_memory(target, breakpoint->address, 4, 1, - (uint8_t *)¤t_instr); - if (retval != ERROR_OK) - return retval; - - /** - * target_read_memory() gets us data in _target_ endianess. - * If we want to use this data on the host for comparisons with some macros - * we must first transform it to _host_ endianess using target_buffer_get_u32(). - */ - current_instr = target_buffer_get_u32(target, (uint8_t *)¤t_instr); - - if (current_instr == MIPS32_SDBBP) { - retval = target_write_memory(target, breakpoint->address, 4, 1, - breakpoint->orig_instr); + if (bplength == 4) { + uint32_t sdbbp32_instr = MIPS32_SDBBP(isa_req); + if (ejtag_info->endianness && isa_req) + sdbbp32_instr = SWAP16(sdbbp32_instr); + + if ((breakpoint->address & 3) == 0) { /* 32bit aligned */ + /* check that user program has not modified breakpoint instruction */ + retval = target_read_memory(target, breakpoint->address, 4, 1, current_instr); + if (retval != ERROR_OK) + return retval; + /** + * target_read_memory() gets us data in _target_ endianess. + * If we want to use this data on the host for comparisons with some macros + * we must first transform it to _host_ endianess using target_buffer_get_u16(). + */ + if (sdbbp32_instr == target_buffer_get_u32(target, current_instr)) { + retval = target_write_memory(target, breakpoint->address, 4, 1, + breakpoint->orig_instr); + if (retval != ERROR_OK) + return retval; + } + } else { /* 16bit alligned */ + retval = target_read_memory(target, breakpoint->address, 2, 2, current_instr); if (retval != ERROR_OK) return retval; + + if (sdbbp32_instr == target_buffer_get_u32(target, current_instr)) { + retval = target_write_memory(target, breakpoint->address, 2, 2, + breakpoint->orig_instr); + if (retval != ERROR_OK) + return retval; + } } } else { - uint16_t current_instr; - /* check that user program has not modified breakpoint instruction */ - retval = target_read_memory(target, breakpoint->address, 2, 1, - (uint8_t *)¤t_instr); + retval = target_read_memory(target, breakpoint->address, 2, 1, current_instr); if (retval != ERROR_OK) return retval; - current_instr = target_buffer_get_u16(target, (uint8_t *)¤t_instr); - if (current_instr == MIPS16_SDBBP) { + + if (target_buffer_get_u16(target, current_instr) == MIPS16_SDBBP(isa_req)) { retval = target_write_memory(target, breakpoint->address, 2, 1, - breakpoint->orig_instr); + breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } } } + breakpoint->set = 0; return ERROR_OK; @@ -766,6 +827,12 @@ static int mips_m4k_add_breakpoint(struct target *target, struct breakpoint *bre { struct mips32_common *mips32 = target_to_mips32(target); + if ((breakpoint->length > 5 || breakpoint->length < 2) || /* out of range */ + (breakpoint->length == 4 && (breakpoint->address & 2)) || /* mips32 unaligned */ + (mips32->isa_imp == MIPS32_ONLY && breakpoint->length != 4) || /* misp32 specific */ + ((mips32->isa_imp & 1) != (breakpoint->length & 1))) /* isa not implemented */ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + if (breakpoint->type == BKPT_HARD) { if (mips32->num_inst_bpoints_avail < 1) { LOG_INFO("no hardware breakpoint available"); @@ -949,13 +1016,13 @@ static void mips_m4k_enable_watchpoints(struct target *target) } } -static int mips_m4k_read_memory(struct target *target, uint32_t address, +static int mips_m4k_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; - LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); if (target->state != TARGET_HALTED) { @@ -1008,13 +1075,13 @@ static int mips_m4k_read_memory(struct target *target, uint32_t address, return retval; } -static int mips_m4k_write_memory(struct target *target, uint32_t address, +static int mips_m4k_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; - LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); if (target->state != TARGET_HALTED) { @@ -1107,39 +1174,33 @@ static int mips_m4k_target_create(struct target *target, Jim_Interp *interp) static int mips_m4k_examine(struct target *target) { - int retval; struct mips_m4k_common *mips_m4k = target_to_m4k(target); struct mips_ejtag *ejtag_info = &mips_m4k->mips32.ejtag_info; - uint32_t idcode = 0; if (!target_was_examined(target)) { - retval = mips_ejtag_get_idcode(ejtag_info, &idcode); - if (retval != ERROR_OK) + int retval = mips_ejtag_get_idcode(ejtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("idcode read failed"); return retval; - ejtag_info->idcode = idcode; - - if (((idcode >> 1) & 0x7FF) == 0x29) { + } + if (((ejtag_info->idcode >> 1) & 0x7FF) == 0x29) { /* we are using a pic32mx so select ejtag port * as it is not selected by default */ mips_ejtag_set_instr(ejtag_info, MTAP_SW_ETAP); - LOG_DEBUG("PIC32MX Detected - using EJTAG Interface"); + LOG_DEBUG("PIC32 Detected - using EJTAG Interface"); mips_m4k->is_pic32mx = true; } } /* init rest of ejtag interface */ - retval = mips_ejtag_init(ejtag_info); + int retval = mips_ejtag_init(ejtag_info); if (retval != ERROR_OK) return retval; - retval = mips32_examine(target); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; + return mips32_examine(target); } -static int mips_m4k_bulk_write_memory(struct target *target, uint32_t address, +static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer) { struct mips32_common *mips32 = target_to_mips32(target); @@ -1148,7 +1209,8 @@ static int mips_m4k_bulk_write_memory(struct target *target, uint32_t address, int retval; int write_t = 1; - LOG_DEBUG("address: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, count); + LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32 "", + address, count); /* check alignment */ if (address & 0x3u) @@ -1175,8 +1237,8 @@ static int mips_m4k_bulk_write_memory(struct target *target, uint32_t address, if (address <= fast_data_area->address + fast_data_area->size && fast_data_area->address <= address + count) { - LOG_ERROR("fast_data (0x%8.8" PRIx32 ") is within write area " - "(0x%8.8" PRIx32 "-0x%8.8" PRIx32 ").", + LOG_ERROR("fast_data (" TARGET_ADDR_FMT ") is within write area " + "(" TARGET_ADDR_FMT "-" TARGET_ADDR_FMT ").", fast_data_area->address, address, address + count); LOG_ERROR("Change work-area-phys or load_image address!"); return ERROR_FAIL; diff --git a/src/target/mips_m4k.h b/src/target/mips_m4k.h index cf826612..ea09ae52 100644 --- a/src/target/mips_m4k.h +++ b/src/target/mips_m4k.h @@ -41,6 +41,17 @@ target_to_m4k(struct target *target) struct mips_m4k_common, mips32); } +static inline void mips_m4k_isa_filter(enum mips32_isa_imp isa_imp, target_addr_t *addr) +{ + if (isa_imp <= 1) { /* if only one isa implemented */ + target_addr_t address = (*addr & ~1) | isa_imp; + + if (address != *addr) { + LOG_USER("Warning: isa bit changed due to isa not implemented"); + *addr = address; + } + } +} extern const struct command_registration mips_m4k_command_handlers[]; #endif /* OPENOCD_TARGET_MIPS_M4K_H */ diff --git a/src/target/nds32.c b/src/target/nds32.c index 2926b236..e4bb17f9 100644 --- a/src/target/nds32.c +++ b/src/target/nds32.c @@ -823,7 +823,7 @@ int nds32_read_memory(struct target *target, uint32_t address, return aice_read_mem_unit(aice, address, size, count, buffer); } -int nds32_read_phys_memory(struct target *target, uint32_t address, +int nds32_read_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct aice_port_s *aice = target_to_aice(target); @@ -932,7 +932,7 @@ int nds32_write_memory(struct target *target, uint32_t address, return aice_write_mem_unit(aice, address, size, count, buffer); } -int nds32_write_phys_memory(struct target *target, uint32_t address, +int nds32_write_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct aice_port_s *aice = target_to_aice(target); @@ -1674,7 +1674,7 @@ int nds32_init_arch_info(struct target *target, struct nds32 *nds32) return ERROR_OK; } -int nds32_virtual_to_physical(struct target *target, uint32_t address, uint32_t *physical) +int nds32_virtual_to_physical(struct target *target, target_addr_t address, target_addr_t *physical) { struct nds32 *nds32 = target_to_nds32(target); @@ -1692,7 +1692,7 @@ int nds32_virtual_to_physical(struct target *target, uint32_t address, uint32_t return ERROR_FAIL; } -int nds32_cache_sync(struct target *target, uint32_t address, uint32_t length) +int nds32_cache_sync(struct target *target, target_addr_t address, uint32_t length) { struct aice_port_s *aice = target_to_aice(target); struct nds32 *nds32 = target_to_nds32(target); @@ -1738,7 +1738,7 @@ int nds32_cache_sync(struct target *target, uint32_t address, uint32_t length) /* Because PSW.IT is turned off under debug exception, address MUST * be physical address. L1I_VA_INVALIDATE uses PSW.IT to decide * address translation or not. */ - uint32_t physical_addr; + target_addr_t physical_addr; if (ERROR_FAIL == target->type->virt2phys(target, cur_address, &physical_addr)) return ERROR_FAIL; @@ -1764,7 +1764,7 @@ uint32_t nds32_nextpc(struct nds32 *nds32, int current, uint32_t address) } int nds32_step(struct target *target, int current, - uint32_t address, int handle_breakpoints) + target_addr_t address, int handle_breakpoints) { LOG_DEBUG("target->state: %s", target_state_name(target)); @@ -1778,7 +1778,7 @@ int nds32_step(struct target *target, int current, address = nds32_nextpc(nds32, current, address); - LOG_DEBUG("STEP PC %08" PRIx32 "%s", address, !current ? "!" : ""); + LOG_DEBUG("STEP PC %08" TARGET_PRIxADDR "%s", address, !current ? "!" : ""); /** set DSSIM */ uint32_t ir14_value; @@ -2120,9 +2120,9 @@ int nds32_poll(struct target *target) } int nds32_resume(struct target *target, int current, - uint32_t address, int handle_breakpoints, int debug_execution) + target_addr_t address, int handle_breakpoints, int debug_execution) { - LOG_DEBUG("current %d address %08" PRIx32 + LOG_DEBUG("current %d address %08" TARGET_PRIxADDR " handle_breakpoints %d" " debug_execution %d", current, address, handle_breakpoints, debug_execution); @@ -2136,7 +2136,7 @@ int nds32_resume(struct target *target, int current, address = nds32_nextpc(nds32, current, address); - LOG_DEBUG("RESUME PC %08" PRIx32 "%s", address, !current ? "!" : ""); + LOG_DEBUG("RESUME PC %08" TARGET_PRIxADDR "%s", address, !current ? "!" : ""); if (!debug_execution) target_free_all_working_areas(target); diff --git a/src/target/nds32.h b/src/target/nds32.h index 88af4f3a..141dbf4c 100644 --- a/src/target/nds32.h +++ b/src/target/nds32.h @@ -400,23 +400,23 @@ extern int nds32_get_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t * extern int nds32_set_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t value); extern int nds32_edm_config(struct nds32 *nds32); -extern int nds32_cache_sync(struct target *target, uint32_t address, uint32_t length); +extern int nds32_cache_sync(struct target *target, target_addr_t address, uint32_t length); extern int nds32_mmu(struct target *target, int *enabled); -extern int nds32_virtual_to_physical(struct target *target, uint32_t address, - uint32_t *physical); -extern int nds32_read_phys_memory(struct target *target, uint32_t address, +extern int nds32_virtual_to_physical(struct target *target, target_addr_t address, + target_addr_t *physical); +extern int nds32_read_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); -extern int nds32_write_phys_memory(struct target *target, uint32_t address, +extern int nds32_write_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); extern uint32_t nds32_nextpc(struct nds32 *nds32, int current, uint32_t address); extern int nds32_examine_debug_reason(struct nds32 *nds32); extern int nds32_step(struct target *target, int current, - uint32_t address, int handle_breakpoints); + target_addr_t address, int handle_breakpoints); extern int nds32_target_state(struct nds32 *nds32, enum target_state *state); extern int nds32_halt(struct target *target); extern int nds32_poll(struct target *target); extern int nds32_resume(struct target *target, int current, - uint32_t address, int handle_breakpoints, int debug_execution); + target_addr_t address, int handle_breakpoints, int debug_execution); extern int nds32_assert_reset(struct target *target); extern int nds32_init(struct nds32 *nds32); extern int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info); diff --git a/src/target/nds32_aice.c b/src/target/nds32_aice.c index bdfafb53..e494a3e1 100644 --- a/src/target/nds32_aice.c +++ b/src/target/nds32_aice.c @@ -42,8 +42,8 @@ int aice_write_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t val) return aice->port->api->write_reg_64(aice->coreid, num, val); } -int aice_read_tlb(struct aice_port_s *aice, uint32_t virtual_address, - uint32_t *physical_address) +int aice_read_tlb(struct aice_port_s *aice, target_addr_t virtual_address, + target_addr_t *physical_address) { if (aice->port->api->read_tlb == NULL) { LOG_WARNING("Not implemented: %s", __func__); diff --git a/src/target/nds32_aice.h b/src/target/nds32_aice.h index ae801ed3..5ea3b161 100644 --- a/src/target/nds32_aice.h +++ b/src/target/nds32_aice.h @@ -23,8 +23,8 @@ int aice_read_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t *val); int aice_write_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t val); -int aice_read_tlb(struct aice_port_s *aice, uint32_t virtual_address, - uint32_t *physical_address); +int aice_read_tlb(struct aice_port_s *aice, target_addr_t virtual_address, + target_addr_t *physical_address); int aice_cache_ctl(struct aice_port_s *aice, uint32_t subtype, uint32_t address); int aice_set_retry_times(struct aice_port_s *aice, uint32_t a_retry_times); int aice_program_edm(struct aice_port_s *aice, char *command_sequence); diff --git a/src/target/nds32_tlb.c b/src/target/nds32_tlb.c index 6a91a0f8..c4bce1a6 100644 --- a/src/target/nds32_tlb.c +++ b/src/target/nds32_tlb.c @@ -22,8 +22,8 @@ #include "nds32_aice.h" #include "nds32_tlb.h" -int nds32_probe_tlb(struct nds32 *nds32, const uint32_t virtual_address, - uint32_t *physical_address) +int nds32_probe_tlb(struct nds32 *nds32, const target_addr_t virtual_address, + target_addr_t *physical_address) { struct target *target = nds32->target; struct aice_port_s *aice = target_to_aice(target); @@ -38,8 +38,8 @@ struct page_table_walker_info_s page_table_info[PAGE_SIZE_NUM] = { {0xFF000000, 22, 0x00FFE000, 11, 0x00001FFF, 0xFFFFF000, 0xFFFFE000, 0xFFFFE000}, }; -int nds32_walk_page_table(struct nds32 *nds32, const uint32_t virtual_address, - uint32_t *physical_address) +int nds32_walk_page_table(struct nds32 *nds32, const target_addr_t virtual_address, + target_addr_t *physical_address) { struct target *target = nds32->target; uint32_t value_mr1; diff --git a/src/target/nds32_tlb.h b/src/target/nds32_tlb.h index ada2c198..62512c11 100644 --- a/src/target/nds32_tlb.h +++ b/src/target/nds32_tlb.h @@ -39,9 +39,9 @@ struct page_table_walker_info_s { uint32_t ppn_mask; }; -extern int nds32_probe_tlb(struct nds32 *nds32, const uint32_t virtual_address, - uint32_t *physical_address); -extern int nds32_walk_page_table(struct nds32 *nds32, const uint32_t virtual_address, - uint32_t *physical_address); +extern int nds32_probe_tlb(struct nds32 *nds32, const target_addr_t virtual_address, + target_addr_t *physical_address); +extern int nds32_walk_page_table(struct nds32 *nds32, const target_addr_t virtual_address, + target_addr_t *physical_address); #endif /* OPENOCD_TARGET_NDS32_TLB_H */ diff --git a/src/target/nds32_v2.c b/src/target/nds32_v2.c index 4497551a..29489a03 100644 --- a/src/target/nds32_v2.c +++ b/src/target/nds32_v2.c @@ -112,7 +112,7 @@ static int nds32_v2_activate_hardware_breakpoint(struct target *target) /* enable breakpoint (physical address) */ aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0xA); - LOG_DEBUG("Add hardware BP %" PRId32 " at %08" PRIx32, hbr_index, + LOG_DEBUG("Add hardware BP %" PRId32 " at %08" TARGET_PRIxADDR, hbr_index, bp->address); hbr_index++; @@ -139,7 +139,7 @@ static int nds32_v2_deactivate_hardware_breakpoint(struct target *target) else return ERROR_FAIL; - LOG_DEBUG("Remove hardware BP %" PRId32 " at %08" PRIx32, hbr_index, + LOG_DEBUG("Remove hardware BP %" PRId32 " at %08" TARGET_PRIxADDR, hbr_index, bp->address); hbr_index++; @@ -184,7 +184,7 @@ static int nds32_v2_activate_hardware_watchpoint(struct target *target) /* set value */ aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + wp_num, 0); - LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" PRIx32 " mask %08" PRIx32, wp_num, + LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR " mask %08" PRIx32, wp_num, wp->address, wp->mask); } @@ -204,7 +204,7 @@ static int nds32_v2_deactivate_hardware_watchpoint(struct target *target) /* disable watchpoint */ aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0); - LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" PRIx32 " mask %08" PRIx32, + LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR " mask %08" PRIx32, wp_num, wp->address, wp->mask); } @@ -405,7 +405,7 @@ static int nds32_v2_deassert_reset(struct target *target) } static int nds32_v2_checksum_memory(struct target *target, - uint32_t address, uint32_t count, uint32_t *checksum) + target_addr_t address, uint32_t count, uint32_t *checksum) { LOG_WARNING("Not implemented: %s", __func__); @@ -561,8 +561,8 @@ static int nds32_v2_run_algorithm(struct target *target, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - uint32_t entry_point, - uint32_t exit_point, + target_addr_t entry_point, + target_addr_t exit_point, int timeout_ms, void *arch_info) { @@ -635,11 +635,11 @@ static int nds32_v2_examine(struct target *target) return ERROR_OK; } -static int nds32_v2_translate_address(struct target *target, uint32_t *address) +static int nds32_v2_translate_address(struct target *target, target_addr_t *address) { struct nds32 *nds32 = target_to_nds32(target); struct nds32_memory *memory = &(nds32->memory); - uint32_t physical_address; + target_addr_t physical_address; /* Following conditions need to do address translation * 1. BUS mode @@ -656,7 +656,7 @@ static int nds32_v2_translate_address(struct target *target, uint32_t *address) return ERROR_OK; } -static int nds32_v2_read_buffer(struct target *target, uint32_t address, +static int nds32_v2_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { struct nds32 *nds32 = target_to_nds32(target); @@ -676,7 +676,7 @@ static int nds32_v2_read_buffer(struct target *target, uint32_t address, return nds32_read_buffer(target, address, size, buffer); } -static int nds32_v2_write_buffer(struct target *target, uint32_t address, +static int nds32_v2_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer) { struct nds32 *nds32 = target_to_nds32(target); @@ -696,7 +696,7 @@ static int nds32_v2_write_buffer(struct target *target, uint32_t address, return nds32_write_buffer(target, address, size, buffer); } -static int nds32_v2_read_memory(struct target *target, uint32_t address, +static int nds32_v2_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct nds32 *nds32 = target_to_nds32(target); @@ -716,7 +716,7 @@ static int nds32_v2_read_memory(struct target *target, uint32_t address, return nds32_read_memory(target, address, size, count, buffer); } -static int nds32_v2_write_memory(struct target *target, uint32_t address, +static int nds32_v2_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct nds32 *nds32 = target_to_nds32(target); diff --git a/src/target/nds32_v3.c b/src/target/nds32_v3.c index 35b72e3d..e5d146bb 100644 --- a/src/target/nds32_v3.c +++ b/src/target/nds32_v3.c @@ -53,7 +53,7 @@ static int nds32_v3_activate_hardware_breakpoint(struct target *target) /* enable breakpoint (physical address) */ aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0xA); - LOG_DEBUG("Add hardware BP %" PRId32 " at %08" PRIx32, hbr_index, + LOG_DEBUG("Add hardware BP %" PRId32 " at %08" TARGET_PRIxADDR, hbr_index, bp->address); } else { return ERROR_FAIL; @@ -81,7 +81,7 @@ static int nds32_v3_deactivate_hardware_breakpoint(struct target *target) return ERROR_FAIL; } - LOG_DEBUG("Remove hardware BP %" PRId32 " at %08" PRIx32, hbr_index, + LOG_DEBUG("Remove hardware BP %" PRId32 " at %08" TARGET_PRIxADDR, hbr_index, bp->address); } @@ -128,7 +128,7 @@ static int nds32_v3_activate_hardware_watchpoint(struct target *target) /* set value */ aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + wp_num, 0); - LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" PRIx32 " mask %08" PRIx32, + LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR " mask %08" PRIx32, wp_num, wp->address, wp->mask); wp_num++; @@ -169,7 +169,7 @@ static int nds32_v3_deactivate_hardware_watchpoint(struct target *target) /* disable watchpoint */ aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0); - LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" PRIx32 + LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR " mask %08" PRIx32, wp_num, wp->address, wp->mask); wp_num++; diff --git a/src/target/nds32_v3_common.c b/src/target/nds32_v3_common.c index 191f4b5c..271ffdd1 100644 --- a/src/target/nds32_v3_common.c +++ b/src/target/nds32_v3_common.c @@ -368,7 +368,7 @@ int nds32_v3_target_request_data(struct target *target, } int nds32_v3_checksum_memory(struct target *target, - uint32_t address, uint32_t count, uint32_t *checksum) + target_addr_t address, uint32_t count, uint32_t *checksum) { LOG_WARNING("Not implemented: %s", __func__); @@ -434,8 +434,8 @@ int nds32_v3_run_algorithm(struct target *target, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - uint32_t entry_point, - uint32_t exit_point, + target_addr_t entry_point, + target_addr_t exit_point, int timeout_ms, void *arch_info) { @@ -444,7 +444,7 @@ int nds32_v3_run_algorithm(struct target *target, return ERROR_FAIL; } -int nds32_v3_read_buffer(struct target *target, uint32_t address, +int nds32_v3_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { struct nds32 *nds32 = target_to_nds32(target); @@ -456,7 +456,7 @@ int nds32_v3_read_buffer(struct target *target, uint32_t address, return ERROR_TARGET_NOT_HALTED; } - uint32_t physical_address; + target_addr_t physical_address; /* BUG: If access range crosses multiple pages, the translation will not correct * for second page or so. */ @@ -502,7 +502,7 @@ int nds32_v3_read_buffer(struct target *target, uint32_t address, return result; } -int nds32_v3_write_buffer(struct target *target, uint32_t address, +int nds32_v3_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer) { struct nds32 *nds32 = target_to_nds32(target); @@ -514,7 +514,7 @@ int nds32_v3_write_buffer(struct target *target, uint32_t address, return ERROR_TARGET_NOT_HALTED; } - uint32_t physical_address; + target_addr_t physical_address; /* BUG: If access range crosses multiple pages, the translation will not correct * for second page or so. */ @@ -564,7 +564,7 @@ int nds32_v3_write_buffer(struct target *target, uint32_t address, return nds32_write_buffer(target, address, size, buffer); } -int nds32_v3_read_memory(struct target *target, uint32_t address, +int nds32_v3_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct nds32 *nds32 = target_to_nds32(target); @@ -576,7 +576,7 @@ int nds32_v3_read_memory(struct target *target, uint32_t address, return ERROR_TARGET_NOT_HALTED; } - uint32_t physical_address; + target_addr_t physical_address; /* BUG: If access range crosses multiple pages, the translation will not correct * for second page or so. */ @@ -622,7 +622,7 @@ int nds32_v3_read_memory(struct target *target, uint32_t address, return result; } -int nds32_v3_write_memory(struct target *target, uint32_t address, +int nds32_v3_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct nds32 *nds32 = target_to_nds32(target); @@ -634,7 +634,7 @@ int nds32_v3_write_memory(struct target *target, uint32_t address, return ERROR_TARGET_NOT_HALTED; } - uint32_t physical_address; + target_addr_t physical_address; /* BUG: If access range crosses multiple pages, the translation will not correct * for second page or so. */ diff --git a/src/target/nds32_v3_common.h b/src/target/nds32_v3_common.h index 1f5df199..23393e55 100644 --- a/src/target/nds32_v3_common.h +++ b/src/target/nds32_v3_common.h @@ -34,7 +34,7 @@ void nds32_v3_common_register_callback(struct nds32_v3_common_callback *callback int nds32_v3_target_request_data(struct target *target, uint32_t size, uint8_t *buffer); int nds32_v3_checksum_memory(struct target *target, - uint32_t address, uint32_t count, uint32_t *checksum); + target_addr_t address, uint32_t count, uint32_t *checksum); int nds32_v3_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint); int nds32_v3_target_create_common(struct target *target, struct nds32 *nds32); @@ -43,17 +43,17 @@ int nds32_v3_run_algorithm(struct target *target, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - uint32_t entry_point, - uint32_t exit_point, + target_addr_t entry_point, + target_addr_t exit_point, int timeout_ms, void *arch_info); -int nds32_v3_read_buffer(struct target *target, uint32_t address, +int nds32_v3_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer); -int nds32_v3_write_buffer(struct target *target, uint32_t address, +int nds32_v3_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer); -int nds32_v3_read_memory(struct target *target, uint32_t address, +int nds32_v3_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); -int nds32_v3_write_memory(struct target *target, uint32_t address, +int nds32_v3_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int nds32_v3_init_target(struct command_context *cmd_ctx, struct target *target); diff --git a/src/target/nds32_v3m.c b/src/target/nds32_v3m.c index 2d52bc38..86903a51 100644 --- a/src/target/nds32_v3m.c +++ b/src/target/nds32_v3m.c @@ -50,7 +50,7 @@ static int nds32_v3m_activate_hardware_breakpoint(struct target *target) /* enable breakpoint (physical address) */ aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0xA); - LOG_DEBUG("Add hardware BP %u at %08" PRIx32, brp_num, + LOG_DEBUG("Add hardware BP %u at %08" TARGET_PRIxADDR, brp_num, bp->address); brp_num--; @@ -78,7 +78,7 @@ static int nds32_v3m_deactivate_hardware_breakpoint(struct target *target) else return ERROR_FAIL; - LOG_DEBUG("Remove hardware BP %u at %08" PRIx32, brp_num, + LOG_DEBUG("Remove hardware BP %u at %08" TARGET_PRIxADDR, brp_num, bp->address); brp_num--; @@ -125,7 +125,7 @@ static int nds32_v3m_activate_hardware_watchpoint(struct target *target) /* enable watchpoint */ aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config); - LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" PRIx32 + LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR " mask %08" PRIx32, wp_num, wp->address, wp->mask); wp_num++; @@ -166,7 +166,7 @@ static int nds32_v3m_deactivate_hardware_watchpoint(struct target *target) /* disable watchpoint */ aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0); - LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" PRIx32 + LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR " mask %08" PRIx32, wp_num, wp->address, wp->mask); wp_num++; } else if (nds32_v3m->nds32.global_stop) { diff --git a/src/target/openrisc/or1k.c b/src/target/openrisc/or1k.c index 2cc869f9..3895ddfa 100644 --- a/src/target/openrisc/or1k.c +++ b/src/target/openrisc/or1k.c @@ -861,7 +861,7 @@ static int or1k_resume_or_step(struct target *target, int current, /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { - LOG_DEBUG("Unset breakpoint at 0x%08" PRIx32, breakpoint->address); + LOG_DEBUG("Unset breakpoint at 0x%08" TARGET_PRIxADDR, breakpoint->address); retval = or1k_remove_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; @@ -897,7 +897,8 @@ static int or1k_resume_or_step(struct target *target, int current, } static int or1k_resume(struct target *target, int current, - uint32_t address, int handle_breakpoints, int debug_execution) + target_addr_t address, int handle_breakpoints, + int debug_execution) { return or1k_resume_or_step(target, current, address, handle_breakpoints, @@ -906,7 +907,7 @@ static int or1k_resume(struct target *target, int current, } static int or1k_step(struct target *target, int current, - uint32_t address, int handle_breakpoints) + target_addr_t address, int handle_breakpoints) { return or1k_resume_or_step(target, current, address, handle_breakpoints, @@ -922,7 +923,7 @@ static int or1k_add_breakpoint(struct target *target, struct or1k_du *du_core = or1k_to_du(or1k); uint8_t data; - LOG_DEBUG("Adding breakpoint: addr 0x%08" PRIx32 ", len %d, type %d, set: %d, id: %" PRId32, + LOG_DEBUG("Adding breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, set: %d, id: %" PRId32, breakpoint->address, breakpoint->length, breakpoint->type, breakpoint->set, breakpoint->unique_id); @@ -937,7 +938,7 @@ static int or1k_add_breakpoint(struct target *target, 1, &data); if (retval != ERROR_OK) { - LOG_ERROR("Error while reading the instruction at 0x%08" PRIx32, + LOG_ERROR("Error while reading the instruction at 0x%08" TARGET_PRIxADDR, breakpoint->address); return retval; } @@ -958,14 +959,15 @@ static int or1k_add_breakpoint(struct target *target, or1k_trap_insn); if (retval != ERROR_OK) { - LOG_ERROR("Error while writing OR1K_TRAP_INSTR at 0x%08" PRIx32, + LOG_ERROR("Error while writing OR1K_TRAP_INSTR at 0x%08" TARGET_PRIxADDR, breakpoint->address); return retval; } /* invalidate instruction cache */ + uint32_t addr = breakpoint->address; retval = du_core->or1k_jtag_write_cpu(&or1k->jtag, - OR1K_ICBIR_CPU_REG_ADD, 1, &breakpoint->address); + OR1K_ICBIR_CPU_REG_ADD, 1, &addr); if (retval != ERROR_OK) { LOG_ERROR("Error while invalidating the ICACHE"); return retval; @@ -980,7 +982,7 @@ static int or1k_remove_breakpoint(struct target *target, struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); - LOG_DEBUG("Removing breakpoint: addr 0x%08" PRIx32 ", len %d, type %d, set: %d, id: %" PRId32, + LOG_DEBUG("Removing breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, set: %d, id: %" PRId32, breakpoint->address, breakpoint->length, breakpoint->type, breakpoint->set, breakpoint->unique_id); @@ -996,14 +998,15 @@ static int or1k_remove_breakpoint(struct target *target, breakpoint->orig_instr); if (retval != ERROR_OK) { - LOG_ERROR("Error while writing back the instruction at 0x%08" PRIx32, + LOG_ERROR("Error while writing back the instruction at 0x%08" TARGET_PRIxADDR, breakpoint->address); return retval; } /* invalidate instruction cache */ + uint32_t addr = breakpoint->address; retval = du_core->or1k_jtag_write_cpu(&or1k->jtag, - OR1K_ICBIR_CPU_REG_ADD, 1, &breakpoint->address); + OR1K_ICBIR_CPU_REG_ADD, 1, &addr); if (retval != ERROR_OK) { LOG_ERROR("Error while invalidating the ICACHE"); return retval; @@ -1026,13 +1029,13 @@ static int or1k_remove_watchpoint(struct target *target, return ERROR_OK; } -static int or1k_read_memory(struct target *target, uint32_t address, +static int or1k_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); - LOG_DEBUG("Read memory at 0x%08" PRIx32 ", size: %" PRIu32 ", count: 0x%08" PRIx32, address, size, count); + LOG_DEBUG("Read memory at 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: 0x%08" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -1053,13 +1056,13 @@ static int or1k_read_memory(struct target *target, uint32_t address, return du_core->or1k_jtag_read_memory(&or1k->jtag, address, size, count, buffer); } -static int or1k_write_memory(struct target *target, uint32_t address, +static int or1k_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); - LOG_DEBUG("Write memory at 0x%08" PRIx32 ", size: %" PRIu32 ", count: 0x%08" PRIx32, address, size, count); + LOG_DEBUG("Write memory at 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: 0x%08" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("Target not halted"); @@ -1203,7 +1206,7 @@ int or1k_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *file return ERROR_FAIL; } -static int or1k_checksum_memory(struct target *target, uint32_t address, +static int or1k_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum) { return ERROR_FAIL; diff --git a/src/target/target.c b/src/target/target.c index c8a3ce4d..e04ecc47 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -58,9 +58,9 @@ /* default halt wait timeout (ms) */ #define DEFAULT_HALT_TIMEOUT 5000 -static int target_read_buffer_default(struct target *target, uint32_t address, +static int target_read_buffer_default(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer); -static int target_write_buffer_default(struct target *target, uint32_t address, +static int target_write_buffer_default(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer); static int target_array2mem(Jim_Interp *interp, struct target *target, int argc, Jim_Obj * const *argv); @@ -88,6 +88,7 @@ extern struct target_type dragonite_target; extern struct target_type xscale_target; extern struct target_type cortexm_target; extern struct target_type cortexa_target; +extern struct target_type aarch64_target; extern struct target_type cortexr4_target; extern struct target_type arm11_target; extern struct target_type ls1_sap_target; @@ -135,6 +136,9 @@ static struct target_type *target_types[] = { &or1k_target, &quark_x10xx_target, &quark_d20xx_target, +#if BUILD_TARGET64 + &aarch64_target, +#endif NULL, }; @@ -597,7 +601,8 @@ int target_halt(struct target *target) * hand the infrastructure for running such helpers might use this * procedure but rely on hardware breakpoint to detect termination.) */ -int target_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) +int target_resume(struct target *target, int current, target_addr_t address, + int handle_breakpoints, int debug_execution) { int retval; @@ -668,7 +673,7 @@ static int target_process_reset(struct command_context *cmd_ctx, enum target_res } static int identity_virt2phys(struct target *target, - uint32_t virtual, uint32_t *physical) + target_addr_t virtual, target_addr_t *physical) { *physical = virtual; return ERROR_OK; @@ -1034,7 +1039,7 @@ int target_run_flash_async_algorithm(struct target *target, } int target_read_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); @@ -1048,7 +1053,7 @@ int target_read_memory(struct target *target, } int target_read_phys_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); @@ -1062,7 +1067,7 @@ int target_read_phys_memory(struct target *target, } int target_write_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); @@ -1076,7 +1081,7 @@ int target_write_memory(struct target *target, } int target_write_phys_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); @@ -1164,7 +1169,7 @@ int target_get_gdb_reg_list(struct target *target, return target->type->get_gdb_reg_list(target, reg_list, reg_list_size, reg_class); } int target_step(struct target *target, - int current, uint32_t address, int handle_breakpoints) + int current, target_addr_t address, int handle_breakpoints) { return target->type->step(target, current, address, handle_breakpoints); } @@ -1635,7 +1640,7 @@ static void print_wa_layout(struct target *target) struct working_area *c = target->working_areas; while (c) { - LOG_DEBUG("%c%c 0x%08"PRIx32"-0x%08"PRIx32" (%"PRIu32" bytes)", + LOG_DEBUG("%c%c " TARGET_ADDR_FMT "-" TARGET_ADDR_FMT " (%" PRIu32 " bytes)", c->backup ? 'b' : ' ', c->free ? ' ' : '*', c->address, c->address + c->size - 1, c->size); c = c->next; @@ -1720,7 +1725,7 @@ int target_alloc_working_area_try(struct target *target, uint32_t size, struct w if (!enabled) { if (target->working_area_phys_spec) { LOG_DEBUG("MMU disabled, using physical " - "address for working memory 0x%08"PRIx32, + "address for working memory " TARGET_ADDR_FMT, target->working_area_phys); target->working_area = target->working_area_phys; } else { @@ -1731,7 +1736,7 @@ int target_alloc_working_area_try(struct target *target, uint32_t size, struct w } else { if (target->working_area_virt_spec) { LOG_DEBUG("MMU enabled, using virtual " - "address for working memory 0x%08"PRIx32, + "address for working memory " TARGET_ADDR_FMT, target->working_area_virt); target->working_area = target->working_area_virt; } else { @@ -1774,7 +1779,8 @@ int target_alloc_working_area_try(struct target *target, uint32_t size, struct w /* Split the working area into the requested size */ target_split_working_area(c, size); - LOG_DEBUG("allocated new working area of %"PRIu32" bytes at address 0x%08"PRIx32, size, c->address); + LOG_DEBUG("allocated new working area of %" PRIu32 " bytes at address " TARGET_ADDR_FMT, + size, c->address); if (target->backup_working_area) { if (c->backup == NULL) { @@ -1818,7 +1824,7 @@ static int target_restore_working_area(struct target *target, struct working_are if (target->backup_working_area && area->backup != NULL) { retval = target_write_memory(target, area->address, 4, area->size / 4, area->backup); if (retval != ERROR_OK) - LOG_ERROR("failed to restore %"PRIu32" bytes of working area at address 0x%08"PRIx32, + LOG_ERROR("failed to restore %" PRIu32 " bytes of working area at address " TARGET_ADDR_FMT, area->size, area->address); } @@ -1842,7 +1848,7 @@ static int target_free_working_area_restore(struct target *target, struct workin area->free = true; - LOG_DEBUG("freed %"PRIu32" bytes of working area at address 0x%08"PRIx32, + LOG_DEBUG("freed %" PRIu32 " bytes of working area at address " TARGET_ADDR_FMT, area->size, area->address); /* mark user pointer invalid */ @@ -1864,6 +1870,17 @@ int target_free_working_area(struct target *target, struct working_area *area) return target_free_working_area_restore(target, area, 1); } +static void target_destroy(struct target *target) +{ + if (target->type->deinit_target) + target->type->deinit_target(target); + + free(target->type); + free(target->trace_info); + free(target->cmd_name); + free(target); +} + void target_quit(void) { struct target_event_callback *pe = target_event_callbacks; @@ -1882,11 +1899,15 @@ void target_quit(void) } target_timer_callbacks = NULL; - for (struct target *target = all_targets; - target; target = target->next) { - if (target->type->deinit_target) - target->type->deinit_target(target); + for (struct target *target = all_targets; target;) { + struct target *tmp; + + tmp = target->next; + target_destroy(target); + target = tmp; } + + all_targets = NULL; } /* free resources and restore memory, if restoring memory fails, @@ -2024,9 +2045,9 @@ static int target_profiling_default(struct target *target, uint32_t *samples, * mode respectively, otherwise data is handled as quickly as * possible */ -int target_write_buffer(struct target *target, uint32_t address, uint32_t size, const uint8_t *buffer) +int target_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer) { - LOG_DEBUG("writing buffer of %" PRIi32 " byte at 0x%8.8" PRIx32, + LOG_DEBUG("writing buffer of %" PRIi32 " byte at " TARGET_ADDR_FMT, size, address); if (!target_was_examined(target)) { @@ -2039,7 +2060,7 @@ int target_write_buffer(struct target *target, uint32_t address, uint32_t size, if ((address + size - 1) < address) { /* GDB can request this when e.g. PC is 0xfffffffc */ - LOG_ERROR("address + size wrapped (0x%08" PRIx32 ", 0x%08" PRIx32 ")", + LOG_ERROR("address + size wrapped (" TARGET_ADDR_FMT ", 0x%08" PRIx32 ")", address, size); return ERROR_FAIL; @@ -2048,7 +2069,8 @@ int target_write_buffer(struct target *target, uint32_t address, uint32_t size, return target->type->write_buffer(target, address, size, buffer); } -static int target_write_buffer_default(struct target *target, uint32_t address, uint32_t count, const uint8_t *buffer) +static int target_write_buffer_default(struct target *target, + target_addr_t address, uint32_t count, const uint8_t *buffer) { uint32_t size; @@ -2085,9 +2107,9 @@ static int target_write_buffer_default(struct target *target, uint32_t address, * mode respectively, otherwise data is handled as quickly as * possible */ -int target_read_buffer(struct target *target, uint32_t address, uint32_t size, uint8_t *buffer) +int target_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { - LOG_DEBUG("reading buffer of %" PRIi32 " byte at 0x%8.8" PRIx32, + LOG_DEBUG("reading buffer of %" PRIi32 " byte at " TARGET_ADDR_FMT, size, address); if (!target_was_examined(target)) { @@ -2100,7 +2122,7 @@ int target_read_buffer(struct target *target, uint32_t address, uint32_t size, u if ((address + size - 1) < address) { /* GDB can request this when e.g. PC is 0xfffffffc */ - LOG_ERROR("address + size wrapped (0x%08" PRIx32 ", 0x%08" PRIx32 ")", + LOG_ERROR("address + size wrapped (" TARGET_ADDR_FMT ", 0x%08" PRIx32 ")", address, size); return ERROR_FAIL; @@ -2109,7 +2131,7 @@ int target_read_buffer(struct target *target, uint32_t address, uint32_t size, u return target->type->read_buffer(target, address, size, buffer); } -static int target_read_buffer_default(struct target *target, uint32_t address, uint32_t count, uint8_t *buffer) +static int target_read_buffer_default(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer) { uint32_t size; @@ -2142,7 +2164,7 @@ static int target_read_buffer_default(struct target *target, uint32_t address, u return ERROR_OK; } -int target_checksum_memory(struct target *target, uint32_t address, uint32_t size, uint32_t* crc) +int target_checksum_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t* crc) { uint8_t *buffer; int retval; @@ -2182,7 +2204,7 @@ int target_checksum_memory(struct target *target, uint32_t address, uint32_t siz return retval; } -int target_blank_check_memory(struct target *target, uint32_t address, uint32_t size, uint32_t* blank, +int target_blank_check_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t* blank, uint8_t erased_value) { int retval; @@ -2199,7 +2221,7 @@ int target_blank_check_memory(struct target *target, uint32_t address, uint32_t return retval; } -int target_read_u64(struct target *target, uint64_t address, uint64_t *value) +int target_read_u64(struct target *target, target_addr_t address, uint64_t *value) { uint8_t value_buf[8]; if (!target_was_examined(target)) { @@ -2211,19 +2233,19 @@ int target_read_u64(struct target *target, uint64_t address, uint64_t *value) if (retval == ERROR_OK) { *value = target_buffer_get_u64(target, value_buf); - LOG_DEBUG("address: 0x%" PRIx64 ", value: 0x%16.16" PRIx64 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64 "", address, *value); } else { *value = 0x0; - LOG_DEBUG("address: 0x%" PRIx64 " failed", + LOG_DEBUG("address: " TARGET_ADDR_FMT " failed", address); } return retval; } -int target_read_u32(struct target *target, uint32_t address, uint32_t *value) +int target_read_u32(struct target *target, target_addr_t address, uint32_t *value) { uint8_t value_buf[4]; if (!target_was_examined(target)) { @@ -2235,19 +2257,19 @@ int target_read_u32(struct target *target, uint32_t address, uint32_t *value) if (retval == ERROR_OK) { *value = target_buffer_get_u32(target, value_buf); - LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32 "", address, *value); } else { *value = 0x0; - LOG_DEBUG("address: 0x%8.8" PRIx32 " failed", + LOG_DEBUG("address: " TARGET_ADDR_FMT " failed", address); } return retval; } -int target_read_u16(struct target *target, uint32_t address, uint16_t *value) +int target_read_u16(struct target *target, target_addr_t address, uint16_t *value) { uint8_t value_buf[2]; if (!target_was_examined(target)) { @@ -2259,19 +2281,19 @@ int target_read_u16(struct target *target, uint32_t address, uint16_t *value) if (retval == ERROR_OK) { *value = target_buffer_get_u16(target, value_buf); - LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%4.4" PRIx16, + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%4.4" PRIx16, address, *value); } else { *value = 0x0; - LOG_DEBUG("address: 0x%8.8" PRIx32 " failed", + LOG_DEBUG("address: " TARGET_ADDR_FMT " failed", address); } return retval; } -int target_read_u8(struct target *target, uint32_t address, uint8_t *value) +int target_read_u8(struct target *target, target_addr_t address, uint8_t *value) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); @@ -2281,19 +2303,19 @@ int target_read_u8(struct target *target, uint32_t address, uint8_t *value) int retval = target_read_memory(target, address, 1, 1, value); if (retval == ERROR_OK) { - LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%2.2" PRIx8, + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%2.2" PRIx8, address, *value); } else { *value = 0x0; - LOG_DEBUG("address: 0x%8.8" PRIx32 " failed", + LOG_DEBUG("address: " TARGET_ADDR_FMT " failed", address); } return retval; } -int target_write_u64(struct target *target, uint64_t address, uint64_t value) +int target_write_u64(struct target *target, target_addr_t address, uint64_t value) { int retval; uint8_t value_buf[8]; @@ -2302,7 +2324,7 @@ int target_write_u64(struct target *target, uint64_t address, uint64_t value) return ERROR_FAIL; } - LOG_DEBUG("address: 0x%" PRIx64 ", value: 0x%16.16" PRIx64 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64 "", address, value); @@ -2314,7 +2336,7 @@ int target_write_u64(struct target *target, uint64_t address, uint64_t value) return retval; } -int target_write_u32(struct target *target, uint32_t address, uint32_t value) +int target_write_u32(struct target *target, target_addr_t address, uint32_t value) { int retval; uint8_t value_buf[4]; @@ -2323,7 +2345,7 @@ int target_write_u32(struct target *target, uint32_t address, uint32_t value) return ERROR_FAIL; } - LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32 "", address, value); @@ -2335,7 +2357,7 @@ int target_write_u32(struct target *target, uint32_t address, uint32_t value) return retval; } -int target_write_u16(struct target *target, uint32_t address, uint16_t value) +int target_write_u16(struct target *target, target_addr_t address, uint16_t value) { int retval; uint8_t value_buf[2]; @@ -2344,7 +2366,7 @@ int target_write_u16(struct target *target, uint32_t address, uint16_t value) return ERROR_FAIL; } - LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%8.8" PRIx16, + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx16, address, value); @@ -2356,7 +2378,7 @@ int target_write_u16(struct target *target, uint32_t address, uint16_t value) return retval; } -int target_write_u8(struct target *target, uint32_t address, uint8_t value) +int target_write_u8(struct target *target, target_addr_t address, uint8_t value) { int retval; if (!target_was_examined(target)) { @@ -2364,7 +2386,7 @@ int target_write_u8(struct target *target, uint32_t address, uint8_t value) return ERROR_FAIL; } - LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%2.2" PRIx8, + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%2.2" PRIx8, address, value); retval = target_write_memory(target, address, 1, 1, &value); @@ -2374,6 +2396,87 @@ int target_write_u8(struct target *target, uint32_t address, uint8_t value) return retval; } +int target_write_phys_u64(struct target *target, target_addr_t address, uint64_t value) +{ + int retval; + uint8_t value_buf[8]; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_FAIL; + } + + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64 "", + address, + value); + + target_buffer_set_u64(target, value_buf, value); + retval = target_write_phys_memory(target, address, 8, 1, value_buf); + if (retval != ERROR_OK) + LOG_DEBUG("failed: %i", retval); + + return retval; +} + +int target_write_phys_u32(struct target *target, target_addr_t address, uint32_t value) +{ + int retval; + uint8_t value_buf[4]; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_FAIL; + } + + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32 "", + address, + value); + + target_buffer_set_u32(target, value_buf, value); + retval = target_write_phys_memory(target, address, 4, 1, value_buf); + if (retval != ERROR_OK) + LOG_DEBUG("failed: %i", retval); + + return retval; +} + +int target_write_phys_u16(struct target *target, target_addr_t address, uint16_t value) +{ + int retval; + uint8_t value_buf[2]; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_FAIL; + } + + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx16, + address, + value); + + target_buffer_set_u16(target, value_buf, value); + retval = target_write_phys_memory(target, address, 2, 1, value_buf); + if (retval != ERROR_OK) + LOG_DEBUG("failed: %i", retval); + + return retval; +} + +int target_write_phys_u8(struct target *target, target_addr_t address, uint8_t value) +{ + int retval; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_FAIL; + } + + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%2.2" PRIx8, + address, value); + + retval = target_write_phys_memory(target, address, 1, 1, &value); + if (retval != ERROR_OK) + LOG_DEBUG("failed: %i", retval); + + return retval; +} + static int find_target(struct command_context *cmd_ctx, const char *name) { struct target *target = get_target(name); @@ -2877,9 +2980,9 @@ COMMAND_HANDLER(handle_resume_command) /* with no CMD_ARGV, resume from current pc, addr = 0, * with one arguments, addr = CMD_ARGV[0], * handle breakpoints, not debugging */ - uint32_t addr = 0; + target_addr_t addr = 0; if (CMD_ARGC == 1) { - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); current = 0; } @@ -2896,10 +2999,10 @@ COMMAND_HANDLER(handle_step_command) /* with no CMD_ARGV, step from current pc, addr = 0, * with one argument addr = CMD_ARGV[0], * handle breakpoints, debugging */ - uint32_t addr = 0; + target_addr_t addr = 0; int current_pc = 1; if (CMD_ARGC == 1) { - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); current_pc = 0; } @@ -2909,7 +3012,7 @@ COMMAND_HANDLER(handle_step_command) } static void handle_md_output(struct command_context *cmd_ctx, - struct target *target, uint32_t address, unsigned size, + struct target *target, target_addr_t address, unsigned size, unsigned count, const uint8_t *buffer) { const unsigned line_bytecnt = 32; @@ -2920,6 +3023,9 @@ static void handle_md_output(struct command_context *cmd_ctx, const char *value_fmt; switch (size) { + case 8: + value_fmt = "%16.16llx "; + break; case 4: value_fmt = "%8.8x "; break; @@ -2939,13 +3045,16 @@ static void handle_md_output(struct command_context *cmd_ctx, if (i % line_modulo == 0) { output_len += snprintf(output + output_len, sizeof(output) - output_len, - "0x%8.8x: ", - (unsigned)(address + (i*size))); + TARGET_ADDR_FMT ": ", + (address + (i * size))); } - uint32_t value = 0; + uint64_t value = 0; const uint8_t *value_ptr = buffer + i * size; switch (size) { + case 8: + value = target_buffer_get_u64(target, value_ptr); + break; case 4: value = target_buffer_get_u32(target, value_ptr); break; @@ -2973,6 +3082,9 @@ COMMAND_HANDLER(handle_md_command) unsigned size = 0; switch (CMD_NAME[2]) { + case 'd': + size = 8; + break; case 'w': size = 4; break; @@ -2988,7 +3100,7 @@ COMMAND_HANDLER(handle_md_command) bool physical = strcmp(CMD_ARGV[0], "phys") == 0; int (*fn)(struct target *target, - uint32_t address, uint32_t size_value, uint32_t count, uint8_t *buffer); + target_addr_t address, uint32_t size_value, uint32_t count, uint8_t *buffer); if (physical) { CMD_ARGC--; CMD_ARGV++; @@ -2998,8 +3110,8 @@ COMMAND_HANDLER(handle_md_command) if ((CMD_ARGC < 1) || (CMD_ARGC > 2)) return ERROR_COMMAND_SYNTAX_ERROR; - uint32_t address; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); + target_addr_t address; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); unsigned count = 1; if (CMD_ARGC == 2) @@ -3018,14 +3130,14 @@ COMMAND_HANDLER(handle_md_command) } typedef int (*target_write_fn)(struct target *target, - uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); static int target_fill_mem(struct target *target, - uint32_t address, + target_addr_t address, target_write_fn fn, unsigned data_size, /* value */ - uint32_t b, + uint64_t b, /* count */ unsigned c) { @@ -3040,6 +3152,9 @@ static int target_fill_mem(struct target *target, for (unsigned i = 0; i < chunk_size; i++) { switch (data_size) { + case 8: + target_buffer_set_u64(target, target_buf + i * data_size, b); + break; case 4: target_buffer_set_u32(target, target_buf + i * data_size, b); break; @@ -3088,11 +3203,11 @@ COMMAND_HANDLER(handle_mw_command) if ((CMD_ARGC < 2) || (CMD_ARGC > 3)) return ERROR_COMMAND_SYNTAX_ERROR; - uint32_t address; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); + target_addr_t address; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); - uint32_t value; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + target_addr_t value; + COMMAND_PARSE_ADDRESS(CMD_ARGV[1], value); unsigned count = 1; if (CMD_ARGC == 3) @@ -3101,6 +3216,9 @@ COMMAND_HANDLER(handle_mw_command) struct target *target = get_current_target(CMD_CTX); unsigned wordsize; switch (CMD_NAME[2]) { + case 'd': + wordsize = 8; + break; case 'w': wordsize = 4; break; @@ -3118,7 +3236,7 @@ COMMAND_HANDLER(handle_mw_command) } static COMMAND_HELPER(parse_load_image_command_CMD_ARGV, struct image *image, - uint32_t *min_address, uint32_t *max_address) + target_addr_t *min_address, target_addr_t *max_address) { if (CMD_ARGC < 1 || CMD_ARGC > 5) return ERROR_COMMAND_SYNTAX_ERROR; @@ -3126,8 +3244,8 @@ static COMMAND_HELPER(parse_load_image_command_CMD_ARGV, struct image *image, /* a base address isn't always necessary, * default to 0x0 (i.e. don't relocate) */ if (CMD_ARGC >= 2) { - uint32_t addr; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], addr); + target_addr_t addr; + COMMAND_PARSE_ADDRESS(CMD_ARGV[1], addr); image->base_address = addr; image->base_address_set = 1; } else @@ -3136,9 +3254,9 @@ static COMMAND_HELPER(parse_load_image_command_CMD_ARGV, struct image *image, image->start_address_set = 0; if (CMD_ARGC >= 4) - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], *min_address); + COMMAND_PARSE_ADDRESS(CMD_ARGV[3], *min_address); if (CMD_ARGC == 5) { - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], *max_address); + COMMAND_PARSE_ADDRESS(CMD_ARGV[4], *max_address); /* use size (given) to find max (required) */ *max_address += *min_address; } @@ -3154,8 +3272,8 @@ COMMAND_HANDLER(handle_load_image_command) uint8_t *buffer; size_t buf_cnt; uint32_t image_size; - uint32_t min_address = 0; - uint32_t max_address = 0xffffffff; + target_addr_t min_address = 0; + target_addr_t max_address = -1; int i; struct image image; @@ -3214,7 +3332,7 @@ COMMAND_HANDLER(handle_load_image_command) break; } image_size += length; - command_print(CMD_CTX, "%u bytes written at address 0x%8.8" PRIx32 "", + command_print(CMD_CTX, "%u bytes written at address " TARGET_ADDR_FMT "", (unsigned int)length, image.sections[i].base_address + offset); } @@ -3239,15 +3357,15 @@ COMMAND_HANDLER(handle_dump_image_command) struct fileio *fileio; uint8_t *buffer; int retval, retvaltemp; - uint32_t address, size; + target_addr_t address, size; struct duration bench; struct target *target = get_current_target(CMD_CTX); if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], address); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], size); + COMMAND_PARSE_ADDRESS(CMD_ARGV[1], address); + COMMAND_PARSE_ADDRESS(CMD_ARGV[2], size); uint32_t buf_size = (size > 4096) ? 4096 : size; buffer = malloc(buf_size); @@ -3328,8 +3446,8 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver duration_start(&bench); if (CMD_ARGC >= 2) { - uint32_t addr; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], addr); + target_addr_t addr; + COMMAND_PARSE_ADDRESS(CMD_ARGV[1], addr); image.base_address = addr; image.base_address_set = 1; } else { @@ -3419,7 +3537,7 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver free(data); } } else { - command_print(CMD_CTX, "address 0x%08" PRIx32 " length 0x%08zx", + command_print(CMD_CTX, "address " TARGET_ADDR_FMT " length 0x%08zx", image.sections[i].base_address, buf_cnt); } @@ -3466,7 +3584,7 @@ static int handle_bp_command_list(struct command_context *cmd_ctx) if (breakpoint->type == BKPT_SOFT) { char *buf = buf_to_str(breakpoint->orig_instr, breakpoint->length, 16); - command_print(cmd_ctx, "IVA breakpoint: 0x%8.8" PRIx32 ", 0x%x, %i, 0x%s", + command_print(cmd_ctx, "IVA breakpoint: " TARGET_ADDR_FMT ", 0x%x, %i, 0x%s", breakpoint->address, breakpoint->length, breakpoint->set, buf); @@ -3477,13 +3595,13 @@ static int handle_bp_command_list(struct command_context *cmd_ctx) breakpoint->asid, breakpoint->length, breakpoint->set); else if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { - command_print(cmd_ctx, "Hybrid breakpoint(IVA): 0x%8.8" PRIx32 ", 0x%x, %i", + command_print(cmd_ctx, "Hybrid breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %i", breakpoint->address, breakpoint->length, breakpoint->set); command_print(cmd_ctx, "\t|--->linked with ContextID: 0x%8.8" PRIx32, breakpoint->asid); } else - command_print(cmd_ctx, "Breakpoint(IVA): 0x%8.8" PRIx32 ", 0x%x, %i", + command_print(cmd_ctx, "Breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %i", breakpoint->address, breakpoint->length, breakpoint->set); } @@ -3494,7 +3612,7 @@ static int handle_bp_command_list(struct command_context *cmd_ctx) } static int handle_bp_command_set(struct command_context *cmd_ctx, - uint32_t addr, uint32_t asid, uint32_t length, int hw) + target_addr_t addr, uint32_t asid, uint32_t length, int hw) { struct target *target = get_current_target(cmd_ctx); int retval; @@ -3502,7 +3620,7 @@ static int handle_bp_command_set(struct command_context *cmd_ctx, if (asid == 0) { retval = breakpoint_add(target, addr, length, hw); if (ERROR_OK == retval) - command_print(cmd_ctx, "breakpoint set at 0x%8.8" PRIx32 "", addr); + command_print(cmd_ctx, "breakpoint set at " TARGET_ADDR_FMT "", addr); else { LOG_ERROR("Failure setting breakpoint, the same address(IVA) is already used"); return retval; @@ -3537,7 +3655,7 @@ static int handle_bp_command_set(struct command_context *cmd_ctx, COMMAND_HANDLER(handle_bp_command) { - uint32_t addr; + target_addr_t addr; uint32_t asid; uint32_t length; int hw = BKPT_SOFT; @@ -3548,17 +3666,15 @@ COMMAND_HANDLER(handle_bp_command) case 2: asid = 0; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); return handle_bp_command_set(CMD_CTX, addr, asid, length, hw); case 3: if (strcmp(CMD_ARGV[2], "hw") == 0) { hw = BKPT_HARD; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); - + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); - asid = 0; return handle_bp_command_set(CMD_CTX, addr, asid, length, hw); } else if (strcmp(CMD_ARGV[2], "hw_ctx") == 0) { @@ -3571,7 +3687,7 @@ COMMAND_HANDLER(handle_bp_command) case 4: hw = BKPT_HARD; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], asid); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], length); return handle_bp_command_set(CMD_CTX, addr, asid, length, hw); @@ -3586,8 +3702,8 @@ COMMAND_HANDLER(handle_rbp_command) if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - uint32_t addr; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); + target_addr_t addr; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); struct target *target = get_current_target(CMD_CTX); breakpoint_remove(target, addr); @@ -3603,7 +3719,7 @@ COMMAND_HANDLER(handle_wp_command) struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { - command_print(CMD_CTX, "address: 0x%8.8" PRIx32 + command_print(CMD_CTX, "address: " TARGET_ADDR_FMT ", len: 0x%8.8" PRIx32 ", r/w/a: %i, value: 0x%8.8" PRIx32 ", mask: 0x%8.8" PRIx32, @@ -3688,14 +3804,14 @@ COMMAND_HANDLER(handle_virt2phys_command) if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - uint32_t va; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], va); - uint32_t pa; + target_addr_t va; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], va); + target_addr_t pa; struct target *target = get_current_target(CMD_CTX); int retval = target->type->virt2phys(target, va, &pa); if (retval == ERROR_OK) - command_print(CMD_CTX, "Physical address 0x%08" PRIx32 "", pa); + command_print(CMD_CTX, "Physical address " TARGET_ADDR_FMT "", pa); return retval; } @@ -4344,6 +4460,7 @@ enum target_cfg_param { TCFG_COREID, TCFG_CHAIN_POSITION, TCFG_DBGBASE, + TCFG_CTIBASE, TCFG_RTOS, TCFG_DEFER_EXAMINE, }; @@ -4359,6 +4476,7 @@ 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 } @@ -4625,7 +4743,20 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) 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 */ { @@ -4771,7 +4902,7 @@ static int jim_target_md(Jim_Interp *interp, int argc, Jim_Obj *const *argv) } int (*fn)(struct target *target, - uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); fn = target_read_memory; int e; @@ -5643,7 +5774,7 @@ static const struct command_registration target_subcommand_handlers[] = { }; struct FastLoad { - uint32_t address; + target_addr_t address; uint8_t *data; int length; @@ -5670,8 +5801,8 @@ COMMAND_HANDLER(handle_fast_load_image_command) uint8_t *buffer; size_t buf_cnt; uint32_t image_size; - uint32_t min_address = 0; - uint32_t max_address = 0xffffffff; + target_addr_t min_address = 0; + target_addr_t max_address = -1; int i; struct image image; @@ -6141,6 +6272,13 @@ static const struct command_registration target_exec_command_handlers[] = { .help = "step one instruction from current PC or address", .usage = "[address]", }, + { + .name = "mdd", + .handler = handle_md_command, + .mode = COMMAND_EXEC, + .help = "display memory words", + .usage = "['phys'] address [count]", + }, { .name = "mdw", .handler = handle_md_command, @@ -6162,6 +6300,13 @@ static const struct command_registration target_exec_command_handlers[] = { .help = "display memory bytes", .usage = "['phys'] address [count]", }, + { + .name = "mwd", + .handler = handle_mw_command, + .mode = COMMAND_EXEC, + .help = "write memory word", + .usage = "['phys'] address value [count]", + }, { .name = "mww", .handler = handle_mw_command, diff --git a/src/target/target.h b/src/target/target.h index e86b700a..53f9e261 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -93,7 +93,7 @@ enum target_endianness { }; struct working_area { - uint32_t address; + target_addr_t address; uint32_t size; bool free; uint8_t *backup; @@ -125,7 +125,7 @@ enum target_register_class { /* target_type.h contains the full definition of struct target_type */ struct target { struct target_type *type; /* target type definition (name, access functions) */ - const char *cmd_name; /* tcl Name of target */ + char *cmd_name; /* tcl Name of target */ int target_number; /* DO NOT USE! field to be removed in 2010 */ struct jtag_tap *tap; /* where on the jtag chain is this */ int32_t coreid; /* which device on the TAP? */ @@ -156,9 +156,9 @@ struct target { uint32_t working_area; /* working area (initialised RAM). Evaluated * upon first allocation from virtual/physical address. */ bool working_area_virt_spec; /* virtual address specified? */ - uint32_t working_area_virt; /* virtual address */ + target_addr_t working_area_virt; /* virtual address */ bool working_area_phys_spec; /* physical address specified? */ - uint32_t working_area_phys; /* physical address */ + target_addr_t working_area_phys; /* physical address */ uint32_t working_area_size; /* size in bytes */ uint32_t backup_working_area; /* whether the content of the working area has to be preserved */ struct working_area *working_areas;/* list of allocated working areas */ @@ -185,6 +185,11 @@ struct target { uint32_t dbgbase; /* Really a Cortex-A specific option, but there is no * system in place to support target specific options * currently. */ + + 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 */ @@ -353,7 +358,7 @@ int target_unregister_trace_callback( * yet it is possible to detect error conditions. */ int target_poll(struct target *target); -int target_resume(struct target *target, int current, uint32_t address, +int target_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution); int target_halt(struct target *target); int target_call_event_callbacks(struct target *target, enum target_event event); @@ -474,7 +479,7 @@ int target_get_gdb_reg_list(struct target *target, * This routine is a wrapper for target->type->step. */ int target_step(struct target *target, - int current, uint32_t address, int handle_breakpoints); + int current, target_addr_t address, int handle_breakpoints); /** * Run an algorithm on the @a target given. * @@ -527,9 +532,9 @@ int target_run_flash_async_algorithm(struct target *target, * This routine is a wrapper for target->type->read_memory. */ int target_read_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); int target_read_phys_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); /** * Write @a count items of @a size bytes to the memory of @a target at * the @a address given. @a address must be aligned to @a size @@ -548,9 +553,9 @@ int target_read_phys_memory(struct target *target, * This routine is wrapper for target->type->write_memory. */ int target_write_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int target_write_phys_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); /* * Write to target memory using the virtual address. @@ -577,13 +582,13 @@ int target_write_phys_memory(struct target *target, * peripheral registers which do not support byte operations. */ int target_write_buffer(struct target *target, - uint32_t address, uint32_t size, const uint8_t *buffer); + target_addr_t address, uint32_t size, const uint8_t *buffer); int target_read_buffer(struct target *target, - uint32_t address, uint32_t size, uint8_t *buffer); + target_addr_t address, uint32_t size, uint8_t *buffer); int target_checksum_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t *crc); + target_addr_t address, uint32_t size, uint32_t *crc); int target_blank_check_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t *blank, uint8_t erased_value); + target_addr_t address, uint32_t size, uint32_t *blank, uint8_t erased_value); int target_wait_state(struct target *target, enum target_state state, int ms); /** @@ -659,14 +664,19 @@ void target_buffer_set_u64_array(struct target *target, uint8_t *buffer, uint32_ void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_t count, const uint32_t *srcbuf); void target_buffer_set_u16_array(struct target *target, uint8_t *buffer, uint32_t count, const uint16_t *srcbuf); -int target_read_u64(struct target *target, uint64_t address, uint64_t *value); -int target_read_u32(struct target *target, uint32_t address, uint32_t *value); -int target_read_u16(struct target *target, uint32_t address, uint16_t *value); -int target_read_u8(struct target *target, uint32_t address, uint8_t *value); -int target_write_u64(struct target *target, uint64_t address, uint64_t value); -int target_write_u32(struct target *target, uint32_t address, uint32_t value); -int target_write_u16(struct target *target, uint32_t address, uint16_t value); -int target_write_u8(struct target *target, uint32_t address, uint8_t value); +int target_read_u64(struct target *target, target_addr_t address, uint64_t *value); +int target_read_u32(struct target *target, target_addr_t address, uint32_t *value); +int target_read_u16(struct target *target, target_addr_t address, uint16_t *value); +int target_read_u8(struct target *target, target_addr_t address, uint8_t *value); +int target_write_u64(struct target *target, target_addr_t address, uint64_t value); +int target_write_u32(struct target *target, target_addr_t address, uint32_t value); +int target_write_u16(struct target *target, target_addr_t address, uint16_t value); +int target_write_u8(struct target *target, target_addr_t address, uint8_t value); + +int target_write_phys_u64(struct target *target, target_addr_t address, uint64_t value); +int target_write_phys_u32(struct target *target, target_addr_t address, uint32_t value); +int target_write_phys_u16(struct target *target, target_addr_t address, uint16_t value); +int target_write_phys_u8(struct target *target, target_addr_t address, uint8_t value); /* Issues USER() statements with target state information */ int target_arch_state(struct target *target); diff --git a/src/target/target_type.h b/src/target/target_type.h index 2473c62c..34e2778a 100644 --- a/src/target/target_type.h +++ b/src/target/target_type.h @@ -53,11 +53,10 @@ struct target_type { /* halt will log a warning, but return ERROR_OK if the target is already halted. */ int (*halt)(struct target *target); - int (*resume)(struct target *target, int current, uint32_t address, + int (*resume)(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution); - int (*step)(struct target *target, int current, uint32_t address, + int (*step)(struct target *target, int current, target_addr_t address, int handle_breakpoints); - /* target reset control. assert reset can be invoked when OpenOCD and * the target is out of sync. * @@ -111,26 +110,26 @@ struct target_type { * Target memory read callback. Do @b not call this function * directly, use target_read_memory() instead. */ - int (*read_memory)(struct target *target, uint32_t address, + int (*read_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); /** * Target memory write callback. Do @b not call this function * directly, use target_write_memory() instead. */ - int (*write_memory)(struct target *target, uint32_t address, + int (*write_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); /* Default implementation will do some fancy alignment to improve performance, target can override */ - int (*read_buffer)(struct target *target, uint32_t address, + int (*read_buffer)(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer); /* Default implementation will do some fancy alignment to improve performance, target can override */ - int (*write_buffer)(struct target *target, uint32_t address, + int (*write_buffer)(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer); - int (*checksum_memory)(struct target *target, uint32_t address, + int (*checksum_memory)(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); - int (*blank_check_memory)(struct target *target, uint32_t address, + int (*blank_check_memory)(struct target *target, target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value); /* @@ -175,15 +174,15 @@ struct target_type { */ int (*run_algorithm)(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, - struct reg_param *reg_param, uint32_t entry_point, - uint32_t exit_point, int timeout_ms, void *arch_info); + struct reg_param *reg_param, target_addr_t entry_point, + target_addr_t exit_point, int timeout_ms, void *arch_info); int (*start_algorithm)(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, - struct reg_param *reg_param, uint32_t entry_point, - uint32_t exit_point, void *arch_info); + struct reg_param *reg_param, target_addr_t entry_point, + target_addr_t exit_point, void *arch_info); int (*wait_algorithm)(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, - struct reg_param *reg_param, uint32_t exit_point, + struct reg_param *reg_param, target_addr_t exit_point, int timeout_ms, void *arch_info); const struct command_registration *commands; @@ -233,7 +232,7 @@ struct target_type { /* translate from virtual to physical address. Default implementation is successful * no-op(i.e. virtual==physical). */ - int (*virt2phys)(struct target *target, uint32_t address, uint32_t *physical); + int (*virt2phys)(struct target *target, target_addr_t address, target_addr_t *physical); /* read directly from physical memory. caches are bypassed and untouched. * @@ -243,13 +242,13 @@ struct target_type { * * Default implementation is to call read_memory. */ - int (*read_phys_memory)(struct target *target, uint32_t phys_address, + int (*read_phys_memory)(struct target *target, target_addr_t phys_address, uint32_t size, uint32_t count, uint8_t *buffer); /* * same as read_phys_memory, except that it writes... */ - int (*write_phys_memory)(struct target *target, uint32_t phys_address, + int (*write_phys_memory)(struct target *target, target_addr_t phys_address, uint32_t size, uint32_t count, const uint8_t *buffer); int (*mmu)(struct target *target, int *enabled); diff --git a/src/target/x86_32_common.c b/src/target/x86_32_common.c index c21167e1..34f92eac 100644 --- a/src/target/x86_32_common.c +++ b/src/target/x86_32_common.c @@ -48,8 +48,8 @@ static int read_mem(struct target *t, uint32_t size, uint32_t addr, uint8_t *buf); static int write_mem(struct target *t, uint32_t size, uint32_t addr, const uint8_t *buf); -static int calcaddr_physfromlin(struct target *t, uint32_t addr, - uint32_t *physaddr); +static int calcaddr_physfromlin(struct target *t, target_addr_t addr, + target_addr_t *physaddr); static int read_phys_mem(struct target *t, uint32_t phys_address, uint32_t size, uint32_t count, uint8_t *buffer); static int write_phys_mem(struct target *t, uint32_t phys_address, @@ -113,7 +113,7 @@ int x86_32_common_mmu(struct target *t, int *enabled) return ERROR_OK; } -int x86_32_common_virt2phys(struct target *t, uint32_t address, uint32_t *physical) +int x86_32_common_virt2phys(struct target *t, target_addr_t address, target_addr_t *physical) { struct x86_32_common *x86_32 = target_to_x86_32(t); @@ -135,7 +135,7 @@ int x86_32_common_virt2phys(struct target *t, uint32_t address, uint32_t *physic } else { /* target halted in protected mode */ if (calcaddr_physfromlin(t, address, physical) != ERROR_OK) { - LOG_ERROR("%s failed to calculate physical address from 0x%08" PRIx32, + LOG_ERROR("%s failed to calculate physical address from " TARGET_ADDR_FMT, __func__, address); return ERROR_FAIL; } @@ -143,7 +143,7 @@ int x86_32_common_virt2phys(struct target *t, uint32_t address, uint32_t *physic return ERROR_OK; } -int x86_32_common_read_phys_mem(struct target *t, uint32_t phys_address, +int x86_32_common_read_phys_mem(struct target *t, target_addr_t phys_address, uint32_t size, uint32_t count, uint8_t *buffer) { struct x86_32_common *x86_32 = target_to_x86_32(t); @@ -226,7 +226,7 @@ static int read_phys_mem(struct target *t, uint32_t phys_address, return retval; } -int x86_32_common_write_phys_mem(struct target *t, uint32_t phys_address, +int x86_32_common_write_phys_mem(struct target *t, target_addr_t phys_address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct x86_32_common *x86_32 = target_to_x86_32(t); @@ -235,7 +235,7 @@ int x86_32_common_write_phys_mem(struct target *t, uint32_t phys_address, check_not_halted(t); if (!count || !buffer || !phys_address) { - LOG_ERROR("%s invalid params count=0x%" PRIx32 ", buf=%p, addr=0x%08" PRIx32, + LOG_ERROR("%s invalid params count=0x%" PRIx32 ", buf=%p, addr=" TARGET_ADDR_FMT, __func__, count, buffer, phys_address); return ERROR_COMMAND_ARGUMENT_INVALID; } @@ -444,7 +444,7 @@ static int write_mem(struct target *t, uint32_t size, return retval; } -int calcaddr_physfromlin(struct target *t, uint32_t addr, uint32_t *physaddr) +int calcaddr_physfromlin(struct target *t, target_addr_t addr, target_addr_t *physaddr) { uint8_t entry_buffer[8]; @@ -568,16 +568,16 @@ int calcaddr_physfromlin(struct target *t, uint32_t addr, uint32_t *physaddr) return ERROR_OK; } -int x86_32_common_read_memory(struct target *t, uint32_t addr, +int x86_32_common_read_memory(struct target *t, target_addr_t addr, uint32_t size, uint32_t count, uint8_t *buf) { int retval = ERROR_OK; struct x86_32_common *x86_32 = target_to_x86_32(t); - LOG_DEBUG("addr=0x%08" PRIx32 ", size=%" PRIu32 ", count=0x%" PRIx32 ", buf=%p", + LOG_DEBUG("addr=" TARGET_ADDR_FMT ", size=%" PRIu32 ", count=0x%" PRIx32 ", buf=%p", addr, size, count, buf); check_not_halted(t); if (!count || !buf || !addr) { - LOG_ERROR("%s invalid params count=0x%" PRIx32 ", buf=%p, addr=0x%08" PRIx32, + LOG_ERROR("%s invalid params count=0x%" PRIx32 ", buf=%p, addr=" TARGET_ADDR_FMT, __func__, count, buf, addr); return ERROR_COMMAND_ARGUMENT_INVALID; } @@ -591,9 +591,10 @@ int x86_32_common_read_memory(struct target *t, uint32_t addr, LOG_ERROR("%s could not disable paging", __func__); return retval; } - uint32_t physaddr = 0; + target_addr_t physaddr = 0; if (calcaddr_physfromlin(t, addr, &physaddr) != ERROR_OK) { - LOG_ERROR("%s failed to calculate physical address from 0x%08" PRIx32, __func__, addr); + LOG_ERROR("%s failed to calculate physical address from " TARGET_ADDR_FMT, + __func__, addr); retval = ERROR_FAIL; } /* TODO: !!! Watch out for page boundaries @@ -603,7 +604,8 @@ int x86_32_common_read_memory(struct target *t, uint32_t addr, if (retval == ERROR_OK && x86_32_common_read_phys_mem(t, physaddr, size, count, buf) != ERROR_OK) { - LOG_ERROR("%s failed to read memory from physical address 0x%08" PRIx32, __func__, physaddr); + LOG_ERROR("%s failed to read memory from physical address " TARGET_ADDR_FMT, + __func__, physaddr); retval = ERROR_FAIL; } /* restore PG bit if it was cleared prior (regardless of retval) */ @@ -615,7 +617,8 @@ int x86_32_common_read_memory(struct target *t, uint32_t addr, } else { /* paging is off - linear address is physical address */ if (x86_32_common_read_phys_mem(t, addr, size, count, buf) != ERROR_OK) { - LOG_ERROR("%s failed to read memory from address 0%08" PRIx32, __func__, addr); + LOG_ERROR("%s failed to read memory from address " TARGET_ADDR_FMT, + __func__, addr); retval = ERROR_FAIL; } } @@ -623,16 +626,16 @@ int x86_32_common_read_memory(struct target *t, uint32_t addr, return retval; } -int x86_32_common_write_memory(struct target *t, uint32_t addr, +int x86_32_common_write_memory(struct target *t, target_addr_t addr, uint32_t size, uint32_t count, const uint8_t *buf) { int retval = ERROR_OK; struct x86_32_common *x86_32 = target_to_x86_32(t); - LOG_DEBUG("addr=0x%08" PRIx32 ", size=%" PRIu32 ", count=0x%" PRIx32 ", buf=%p", + LOG_DEBUG("addr=" TARGET_ADDR_FMT ", size=%" PRIu32 ", count=0x%" PRIx32 ", buf=%p", addr, size, count, buf); check_not_halted(t); if (!count || !buf || !addr) { - LOG_ERROR("%s invalid params count=0x%" PRIx32 ", buf=%p, addr=0x%08" PRIx32, + LOG_ERROR("%s invalid params count=0x%" PRIx32 ", buf=%p, addr=" TARGET_ADDR_FMT, __func__, count, buf, addr); return ERROR_COMMAND_ARGUMENT_INVALID; } @@ -645,9 +648,9 @@ int x86_32_common_write_memory(struct target *t, uint32_t addr, LOG_ERROR("%s could not disable paging", __func__); return retval; } - uint32_t physaddr = 0; + target_addr_t physaddr = 0; if (calcaddr_physfromlin(t, addr, &physaddr) != ERROR_OK) { - LOG_ERROR("%s failed to calculate physical address from 0x%08" PRIx32, + LOG_ERROR("%s failed to calculate physical address from " TARGET_ADDR_FMT, __func__, addr); retval = ERROR_FAIL; } @@ -657,7 +660,7 @@ int x86_32_common_write_memory(struct target *t, uint32_t addr, */ if (retval == ERROR_OK && x86_32_common_write_phys_mem(t, physaddr, size, count, buf) != ERROR_OK) { - LOG_ERROR("%s failed to write memory to physical address 0x%08" PRIx32, + LOG_ERROR("%s failed to write memory to physical address " TARGET_ADDR_FMT, __func__, physaddr); retval = ERROR_FAIL; } @@ -671,7 +674,7 @@ int x86_32_common_write_memory(struct target *t, uint32_t addr, /* paging is off - linear address is physical address */ if (x86_32_common_write_phys_mem(t, addr, size, count, buf) != ERROR_OK) { - LOG_ERROR("%s failed to write memory to address 0x%08" PRIx32, + LOG_ERROR("%s failed to write memory to address " TARGET_ADDR_FMT, __func__, addr); retval = ERROR_FAIL; } @@ -852,7 +855,7 @@ int x86_32_common_remove_watchpoint(struct target *t, struct watchpoint *wp) int x86_32_common_add_breakpoint(struct target *t, struct breakpoint *bp) { - LOG_DEBUG("type=%d, addr=0x%08" PRIx32, bp->type, bp->address); + LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, bp->type, bp->address); if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; /* set_breakpoint() will return ERROR_TARGET_RESOURCE_NOT_AVAILABLE if all @@ -863,7 +866,7 @@ int x86_32_common_add_breakpoint(struct target *t, struct breakpoint *bp) int x86_32_common_remove_breakpoint(struct target *t, struct breakpoint *bp) { - LOG_DEBUG("type=%d, addr=0x%08" PRIx32, bp->type, bp->address); + LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, bp->type, bp->address); if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; if (bp->set) @@ -1003,7 +1006,7 @@ static int unset_hwbp(struct target *t, struct breakpoint *bp) debug_reg_list[hwbp_num].used = 0; debug_reg_list[hwbp_num].bp_value = 0; - LOG_USER("%s hardware breakpoint %" PRIu32 " removed from 0x%08" PRIx32 " (hwreg=%d)", + LOG_USER("%s hardware breakpoint %" PRIu32 " removed from " TARGET_ADDR_FMT " (hwreg=%d)", __func__, bp->unique_id, bp->address, hwbp_num); return ERROR_OK; } @@ -1012,7 +1015,7 @@ static int set_swbp(struct target *t, struct breakpoint *bp) { struct x86_32_common *x86_32 = target_to_x86_32(t); LOG_DEBUG("id %" PRIx32, bp->unique_id); - uint32_t physaddr; + target_addr_t physaddr; uint8_t opcode = SW_BP_OPCODE; uint8_t readback; @@ -1032,7 +1035,7 @@ static int set_swbp(struct target *t, struct breakpoint *bp) return ERROR_FAIL; if (readback != SW_BP_OPCODE) { - LOG_ERROR("%s software breakpoint error at 0x%08" PRIx32 ", check memory", + LOG_ERROR("%s software breakpoint error at " TARGET_ADDR_FMT ", check memory", __func__, bp->address); LOG_ERROR("%s readback=0x%02" PRIx8 " orig=0x%02" PRIx8 "", __func__, readback, *bp->orig_instr); @@ -1059,7 +1062,7 @@ static int set_swbp(struct target *t, struct breakpoint *bp) addto = addto->next; addto->next = new_patch; } - LOG_USER("%s software breakpoint %" PRIu32 " set at 0x%08" PRIx32, + LOG_USER("%s software breakpoint %" PRIu32 " set at " TARGET_ADDR_FMT, __func__, bp->unique_id, bp->address); return ERROR_OK; } @@ -1068,7 +1071,7 @@ static int unset_swbp(struct target *t, struct breakpoint *bp) { struct x86_32_common *x86_32 = target_to_x86_32(t); LOG_DEBUG("id %" PRIx32, bp->unique_id); - uint32_t physaddr; + target_addr_t physaddr; uint8_t current_instr; /* check that user program has not modified breakpoint instruction */ @@ -1081,7 +1084,7 @@ static int unset_swbp(struct target *t, struct breakpoint *bp) if (write_phys_mem(t, physaddr, 1, 1, bp->orig_instr)) return ERROR_FAIL; } else { - LOG_ERROR("%s software breakpoint remove error at 0x%08" PRIx32 ", check memory", + LOG_ERROR("%s software breakpoint remove error at " TARGET_ADDR_FMT ", check memory", __func__, bp->address); LOG_ERROR("%s current=0x%02" PRIx8 " orig=0x%02" PRIx8 "", __func__, current_instr, *bp->orig_instr); @@ -1107,7 +1110,7 @@ static int unset_swbp(struct target *t, struct breakpoint *bp) } } - LOG_USER("%s software breakpoint %" PRIu32 " removed from 0x%08" PRIx32, + LOG_USER("%s software breakpoint %" PRIu32 " removed from " TARGET_ADDR_FMT, __func__, bp->unique_id, bp->address); return ERROR_OK; } @@ -1116,7 +1119,7 @@ static int set_breakpoint(struct target *t, struct breakpoint *bp) { int error = ERROR_OK; struct x86_32_common *x86_32 = target_to_x86_32(t); - LOG_DEBUG("type=%d, addr=0x%08" PRIx32, bp->type, bp->address); + LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, bp->type, bp->address); if (bp->set) { LOG_ERROR("breakpoint already set"); return error; @@ -1124,7 +1127,7 @@ static int set_breakpoint(struct target *t, struct breakpoint *bp) if (bp->type == BKPT_HARD) { error = set_hwbp(t, bp); if (error != ERROR_OK) { - LOG_ERROR("%s error setting hardware breakpoint at 0x%08" PRIx32, + LOG_ERROR("%s error setting hardware breakpoint at " TARGET_ADDR_FMT, __func__, bp->address); return error; } @@ -1132,7 +1135,7 @@ static int set_breakpoint(struct target *t, struct breakpoint *bp) if (x86_32->sw_bpts_supported(t)) { error = set_swbp(t, bp); if (error != ERROR_OK) { - LOG_ERROR("%s error setting software breakpoint at 0x%08" PRIx32, + LOG_ERROR("%s error setting software breakpoint at " TARGET_ADDR_FMT, __func__, bp->address); return error; } @@ -1147,7 +1150,7 @@ static int set_breakpoint(struct target *t, struct breakpoint *bp) static int unset_breakpoint(struct target *t, struct breakpoint *bp) { - LOG_DEBUG("type=%d, addr=0x%08" PRIx32, bp->type, bp->address); + LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, bp->type, bp->address); if (!bp->set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; @@ -1155,13 +1158,13 @@ static int unset_breakpoint(struct target *t, struct breakpoint *bp) if (bp->type == BKPT_HARD) { if (unset_hwbp(t, bp) != ERROR_OK) { - LOG_ERROR("%s error removing hardware breakpoint at 0x%08" PRIx32, + LOG_ERROR("%s error removing hardware breakpoint at " TARGET_ADDR_FMT, __func__, bp->address); return ERROR_FAIL; } } else { if (unset_swbp(t, bp) != ERROR_OK) { - LOG_ERROR("%s error removing software breakpoint at 0x%08" PRIx32, + LOG_ERROR("%s error removing software breakpoint at " TARGET_ADDR_FMT, __func__, bp->address); return ERROR_FAIL; } @@ -1175,7 +1178,7 @@ static int set_watchpoint(struct target *t, struct watchpoint *wp) struct x86_32_common *x86_32 = target_to_x86_32(t); struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list; int wp_num = 0; - LOG_DEBUG("type=%d, addr=0x%08" PRIx32, wp->rw, wp->address); + LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, wp->rw, wp->address); if (wp->set) { LOG_ERROR("%s watchpoint already set", __func__); @@ -1220,7 +1223,7 @@ static int set_watchpoint(struct target *t, struct watchpoint *wp) wp->set = wp_num + 1; debug_reg_list[wp_num].used = 1; debug_reg_list[wp_num].bp_value = wp->address; - LOG_USER("'%s' watchpoint %d set at 0x%08" PRIx32 " with length %" PRIu32 " (hwreg=%d)", + LOG_USER("'%s' watchpoint %d set at " TARGET_ADDR_FMT " with length %" PRIu32 " (hwreg=%d)", wp->rw == WPT_READ ? "read" : wp->rw == WPT_WRITE ? "write" : wp->rw == WPT_ACCESS ? "access" : "?", wp->unique_id, wp->address, wp->length, wp_num); @@ -1231,7 +1234,7 @@ static int unset_watchpoint(struct target *t, struct watchpoint *wp) { struct x86_32_common *x86_32 = target_to_x86_32(t); struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list; - LOG_DEBUG("type=%d, addr=0x%08" PRIx32, wp->rw, wp->address); + LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, wp->rw, wp->address); if (!wp->set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; @@ -1249,7 +1252,7 @@ static int unset_watchpoint(struct target *t, struct watchpoint *wp) debug_reg_list[wp_num].bp_value = 0; wp->set = 0; - LOG_USER("'%s' watchpoint %d removed from 0x%08" PRIx32 " with length %" PRIu32 " (hwreg=%d)", + LOG_USER("'%s' watchpoint %d removed from " TARGET_ADDR_FMT " with length %" PRIu32 " (hwreg=%d)", wp->rw == WPT_READ ? "read" : wp->rw == WPT_WRITE ? "write" : wp->rw == WPT_ACCESS ? "access" : "?", wp->unique_id, wp->address, wp->length, wp_num); diff --git a/src/target/x86_32_common.h b/src/target/x86_32_common.h index b5877da4..0aaa963d 100644 --- a/src/target/x86_32_common.h +++ b/src/target/x86_32_common.h @@ -309,14 +309,14 @@ int x86_32_get_gdb_reg_list(struct target *t, int x86_32_common_init_arch_info(struct target *target, struct x86_32_common *x86_32); int x86_32_common_mmu(struct target *t, int *enabled); -int x86_32_common_virt2phys(struct target *t, uint32_t address, uint32_t *physical); -int x86_32_common_read_phys_mem(struct target *t, uint32_t phys_address, +int x86_32_common_virt2phys(struct target *t, target_addr_t address, target_addr_t *physical); +int x86_32_common_read_phys_mem(struct target *t, target_addr_t phys_address, uint32_t size, uint32_t count, uint8_t *buffer); -int x86_32_common_write_phys_mem(struct target *t, uint32_t phys_address, +int x86_32_common_write_phys_mem(struct target *t, target_addr_t phys_address, uint32_t size, uint32_t count, const uint8_t *buffer); -int x86_32_common_read_memory(struct target *t, uint32_t addr, +int x86_32_common_read_memory(struct target *t, target_addr_t addr, uint32_t size, uint32_t count, uint8_t *buf); -int x86_32_common_write_memory(struct target *t, uint32_t addr, +int x86_32_common_write_memory(struct target *t, target_addr_t addr, uint32_t size, uint32_t count, const uint8_t *buf); int x86_32_common_read_io(struct target *t, uint32_t addr, uint32_t size, uint8_t *buf); diff --git a/src/target/xscale.c b/src/target/xscale.c index e54033fe..8fe8a2cb 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -59,7 +59,7 @@ /* forward declarations */ static int xscale_resume(struct target *, int current, - uint32_t address, int handle_breakpoints, int debug_execution); + target_addr_t address, int handle_breakpoints, int debug_execution); static int xscale_debug_entry(struct target *); static int xscale_restore_banked(struct target *); static int xscale_get_reg(struct reg *reg); @@ -1120,7 +1120,7 @@ static void xscale_free_trace_data(struct xscale_common *xscale) } static int xscale_resume(struct target *target, int current, - uint32_t address, int handle_breakpoints, int debug_execution) + target_addr_t address, int handle_breakpoints, int debug_execution) { struct xscale_common *xscale = target_to_xscale(target); struct arm *arm = &xscale->arm; @@ -1165,7 +1165,8 @@ static int xscale_resume(struct target *target, int current, enum trace_mode saved_trace_mode; /* there's a breakpoint at the current PC, we have to step over it */ - LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", breakpoint->address); + LOG_DEBUG("unset breakpoint at " TARGET_ADDR_FMT "", + breakpoint->address); xscale_unset_breakpoint(target, breakpoint); /* calculate PC of next instruction */ @@ -1222,7 +1223,8 @@ static int xscale_resume(struct target *target, int current, LOG_DEBUG("disable single-step"); xscale_disable_single_step(target); - LOG_DEBUG("set breakpoint at 0x%8.8" PRIx32 "", breakpoint->address); + LOG_DEBUG("set breakpoint at " TARGET_ADDR_FMT "", + breakpoint->address); xscale_set_breakpoint(target, breakpoint); } } @@ -1384,7 +1386,7 @@ static int xscale_step_inner(struct target *target, int current, } static int xscale_step(struct target *target, int current, - uint32_t address, int handle_breakpoints) + target_addr_t address, int handle_breakpoints) { struct arm *arm = target_to_arm(target); struct breakpoint *breakpoint = NULL; @@ -1778,7 +1780,7 @@ static int xscale_restore_banked(struct target *target) return ERROR_OK; } -static int xscale_read_memory(struct target *target, uint32_t address, +static int xscale_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct xscale_common *xscale = target_to_xscale(target); @@ -1786,7 +1788,7 @@ static int xscale_read_memory(struct target *target, uint32_t address, uint32_t i; int retval; - LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, + LOG_DEBUG("address: " TARGET_ADDR_FMT ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); @@ -1864,7 +1866,7 @@ static int xscale_read_memory(struct target *target, uint32_t address, return ERROR_OK; } -static int xscale_read_phys_memory(struct target *target, uint32_t address, +static int xscale_read_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct xscale_common *xscale = target_to_xscale(target); @@ -1879,13 +1881,13 @@ static int xscale_read_phys_memory(struct target *target, uint32_t address, return ERROR_FAIL; } -static int xscale_write_memory(struct target *target, uint32_t address, +static int xscale_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct xscale_common *xscale = target_to_xscale(target); int retval; - LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, + LOG_DEBUG("address: " TARGET_ADDR_FMT ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); @@ -1963,7 +1965,7 @@ static int xscale_write_memory(struct target *target, uint32_t address, return ERROR_OK; } -static int xscale_write_phys_memory(struct target *target, uint32_t address, +static int xscale_write_phys_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct xscale_common *xscale = target_to_xscale(target); @@ -3093,7 +3095,7 @@ COMMAND_HANDLER(xscale_handle_cache_info_command) } static int xscale_virt2phys(struct target *target, - uint32_t virtual, uint32_t *physical) + target_addr_t virtual, target_addr_t *physical) { struct xscale_common *xscale = target_to_xscale(target); uint32_t cb; diff --git a/tcl/board/atmel_samg55_xplained_pro.cfg b/tcl/board/atmel_samg55_xplained_pro.cfg new file mode 100644 index 00000000..3797bf8b --- /dev/null +++ b/tcl/board/atmel_samg55_xplained_pro.cfg @@ -0,0 +1,11 @@ +# +# Atmel SAMG55 Xplained Pro evaluation kit. +# http://www.atmel.com/tools/ATSAMG55-XPRO.aspx +# + +source [find interface/cmsis-dap.cfg] + +# chip name +set CHIPNAME ATSAMG55J19 + +source [find target/at91samg5x.cfg] diff --git a/tcl/board/lemaker_hikey.cfg b/tcl/board/lemaker_hikey.cfg new file mode 100644 index 00000000..d7244404 --- /dev/null +++ b/tcl/board/lemaker_hikey.cfg @@ -0,0 +1,26 @@ +# +# board configuration for LeMaker Hikey +# + +# board does not feature anything but JTAG +transport select jtag + +# SRST-only reset configuration +reset_config srst_only srst_push_pull + +source [find target/hi6220.cfg] + +# halt the cores when gdb attaches +${_TARGETNAME}0 configure -event gdb-attach "halt" + +# make sure the default target is the boot core +targets ${_TARGETNAME}0 + +proc core_up { args } { + global _TARGETNAME + + # examine remaining cores + foreach _core [set args] { + ${_TARGETNAME}$_core arp_examine + } +} diff --git a/tcl/board/st_nucleo_f7.cfg b/tcl/board/st_nucleo_f7.cfg new file mode 100644 index 00000000..88a8a308 --- /dev/null +++ b/tcl/board/st_nucleo_f7.cfg @@ -0,0 +1,10 @@ +# STMicroelectronics STM32F7 Nucleo development board +# Known boards: NUCLEO-F746ZG and NUCLEO-F767ZI + +source [find interface/stlink-v2-1.cfg] + +transport select hla_swd + +source [find target/stm32f7x.cfg] + +reset_config srst_only diff --git a/tcl/board/st_nucleo_l073rz.cfg b/tcl/board/st_nucleo_l073rz.cfg new file mode 100644 index 00000000..fa9dc87c --- /dev/null +++ b/tcl/board/st_nucleo_l073rz.cfg @@ -0,0 +1,12 @@ +# This is an ST NUCLEO-L073RZ board with single STM32L073RZ chip. +# http://www.st.com/en/evaluation-tools/nucleo-l073rz.html +source [find interface/stlink-v2-1.cfg] + +transport select hla_swd + +set WORKAREASIZE 0x2000 + +source [find target/stm32l0_dual_bank.cfg] + +# There is only system reset line and JTAG/SWD command can be issued when SRST +reset_config srst_only diff --git a/tcl/board/ti_beaglebone-base.cfg b/tcl/board/ti_beaglebone-base.cfg new file mode 100644 index 00000000..82d3c312 --- /dev/null +++ b/tcl/board/ti_beaglebone-base.cfg @@ -0,0 +1,4 @@ +# AM335x Beaglebone family base configuration +# http://beagleboard.org/bone + +source [find target/am335x.cfg] diff --git a/tcl/board/ti_beaglebone.cfg b/tcl/board/ti_beaglebone.cfg index 5d31d1d9..a54ad627 100644 --- a/tcl/board/ti_beaglebone.cfg +++ b/tcl/board/ti_beaglebone.cfg @@ -6,8 +6,8 @@ source [find interface/ftdi/xds100v2.cfg] adapter_khz 16000 -source [find target/am335x.cfg] - reset_config trst_and_srst +source [find board/ti_beaglebone-base.cfg] + diff --git a/tcl/board/ti_beaglebone_black.cfg b/tcl/board/ti_beaglebone_black.cfg new file mode 100644 index 00000000..79fc1e8a --- /dev/null +++ b/tcl/board/ti_beaglebone_black.cfg @@ -0,0 +1,8 @@ +# AM335x Beaglebone Black +# http://beagleboard.org/bone + +adapter_khz 1000 + +reset_config trst_and_srst + +source [find board/ti_beaglebone-base.cfg] diff --git a/tcl/cpld/altera-5m570z-cpld.cfg b/tcl/cpld/altera-5m570z-cpld.cfg new file mode 100644 index 00000000..22a422c4 --- /dev/null +++ b/tcl/cpld/altera-5m570z-cpld.cfg @@ -0,0 +1,6 @@ +# Altera MAXV 5M24OZ/5M570Z CPLD +# see MAX V Device Handbook +# Table 6-3: 32-Bit MAX V Device IDCODE +# Version Part Number Manuf. ID LSB +# 0000 0010 0000 1010 0111 000 0110 1110 1 +jtag newtap 5m570z tap -expected-id 0x020a60dd -irlen 10 diff --git a/tcl/interface/ftdi/incircuit-icprog.cfg b/tcl/interface/ftdi/incircuit-icprog.cfg new file mode 100644 index 00000000..5e90a703 --- /dev/null +++ b/tcl/interface/ftdi/incircuit-icprog.cfg @@ -0,0 +1,14 @@ +# +# In-Circuit's ICprog OpenOCD JTAG Adapter +# https://shop.in-circuit.de/product_info.php?products_id=112 +# +# Schematics available at +# http://wiki.in-circuit.de/images/0/06/610000158A_openocd.pdf +# + +interface ftdi +ftdi_vid_pid 0x0403 0x6010 + +ftdi_layout_init 0x0508 0x0f1b +ftdi_layout_signal nSRST -noe 0x0400 -data 0x0800 +ftdi_layout_signal nTRST -noe 0x0100 -data 0x0200 diff --git a/tcl/interface/imx-native.cfg b/tcl/interface/imx-native.cfg new file mode 100644 index 00000000..c2f80eb5 --- /dev/null +++ b/tcl/interface/imx-native.cfg @@ -0,0 +1,35 @@ +# +# Config for using NXP IMX CPU +# +# This is best used with a fast enough buffer but also +# is suitable for direct connection if the target voltage +# matches to host voltage and the cable is short enough. +# +# + +interface imx_gpio + +# For most IMX processors 0x0209c000 +imx_gpio_peripheral_base 0x0209c000 + +# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET +# These depend on system clock, calibrated for IMX6UL@528MHz +# imx_gpio_speed SPEED_COEFF SPEED_OFFSET +imx_gpio_speed_coeffs 50000 50 + +# Each of the JTAG lines need a gpio number set: tck tms tdi tdo. +# Example configuration: +# imx_gpio_jtag_nums 6 7 8 9 + +# SWD interface pins: swclk swdio +# Example configuration: +imx_gpio_swd_nums 1 6 + +# imx_gpio_trst_num 10 +# reset_config trst_only + +# imx_gpio_srst_num 11 +# reset_config srst_only srst_push_pull + +# or if you have both connected, +# reset_config trst_and_srst srst_push_pull \ No newline at end of file diff --git a/tcl/interface/kitprog.cfg b/tcl/interface/kitprog.cfg new file mode 100644 index 00000000..94497147 --- /dev/null +++ b/tcl/interface/kitprog.cfg @@ -0,0 +1,12 @@ +# +# Cypress Semiconductor KitProg +# +# Note: This is the driver for the proprietary KitPtog protocol. If the +# KitProg is in CMSIS-DAP mode, you should either use the cmsis-dap +# interface driver or switch the KitProg to KitProg mode. +# + +interface kitprog + +# Optionally specify the serial number of the KitProg you want to use. +#kitprog_serial 1926402735485200 diff --git a/tcl/stm32f4.cfg b/tcl/stm32f4.cfg index dda02998..3e4c81c4 100644 --- a/tcl/stm32f4.cfg +++ b/tcl/stm32f4.cfg @@ -12,6 +12,18 @@ proc stm_flash {IMGFILE} { shutdown } +proc stm_flash_addr {IMGFILE ADDR} { + reset halt + wait_halt + sleep 100 + flash write_image erase $IMGFILE $ADDR + sleep 100 + verify_image $IMGFILE $ADDR + sleep 100 + reset run + shutdown +} + stm32f4x.cpu configure -event gdb-detach { shutdown } diff --git a/tcl/stm32l4.cfg b/tcl/stm32l4.cfg index 292724c4..b96d420e 100644 --- a/tcl/stm32l4.cfg +++ b/tcl/stm32l4.cfg @@ -12,6 +12,18 @@ proc stm_flash {IMGFILE} { shutdown } +proc stm_flash_addr {IMGFILE ADDR} { + reset halt + wait_halt + sleep 100 + flash write_image erase $IMGFILE $ADDR + sleep 100 + verify_image $IMGFILE $ADDR + sleep 100 + reset run + shutdown +} + stm32l4x.cpu configure -event gdb-detach { shutdown } diff --git a/tcl/target/atmega128rfa1.cfg b/tcl/target/atmega128rfa1.cfg new file mode 100644 index 00000000..2c12a610 --- /dev/null +++ b/tcl/target/atmega128rfa1.cfg @@ -0,0 +1,22 @@ +set _CHIPNAME avr +set _ENDIAN little + +# jtag speed +adapter_khz 4500 + +# avr jtag docs never connect RSTN +reset_config none + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x0a70103f +} +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME avr -endian $_ENDIAN -chain-position $_TARGETNAME + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME avr 0 0 0 0 $_TARGETNAME diff --git a/tcl/target/hi6220.cfg b/tcl/target/hi6220.cfg new file mode 100644 index 00000000..7daa3c11 --- /dev/null +++ b/tcl/target/hi6220.cfg @@ -0,0 +1,56 @@ +# Hisilicon Hi6220 Target + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME hi6220 +} + +# +# Main DAP +# +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x4ba00477 +} + +# 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 + +# declare the 8 main application cores +set _TARGETNAME $_CHIPNAME.cpu +set _smp_command "" + +set $_TARGETNAME.cti(0) 0x80198000 +set $_TARGETNAME.cti(1) 0x80199000 +set $_TARGETNAME.cti(2) 0x8019A000 +set $_TARGETNAME.cti(3) 0x8019B000 +set $_TARGETNAME.cti(4) 0x801D8000 +set $_TARGETNAME.cti(5) 0x801D9000 +set $_TARGETNAME.cti(6) 0x801DA000 +set $_TARGETNAME.cti(7) 0x801DB000 + +set _cores 8 +for { set _core 0 } { $_core < $_cores } { incr _core 1 } { + + set _command "target create ${_TARGETNAME}$_core aarch64 \ + -chain-position $_CHIPNAME.dap -coreid $_core -ctibase [set $_TARGETNAME.cti($_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 + +# 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 diff --git a/tcl/target/stm32l0_dual_bank.cfg b/tcl/target/stm32l0_dual_bank.cfg new file mode 100644 index 00000000..f9f1a4e7 --- /dev/null +++ b/tcl/target/stm32l0_dual_bank.cfg @@ -0,0 +1,5 @@ +source [find target/stm32l0.cfg] + +# Add the second flash bank. +set _FLASHNAME $_CHIPNAME.flash1 +flash bank $_FLASHNAME stm32lx 0 0 0 0 $_TARGETNAME diff --git a/tcl/target/stm32l4x.cfg b/tcl/target/stm32l4x.cfg index 9cad7c49..ccee48e9 100644 --- a/tcl/target/stm32l4x.cfg +++ b/tcl/target/stm32l4x.cfg @@ -75,7 +75,7 @@ $_TARGETNAME configure -event reset-init { # Use MSI 24 MHz clock, compliant even with VOS == 2. # 3 WS compliant with VOS == 2 and 24 MHz. mww 0x40022000 0x00000103 ;# FLASH_ACR = PRFTBE | 3(Latency) - mww 0x40021000 0x00000099 ;# RCC_CR = MSI_ON | MSIRGSEL| MSI Range 10 + mww 0x40021000 0x00000099 ;# RCC_CR = MSI_ON | MSIRGSEL | MSI Range 9 # Boost JTAG frequency adapter_khz 4000 } diff --git a/tools/scripts/checkpatch.pl b/tools/scripts/checkpatch.pl index 92befc6f..b977d361 100755 --- a/tools/scripts/checkpatch.pl +++ b/tools/scripts/checkpatch.pl @@ -2224,7 +2224,7 @@ sub process { # function brace can't be on same line, except for #defines of do while, # or if closed on same line - if (($line=~/$Type\s*$Ident\(.*\).*\s{/) and + if (($line=~/$Type\s*$Ident\(.*\).*\s\{/) and !($line=~/\#\s*define.*do\s\{/) and !($line=~/}/)) { ERROR("OPEN_BRACE", "open brace '{' following function declarations go on the next line\n" . $herecurr);