From upstream (#684)
* flash/nor/atsame5: add LAN9255 devices Support Microchip LAN9255 devices with embedded SAME53J MCU. Signed-off-by: Hans-Erik Floryd <hans-erik.floryd@rt-labs.com> Change-Id: Ia811c593bf7cf73e588d32873c68eb67c6fafad7 Reviewed-on: https://review.openocd.org/c/openocd/+/6811 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * tcl/board: Add EVB-LAN9255 config Config for EVB-LAN9255, tested using Atmel-ICE debugger on J10 connector. Signed-off-by: Hans-Erik Floryd <hans-erik.floryd@rt-labs.com> Change-Id: I8bcf779e9363499a98aa0b7d10819c53da6a19e7 Reviewed-on: https://review.openocd.org/c/openocd/+/6812 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * aarch64: support for aarch32 ARM_MODE_UND Fix: unrecognized psr mode: 0x1b cannot read system control register in this mode: (UNRECOGNIZED : 0x1b) Change-Id: I4dc3e72f90d57e52c0fe63cb59a7529a398757b3 Signed-off-by: Julien Massot <julien.massot@iot.bzh> Change-Id: Ifa5d21ae97492fde9e8c79ee7d99d8a2a871b1b5 Reviewed-on: https://review.openocd.org/c/openocd/+/6808 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * Combine register lists of smp targets. This is helpful when you want to pretend to gdb that your heterogeneous multicore system is homogeneous, because gdb cannot handle heterogeneous systems. This won't always works, but works fine if e.g. one of the cores has an FPU while the other does not. (Specifically, HiFive Unleashed has 1 core with no FPU, plus 4 cores with an FPU.) Signed-off-by: Tim Newsome <tim@sifive.com> Change-Id: I05ff4c28646778fbc00327bc510be064bfe6c9f0 Reviewed-on: https://review.openocd.org/c/openocd/+/6362 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * semihosting: use open mode flags from GDB, not from sys/stat.h Values defined in sys/stat.h are not guaranteed to match the constants defined by the GDB remote protocol, which are defined in https://sourceware.org/gdb/onlinedocs/gdb/Open-Flags.html#Open-Flags. On my local system (Manjaro 21.2.1 x86_64), for example, O_TRUNC is defined as 0x40, whereas GDB requires it to be 0x400, causing all "w" file open modes to misbehave. This patch has been tested with STM32F446. Change-Id: Ifb2c740fd689e71d6f1a4bde1edaecd76fdca910 Signed-off-by: Pavel Kirienko <pavel.kirienko@gmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/6804 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * semihosting: User defined operation, Tcl command exec on host Enabling a portion (0x100 - 0x107) of the user defined semihosting operation number range (0x100 - 0x1FF) to be processed with the help of the existing target event mechanism, to implement a general-purpose Tcl interface for the target available on the host, via semihosting interface. Example usage: - The user configures a Tcl command as a callback for one of the newly defined events (semihosting-user-cmd-0x10X) in the configuration file. - The target can make a semihosting call with <opnum>, passing optional parameters for the call. If there is no callback registered to the user defined operation number, nothing happens. Example usage: Configure RTT automatically with the exact, linked control block location from target. Signed-off-by: Zoltán Dudás <zedudi@gmail.com> Change-Id: I10e1784b1fecd4e630d78df81cb44bf1aa2fc247 Reviewed-on: https://review.openocd.org/c/openocd/+/6748 Tested-by: jenkins Reviewed-by: Oleksij Rempel <linux@rempel-privat.de> Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * target/smp: use a struct list_head to hold the smp targets Instead of reinventing a simply linked list, reuse the list helper for the list of targets in a smp cluster. Using the existing helper, that implements a double linked list, makes trivial going through the list in reverse order. Change-Id: Ib36ad2955f15cd2a601b0b9e36ca6d948b12d00f Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/6783 Tested-by: jenkins * helper/list: add list_for_each_entry_direction() Use a bool flag to specify if the list should be forward or backward iterated. Change-Id: Ied19d049f46cdcb7f50137d459cc7c02014526bc Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/6784 Tested-by: jenkins * target/riscv: revive 'riscv resume_order' This functionality was lost in [1], which was merged as commit615709d140
("Upstream a whole host of RISC-V changes."). Now it works as expected again. Add convenience macro foreach_smp_target_direction(). Link: [1] https://github.com/riscv/riscv-openocd/pull/567 Change-Id: I1545fa6b45b8a07e27c8ff9dcdcfa2fc4f950cd1 Signed-off-by: Tim Newsome <tim@sifive.com> Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/6785 Tested-by: jenkins * doxygen: fix some function prototype description Change-Id: I49311a643ea73143839d2f6bde976cfd76f8c67f Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/6830 Tested-by: jenkins * Cadence virtual debug interface (vdebug) integration Change-Id: I1bc105b3addc3f34161c2356c482ff3011e3f2cc Signed-off-by: Jacek Wuwer <jacekmw8@gmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/6097 Tested-by: jenkins Reviewed-by: Oleksij Rempel <linux@rempel-privat.de> Reviewed-by: zapb <dev@zapb.de> Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * gdb_server: Include thread name as XML attribute Explicitly providing a thread name in the "thread" element produces better thread visualizations in downstream tools like IDEs. Signed-off-by: Ben McMorran <bemcmorr@microsoft.com> Change-Id: I102c14ddb8b87757fa474de8e3a3f6a1cfe10d98 Reviewed-on: https://review.openocd.org/c/openocd/+/6828 Tested-by: jenkins Reviewed-by: zapb <dev@zapb.de> Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * Fix small memory leak. See https://github.com/riscv/riscv-openocd/pull/672 Change-Id: Ia11ab9bcf860f770ea64ad867102c74b898f6b66 Signed-off-by: Tim Newsome <tim@sifive.com> Reviewed-on: https://review.openocd.org/c/openocd/+/6831 Tested-by: jenkins Reviewed-by: zapb <dev@zapb.de> Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * server: remove remaining crust from dropped eCos code Commit39650e2273
("ecosboard: delete bit-rotted eCos code") has removed eCos code but has left some empty function that was used during non-eCos build to replace eCos mutex. Drop the functions and the file that contain them. Change-Id: I31bc0237ea699c11bd70921660f960ee406ffa80 Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/6835 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> * rtos: threadx: Add hla_target support for ThreadX Tested with an AZ3166 dev board (which uses the STM32F412ZGT6) running the Azure RTOS ThreadX demonstration system. Signed-off-by: Ben McMorran <bemcmorr@microsoft.com> Change-Id: I44c8f7701d9f1aaa872274166321cd7d34fb1855 Reviewed-on: https://review.openocd.org/c/openocd/+/6829 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * .gitmodules: switch away from repo.or.cz The host repo.or.cz is often offline, creating issues for cloning and building OpenOCD from scratch. Already 'jimtcl' developer has dropped repo.or.cz, triggering the OpenOCD commit861e75f54e
("jimtcl: switch to github"). Change also the link of the remaining submodules 'git2cl' and 'libjaylink' to their respective main repository. Change-Id: Ib513237427635359ce36a480a8f2060e2fb12ba4 Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/6834 Tested-by: jenkins Reviewed-by: zapb <dev@zapb.de> * flash/nor/stm32f2x: Fix erase of bank 2 sectors This commit corrects the erase function for stm32f2x when dealing with sectors in bank 2, for STM32F42x/43x devices with 1MB flash. On STM32F42x/43x with 1MB flash in dual bank configuration, the sector numbering is not consecutive. The last sector in bank 1 is number 7, and the first sector in bank 2 is number 12. The sector indices used by openocd, however, _are_ consecutive (0 to 15 in this case). The arguments "first" and "last" to stm32x_erase() are of this type, and so the logic surrounding sector numbers needed to be corrected. Since the two banks in dual bank mode have the same number of sectors, a sector index in bank 2 is larger than or equal to half the total number of sectors. Change-Id: I15260f8a86d9002769a1ae1c40ebdf62142dae18 Signed-off-by: Simon Johansson <ampleyfly@gmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/6810 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com> * target/cortex_m: fix target_to_cm() helper The third parameter of container_of() should point to the same member as target->arch_info points to, struct arm. It worked just because struct arm is the first member in struct armv7m_common. If you move arm member from the first place, OpenOCD fails heavily. Change-Id: I0c0a5221490945563e17a0a34d99a603f1d6c2ff Signed-off-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-on: https://review.openocd.org/c/openocd/+/6749 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * target/armv7m,cortex_m: introduce checked arch_info cast routines target_to_armv7m() and target_to_cm() do not match the magic number so they are not suitable for use outside of target driver code. Add checked versions of pointer getters. Match the magic number to ensure the returned value points to struct of the correct type. Change-Id: If90ef7e969ef04f0f2103e0da29dcbe8e1ac1c0d Signed-off-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-on: https://review.openocd.org/c/openocd/+/6750 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * target/cortex_m: add Cortex-M part number getter The getter checks the magic numbers in arch_info to detect eventual type mismatch. Change-Id: I61134b05310a97ae9831517d0516c7b4240d35a5 Signed-off-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-on: https://review.openocd.org/c/openocd/+/6751 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com> * flash/nor/stm32xx: fix segfault accessing Cortex-M part number Some of STM32 flash drivers read Cortex-M part number from cortex_m->core_info. In corner cases the core_info pointer was observed uninitialised even if target_was_examined() returned true. See also [1] Use the new and safe helper to get Cortex-M part number. While on it switch also target_to_cm()/target_to_armv7m() to the safe versions. This prevents a crash when the flash bank is misconfigured with non-Cortex-M target. Add missing checks for target_was_examined() to flash probes. [1] 6545: fix crash in case cortex_m->core_info is not set https://review.openocd.org/c/openocd/+/6545 Change-Id: If2471af74ebfe22f14442f48ae109b2e1bb5fa3b Signed-off-by: Tomas Vanek <vanekt@fbl.cz> Fixes:f5898bd93f
(flash/stm32fxx.c: do not read CPUID as this info is stored in cortex_m_common) Reviewed-on: https://review.openocd.org/c/openocd/+/6752 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com> * cpld: altera-epm240: Add additional IDCODEs This adds some additional IDCODEs from the datasheet. It also adds support for customizing the tap name. Signed-off-by: Sean Anderson <sean.anderson@seco.com> Change-Id: I7cda10b92c229b61836c12cd9ca410de358ede2e Reviewed-on: https://review.openocd.org/c/openocd/+/6846 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * cpld: altera-epm240: Increase adapter speed According to the datasheet, the minimum clock period with Vccio1 = 1.5V (the lowest voltage supported) is 143ns, or around 6MHz. Set the default adapter speed to 5 MHz. Signed-off-by: Sean Anderson <sean.anderson@seco.com> Change-Id: I21cad33fa7f1e25e81f43b5d2214d1fa4ec924de Reviewed-on: https://review.openocd.org/c/openocd/+/6847 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * target: Add support for ls1088a The LS1088A is an octo-core aarch64 processor from NXP in the layerscape family. The JTAG is undocumented, but I was able to figure things out from the output of `dap info`. This is the first in-tree example of using the hwthread rtos (as far as I know), so hopefully it can serve as an example to other developers. There are some ETMs, but I was unable to try them out because I got 'invalid command name "etm"' when trying to test things out. Signed-off-by: Sean Anderson <sean.anderson@seco.com> Change-Id: I9b0791d27d8c41170a413a8d86431107a85feba2 Reviewed-on: https://review.openocd.org/c/openocd/+/6848 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * target: ls1088a: Add service processor Normally the service processor is not necessary for debugging. However, if you are using the hard-coded RCW or your boot source is otherwise corrupt, then the general purpose processors will never be released from hold-off. This will cause GDB to become confused if it tries to attach, since they will appear to be running arm32 processors. To deal with this, we can release the CPUs manually with the BRRL register. This register cannot be written to from the axi target, so we need to do it from the service processor target. This involves halting the service processor, modifying the register, and then resuming it again. We try and determine what state the service processor was in to avoid resuming it if it was already halted. The reset vector for the general purpose processors is determined by the boot logation pointer registers in the device configuration unit. Normally these are set using pre-boot initialization commands, but if they are not set then they default to 0. This will cause the CPU to almost immediately hit an illegal instruction. This is fine because we will almost certainly want to attach to the processor and load a program anyway. I considered adding this as an event handler for either gdb-attach or reset-init. However, this command shouldn't be necessary most of the time, and so I don't think we should run it automatically. Signed-off-by: Sean Anderson <sean.anderson@seco.com> Change-Id: I1b725292d8a11274d03af5313dc83678e10e944c Reviewed-on: https://review.openocd.org/c/openocd/+/6850 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * board: Add NXP LS1088ARDB This adds a board file for the NXP LS1088ARDB. This only covers the "primary" JTAG header J55, and not the PCIe header (J91). The only oddity is that the LS1088A and CPLD are muxed by adding/removing a jumper from J48. Unfortunately, it doesn't look like OpenOCD supports this CPLD beyond determining the irlen, so it's not very useful. Those who are interested in experimenting can define CWTAP to access the CPLD, but the default is to access the CPU. Signed-off-by: Sean Anderson <sean.anderson@seco.com> Change-Id: Ia07436a534f86bd907aa5fe2a78a326a27855a24 Reviewed-on: https://review.openocd.org/c/openocd/+/6849 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * gdb_server: fix double free Commit6541233aa7
("Combine register lists of smp targets.") unconditionally assigns the output pointers of the function smp_reg_list_noread(), even if the function fails and returns error. This causes a double free from the caller, that has assigned NULL to the pointers to simplify the error handling. Use local variables in smp_reg_list_noread() and assign the output pointers only on success. Change-Id: Ic0fd2f26520566cf322f0190780e15637c01cfae Fixes:6541233aa7
("Combine register lists of smp targets.") Reported-by: Michele Bisogno <michele.bisogno.ct@renesas.com> Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/6852 Tested-by: jenkins Reviewed-by: Michele Bisogno <michele.bisogno.ct@renesas.com> Reviewed-by: Tim Newsome <tim@sifive.com> * gdb_server: check target examined while combining reg list Commit6541233aa7
("Combine register lists of smp targets.") assumes that all the targets in the SMP cluster are already examined and unconditionally call target_get_gdb_reg_list_noread() that will in turn return error if the target is not examined yet. Skip targets not examined yet. Add an additional check in case the register list cannot be built, e.g. because no target in the SMP cluster is examined. This should never happen, but it's better to play safe. Change-Id: I8609815c3d5144790fb05a870cb0c931540aef8a Fixes:6541233aa7
("Combine register lists of smp targets.") Reported-by: Michele Bisogno <michele.bisogno.ct@renesas.com> Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/6853 Tested-by: jenkins Reviewed-by: Michele Bisogno <michele.bisogno.ct@renesas.com> Reviewed-by: Tim Newsome <tim@sifive.com> * flash/stm32l4x: fix maybe-uninitialized compiler error using gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0 we get: error: ‘retval’ may be used uninitialized in this function fixes:13cd75b6ec
(flash/nor/stm32xx: fix segfault accessing Cortex-M part number) Change-Id: I897c40c5d2233f50a5385d251ebfa536023e5cf7 Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/6861 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> * Fix build. Change-Id: Ia60246246dd859d75659a43d1c59588dbb274d46 Signed-off-by: Tim Newsome <tim@sifive.com> Co-authored-by: Hans-Erik Floryd <hans-erik.floryd@rt-labs.com> Co-authored-by: Julien Massot <julien.massot@iot.bzh> Co-authored-by: Pavel Kirienko <pavel.kirienko@gmail.com> Co-authored-by: Zoltán Dudás <zedudi@gmail.com> Co-authored-by: Antonio Borneo <borneo.antonio@gmail.com> Co-authored-by: Jacek Wuwer <jacekmw8@gmail.com> Co-authored-by: Ben McMorran <bemcmorr@microsoft.com> Co-authored-by: Simon Johansson <ampleyfly@gmail.com> Co-authored-by: Tomas Vanek <vanekt@fbl.cz> Co-authored-by: Sean Anderson <sean.anderson@seco.com> Co-authored-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
This commit is contained in:
parent
87c0cda00f
commit
9e097d0fc4
15
configure.ac
15
configure.ac
|
@ -275,6 +275,10 @@ AC_ARG_ENABLE([jtag_vpi],
|
|||
AS_HELP_STRING([--enable-jtag_vpi], [Enable building support for JTAG VPI]),
|
||||
[build_jtag_vpi=$enableval], [build_jtag_vpi=no])
|
||||
|
||||
AC_ARG_ENABLE([vdebug],
|
||||
AS_HELP_STRING([--enable-vdebug], [Enable building support for Cadence Virtual Debug Interface]),
|
||||
[build_vdebug=$enableval], [build_vdebug=no])
|
||||
|
||||
AC_ARG_ENABLE([jtag_dpi],
|
||||
AS_HELP_STRING([--enable-jtag_dpi], [Enable building support for JTAG DPI]),
|
||||
[build_jtag_dpi=$enableval], [build_jtag_dpi=no])
|
||||
|
@ -514,6 +518,12 @@ AS_IF([test "x$build_jtag_vpi" = "xyes"], [
|
|||
AC_DEFINE([BUILD_JTAG_VPI], [0], [0 if you don't want JTAG VPI.])
|
||||
])
|
||||
|
||||
AS_IF([test "x$build_vdebug" = "xyes"], [
|
||||
AC_DEFINE([BUILD_VDEBUG], [1], [1 if you want Cadence vdebug interface.])
|
||||
], [
|
||||
AC_DEFINE([BUILD_VDEBUG], [0], [0 if you don't want Cadence vdebug interface.])
|
||||
])
|
||||
|
||||
AS_IF([test "x$build_jtag_dpi" = "xyes"], [
|
||||
AC_DEFINE([BUILD_JTAG_DPI], [1], [1 if you want JTAG DPI.])
|
||||
], [
|
||||
|
@ -689,8 +699,9 @@ 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([JTAG_DPI], [test "x$build_jtag_dpi" = "xyes" -o "x$build_jtag_dpi" = "xyes"])
|
||||
AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes"])
|
||||
AM_CONDITIONAL([VDEBUG], [test "x$build_vdebug" = "xyes"])
|
||||
AM_CONDITIONAL([JTAG_DPI], [test "x$build_jtag_dpi" = "xyes"])
|
||||
AM_CONDITIONAL([USB_BLASTER_DRIVER], [test "x$enable_usb_blaster" != "xno" -o "x$enable_usb_blaster_2" != "xno"])
|
||||
AM_CONDITIONAL([AMTJTAGACCEL], [test "x$build_amtjtagaccel" = "xyes"])
|
||||
AM_CONDITIONAL([GW16012], [test "x$build_gw16012" = "xyes"])
|
||||
|
|
|
@ -588,6 +588,12 @@ produced, PDF schematics are easily found and it is easy to make.
|
|||
@* A JTAG driver acting as a client for the JTAG VPI server interface.
|
||||
@* Link: @url{http://github.com/fjullien/jtag_vpi}
|
||||
|
||||
@item @b{vdebug}
|
||||
@* A driver for Cadence virtual Debug Interface to emulated or simulated targets.
|
||||
It implements a client connecting to the vdebug server, which in turn communicates
|
||||
with the emulated or simulated RTL model through a transactor. The current version
|
||||
supports only JTAG as a transport, but other virtual transports, like DAP are planned.
|
||||
|
||||
@item @b{jtag_dpi}
|
||||
@* A JTAG driver acting as a client for the SystemVerilog Direct Programming
|
||||
Interface (DPI) for JTAG devices. DPI allows OpenOCD to connect to the JTAG
|
||||
|
@ -3345,6 +3351,41 @@ This value is only used with the standard variant.
|
|||
@end deffn
|
||||
|
||||
|
||||
@deffn {Interface Driver} {vdebug}
|
||||
Cadence Virtual Debug Interface driver.
|
||||
|
||||
@deffn {Config Command} {vdebug server} host:port
|
||||
Specifies the host and TCP port number where the vdebug server runs.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {vdebug batching} value
|
||||
Specifies the batching method for the vdebug request. Possible values are
|
||||
0 for no batching
|
||||
1 or wr to batch write transactions together (default)
|
||||
2 or rw to batch both read and write transactions
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {vdebug polling} min max
|
||||
Takes two values, representing the polling interval in ms. Lower values mean faster
|
||||
debugger responsiveness, but lower emulation performance. The minimum should be
|
||||
around 10, maximum should not exceed 1000, which is the default gdb and keepalive
|
||||
timeout value.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {vdebug bfm_path} path clk_period
|
||||
Specifies the hierarchical path and input clk period of the vdebug BFM in the design.
|
||||
The hierarchical path uses Verilog notation top.inst.inst
|
||||
The clock period must include the unit, for instance 40ns.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {vdebug mem_path} path base size
|
||||
Specifies the hierarchical path to the design memory instance for backdoor access.
|
||||
Up to 4 memories can be specified. The hierarchical path uses Verilog notation.
|
||||
The base specifies start address in the design address space, size its size in bytes.
|
||||
Both values can use hexadecimal notation with prefix 0x.
|
||||
@end deffn
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Driver} {jtag_dpi}
|
||||
SystemVerilog Direct Programming Interface (DPI) compatible driver for
|
||||
JTAG devices in emulation. The driver acts as a client for the SystemVerilog
|
||||
|
@ -5185,6 +5226,22 @@ when reset disables PLLs needed to use a fast clock.
|
|||
@* After single-step has completed
|
||||
@item @b{trace-config}
|
||||
@* After target hardware trace configuration was changed
|
||||
@item @b{semihosting-user-cmd-0x100}
|
||||
@* The target made a semihosting call with user-defined operation number 0x100
|
||||
@item @b{semihosting-user-cmd-0x101}
|
||||
@* The target made a semihosting call with user-defined operation number 0x101
|
||||
@item @b{semihosting-user-cmd-0x102}
|
||||
@* The target made a semihosting call with user-defined operation number 0x102
|
||||
@item @b{semihosting-user-cmd-0x103}
|
||||
@* The target made a semihosting call with user-defined operation number 0x103
|
||||
@item @b{semihosting-user-cmd-0x104}
|
||||
@* The target made a semihosting call with user-defined operation number 0x104
|
||||
@item @b{semihosting-user-cmd-0x105}
|
||||
@* The target made a semihosting call with user-defined operation number 0x105
|
||||
@item @b{semihosting-user-cmd-0x106}
|
||||
@* The target made a semihosting call with user-defined operation number 0x106
|
||||
@item @b{semihosting-user-cmd-0x107}
|
||||
@* The target made a semihosting call with user-defined operation number 0x107
|
||||
@end itemize
|
||||
|
||||
@quotation Note
|
||||
|
@ -9241,6 +9298,17 @@ To make the SEMIHOSTING_SYS_EXIT call return normally, enable
|
|||
this option (default: disabled).
|
||||
@end deffn
|
||||
|
||||
@deffn {Command} {arm semihosting_read_user_param}
|
||||
@cindex ARM semihosting
|
||||
Read parameter of the semihosting call from the target. Usable in
|
||||
semihosting-user-cmd-0x10* event handlers, returning a string.
|
||||
|
||||
When the target makes semihosting call with operation number from range 0x100-
|
||||
0x107, an optional string parameter can be passed to the server. This parameter
|
||||
is valid during the run of the event handlers and is accessible with this
|
||||
command.
|
||||
@end deffn
|
||||
|
||||
@section ARMv4 and ARMv5 Architecture
|
||||
@cindex ARMv4
|
||||
@cindex ARMv5
|
||||
|
|
|
@ -146,6 +146,9 @@ static const struct samd_part same53_parts[] = {
|
|||
{ 0x04, "SAME53J20A", 1024, 256 },
|
||||
{ 0x05, "SAME53J19A", 512, 192 },
|
||||
{ 0x06, "SAME53J18A", 256, 128 },
|
||||
{ 0x55, "LAN9255/ZMX020", 1024, 256 },
|
||||
{ 0x56, "LAN9255/ZMX019", 512, 192 },
|
||||
{ 0x57, "LAN9255/ZMX018", 256, 128 },
|
||||
};
|
||||
|
||||
/* Known SAME54 parts. */
|
||||
|
|
|
@ -622,15 +622,14 @@ cleanup:
|
|||
static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||
uint32_t device_id_register = 0;
|
||||
|
||||
if (!target_was_examined(target)) {
|
||||
LOG_ERROR("Target not examined yet");
|
||||
return ERROR_FAIL;
|
||||
return ERROR_TARGET_NOT_EXAMINED;
|
||||
}
|
||||
|
||||
switch (cortex_m->core_info->partno) {
|
||||
switch (cortex_m_get_partno_safe(target)) {
|
||||
case CORTEX_M0_PARTNO: /* STM32F0x devices */
|
||||
device_id_register = 0x40015800;
|
||||
break;
|
||||
|
@ -659,15 +658,14 @@ static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id)
|
|||
static int stm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_in_kb)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||
uint32_t flash_size_reg;
|
||||
|
||||
if (!target_was_examined(target)) {
|
||||
LOG_ERROR("Target not examined yet");
|
||||
return ERROR_FAIL;
|
||||
return ERROR_TARGET_NOT_EXAMINED;
|
||||
}
|
||||
|
||||
switch (cortex_m->core_info->partno) {
|
||||
switch (cortex_m_get_partno_safe(target)) {
|
||||
case CORTEX_M0_PARTNO: /* STM32F0x devices */
|
||||
flash_size_reg = 0x1FFFF7CC;
|
||||
break;
|
||||
|
|
|
@ -636,8 +636,8 @@ static int stm32x_erase(struct flash_bank *bank, unsigned int first,
|
|||
|
||||
for (unsigned int i = first; i <= last; i++) {
|
||||
unsigned int snb;
|
||||
if (stm32x_info->has_large_mem && i >= 12)
|
||||
snb = (i - 12) | 0x10;
|
||||
if (stm32x_info->has_large_mem && i >= (bank->num_sectors / 2))
|
||||
snb = (i - (bank->num_sectors / 2)) | 0x10;
|
||||
else
|
||||
snb = i;
|
||||
|
||||
|
@ -966,14 +966,14 @@ static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id)
|
|||
* Only effects Rev A silicon */
|
||||
|
||||
struct target *target = bank->target;
|
||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||
|
||||
/* read stm32 device id register */
|
||||
int retval = target_read_u32(target, 0xE0042000, device_id);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if ((*device_id & 0xfff) == 0x411 && cortex_m->core_info->partno == CORTEX_M4_PARTNO) {
|
||||
if ((*device_id & 0xfff) == 0x411
|
||||
&& cortex_m_get_partno_safe(target) == CORTEX_M4_PARTNO) {
|
||||
*device_id &= ~((0xFFFF << 16) | 0xfff);
|
||||
*device_id |= (0x1000 << 16) | 0x413;
|
||||
LOG_INFO("stm32f4x errata detected - fixing incorrect MCU_IDCODE");
|
||||
|
@ -1011,6 +1011,11 @@ static int stm32x_probe(struct flash_bank *bank)
|
|||
bank->num_prot_blocks = 0;
|
||||
bank->prot_blocks = NULL;
|
||||
|
||||
if (!target_was_examined(target)) {
|
||||
LOG_ERROR("Target not examined yet");
|
||||
return ERROR_TARGET_NOT_EXAMINED;
|
||||
}
|
||||
|
||||
/* if explicitly called out as OTP bank, short circuit probe */
|
||||
if (stm32x_is_otp(bank)) {
|
||||
if (stm32x_otp_is_f7(bank)) {
|
||||
|
|
|
@ -759,7 +759,6 @@ static int stm32x_read_id_code(struct flash_bank *bank, uint32_t *id)
|
|||
static int stm32x_probe(struct flash_bank *bank)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||
struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
|
||||
uint16_t flash_size_in_kb;
|
||||
uint32_t device_id;
|
||||
|
@ -767,6 +766,11 @@ static int stm32x_probe(struct flash_bank *bank)
|
|||
stm32x_info->probed = false;
|
||||
stm32x_info->part_info = NULL;
|
||||
|
||||
if (!target_was_examined(target)) {
|
||||
LOG_ERROR("Target not examined yet");
|
||||
return ERROR_TARGET_NOT_EXAMINED;
|
||||
}
|
||||
|
||||
int retval = stm32x_read_id_code(bank, &stm32x_info->idcode);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
@ -800,7 +804,8 @@ static int stm32x_probe(struct flash_bank *bank)
|
|||
/* get flash size from target */
|
||||
/* STM32H74x/H75x, the second core (Cortex-M4) cannot read the flash size */
|
||||
retval = ERROR_FAIL;
|
||||
if (device_id == DEVID_STM32H74_H75XX && cortex_m->core_info->partno == CORTEX_M4_PARTNO)
|
||||
if (device_id == DEVID_STM32H74_H75XX
|
||||
&& cortex_m_get_partno_safe(target) == CORTEX_M4_PARTNO)
|
||||
LOG_WARNING("%s cannot read the flash size register", target_name(target));
|
||||
else
|
||||
retval = target_read_u16(target, stm32x_info->part_info->fsize_addr, &flash_size_in_kb);
|
||||
|
|
|
@ -1632,13 +1632,14 @@ err_lock:
|
|||
|
||||
static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id)
|
||||
{
|
||||
int retval;
|
||||
int retval = ERROR_OK;
|
||||
struct target *target = bank->target;
|
||||
|
||||
/* try reading possible IDCODE registers, in the following order */
|
||||
uint32_t dbgmcu_idcode[] = {DBGMCU_IDCODE_L4_G4, DBGMCU_IDCODE_G0, DBGMCU_IDCODE_L5};
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(dbgmcu_idcode); i++) {
|
||||
retval = target_read_u32(bank->target, dbgmcu_idcode[i], id);
|
||||
retval = target_read_u32(target, dbgmcu_idcode[i], id);
|
||||
if ((retval == ERROR_OK) && ((*id & 0xfff) != 0) && ((*id & 0xfff) != 0xfff))
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
@ -1647,12 +1648,16 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id)
|
|||
* DBGMCU_IDCODE cannot be read using CPU1 (Cortex-M0+) at AP1,
|
||||
* to solve this read the UID64 (IEEE 64-bit unique device ID register) */
|
||||
|
||||
struct cortex_m_common *cortex_m = target_to_cm(bank->target);
|
||||
struct armv7m_common *armv7m = target_to_armv7m_safe(target);
|
||||
if (!armv7m) {
|
||||
LOG_ERROR("Flash requires Cortex-M target");
|
||||
return ERROR_TARGET_INVALID;
|
||||
}
|
||||
|
||||
/* CPU2 (Cortex-M0+) is supported only with non-hla adapters because it is on AP1.
|
||||
* Using HLA adapters armv7m.debug_ap is null, and checking ap_num triggers a segfault */
|
||||
if (cortex_m->core_info->partno == CORTEX_M0P_PARTNO &&
|
||||
cortex_m->armv7m.debug_ap && cortex_m->armv7m.debug_ap->ap_num == 1) {
|
||||
if (cortex_m_get_partno_safe(target) == CORTEX_M0P_PARTNO &&
|
||||
armv7m->debug_ap && armv7m->debug_ap->ap_num == 1) {
|
||||
uint32_t uid64_ids;
|
||||
|
||||
/* UID64 is contains
|
||||
|
@ -1662,7 +1667,7 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id)
|
|||
*
|
||||
* read only the fixed values {STID,DEVID} from UID64_IDS to identify the device as STM32WLx
|
||||
*/
|
||||
retval = target_read_u32(bank->target, UID64_IDS, &uid64_ids);
|
||||
retval = target_read_u32(target, UID64_IDS, &uid64_ids);
|
||||
if (retval == ERROR_OK && uid64_ids == UID64_IDS_STM32WL) {
|
||||
/* force the DEV_ID to DEVID_STM32WLE_WL5XX and the REV_ID to unknown */
|
||||
*id = DEVID_STM32WLE_WL5XX;
|
||||
|
@ -1700,11 +1705,21 @@ static const char *get_stm32l4_bank_type_str(struct flash_bank *bank)
|
|||
static int stm32l4_probe(struct flash_bank *bank)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
|
||||
const struct stm32l4_part_info *part_info;
|
||||
uint16_t flash_size_kb = 0xffff;
|
||||
|
||||
if (!target_was_examined(target)) {
|
||||
LOG_ERROR("Target not examined yet");
|
||||
return ERROR_TARGET_NOT_EXAMINED;
|
||||
}
|
||||
|
||||
struct armv7m_common *armv7m = target_to_armv7m_safe(target);
|
||||
if (!armv7m) {
|
||||
LOG_ERROR("Flash requires Cortex-M target");
|
||||
return ERROR_TARGET_INVALID;
|
||||
}
|
||||
|
||||
stm32l4_info->probed = false;
|
||||
|
||||
/* read stm32 device id registers */
|
||||
|
|
|
@ -656,6 +656,20 @@ static inline void list_splice_tail_init(struct list_head *list,
|
|||
!list_entry_is_head(pos, head, member); \
|
||||
pos = list_prev_entry(pos, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_direction - iterate forward/backward over list of given type
|
||||
* @param forward the iterate direction, true for forward, false for backward.
|
||||
* @param pos the type * to use as a loop cursor.
|
||||
* @param head the head for your list.
|
||||
* @param member the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_direction(forward, pos, head, member) \
|
||||
for (pos = forward ? list_first_entry(head, typeof(*pos), member) \
|
||||
: list_last_entry(head, typeof(*pos), member); \
|
||||
!list_entry_is_head(pos, head, member); \
|
||||
pos = forward ? list_next_entry(pos, member) \
|
||||
: list_prev_entry(pos, member))
|
||||
|
||||
/**
|
||||
* list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
|
||||
* @param pos the type * to use as a start point
|
||||
|
|
|
@ -75,6 +75,9 @@ endif
|
|||
if JTAG_VPI
|
||||
DRIVERFILES += %D%/jtag_vpi.c
|
||||
endif
|
||||
if VDEBUG
|
||||
DRIVERFILES += %D%/vdebug.c
|
||||
endif
|
||||
if JTAG_DPI
|
||||
DRIVERFILES += %D%/jtag_dpi.c
|
||||
endif
|
||||
|
|
|
@ -114,8 +114,6 @@ static int jlink_flush(void);
|
|||
* @param in A pointer to store TDO data to, if NULL the data will be discarded.
|
||||
* @param in_offset A bit offset for TDO data.
|
||||
* @param length Amount of bits to transfer out and in.
|
||||
*
|
||||
* @retval This function doesn't return any value.
|
||||
*/
|
||||
static void jlink_clock_data(const uint8_t *out, unsigned out_offset,
|
||||
const uint8_t *tms_out, unsigned tms_offset,
|
||||
|
|
|
@ -604,8 +604,6 @@ static int ulink_get_queue_size(struct ulink *device,
|
|||
* Clear the OpenULINK command queue.
|
||||
*
|
||||
* @param device pointer to struct ulink identifying ULINK driver instance.
|
||||
* @return on success: ERROR_OK
|
||||
* @return on failure: ERROR_FAIL
|
||||
*/
|
||||
static void ulink_clear_queue(struct ulink *device)
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -57,6 +57,9 @@ extern struct adapter_driver usb_blaster_adapter_driver;
|
|||
#if BUILD_JTAG_VPI == 1
|
||||
extern struct adapter_driver jtag_vpi_adapter_driver;
|
||||
#endif
|
||||
#if BUILD_VDEBUG == 1
|
||||
extern struct adapter_driver vdebug_adapter_driver;
|
||||
#endif
|
||||
#if BUILD_JTAG_DPI == 1
|
||||
extern struct adapter_driver jtag_dpi_adapter_driver;
|
||||
#endif
|
||||
|
@ -168,6 +171,9 @@ struct adapter_driver *adapter_drivers[] = {
|
|||
#if BUILD_JTAG_VPI == 1
|
||||
&jtag_vpi_adapter_driver,
|
||||
#endif
|
||||
#if BUILD_VDEBUG == 1
|
||||
&vdebug_adapter_driver,
|
||||
#endif
|
||||
#if BUILD_JTAG_DPI == 1
|
||||
&jtag_dpi_adapter_driver,
|
||||
#endif
|
||||
|
|
|
@ -546,7 +546,8 @@ int jtag_srst_asserted(int *srst_asserted);
|
|||
* @param field Pointer to scan field.
|
||||
* @param value Pointer to scan value.
|
||||
* @param mask Pointer to scan mask; may be NULL.
|
||||
* @returns Nothing, but calls jtag_set_error() on any error.
|
||||
*
|
||||
* returns Nothing, but calls jtag_set_error() on any error.
|
||||
*/
|
||||
void jtag_check_value_mask(struct scan_field *field, uint8_t *value, uint8_t *mask);
|
||||
|
||||
|
|
|
@ -175,6 +175,18 @@ static const struct threadx_params threadx_params_list[] = {
|
|||
get_stacking_info_arm926ejs, /* fn_get_stacking_info */
|
||||
is_thread_id_valid_arm926ejs, /* fn_is_thread_id_valid */
|
||||
},
|
||||
{
|
||||
"hla_target", /* target_name */
|
||||
4, /* pointer_width; */
|
||||
8, /* thread_stack_offset; */
|
||||
40, /* thread_name_offset; */
|
||||
48, /* thread_state_offset; */
|
||||
136, /* thread_next_offset */
|
||||
&rtos_standard_cortex_m3_stacking, /* stacking_info */
|
||||
1, /* stacking_info_nb */
|
||||
NULL, /* fn_get_stacking_info */
|
||||
NULL, /* fn_is_thread_id_valid */
|
||||
},
|
||||
};
|
||||
|
||||
enum threadx_symbol_values {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "target/target.h"
|
||||
#include "target/target_type.h"
|
||||
#include "target/register.h"
|
||||
#include <target/smp.h>
|
||||
#include "rtos.h"
|
||||
#include "helper/log.h"
|
||||
#include "helper/types.h"
|
||||
|
@ -109,7 +110,7 @@ static int hwthread_update_threads(struct rtos *rtos)
|
|||
|
||||
/* determine the number of "threads" */
|
||||
if (target->smp) {
|
||||
for (head = target->head; head; head = head->next) {
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
|
||||
if (!target_was_examined(curr))
|
||||
|
@ -130,7 +131,7 @@ static int hwthread_update_threads(struct rtos *rtos)
|
|||
|
||||
if (target->smp) {
|
||||
/* loop over all threads */
|
||||
for (head = target->head; head; head = head->next) {
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
|
||||
if (!target_was_examined(curr))
|
||||
|
@ -225,7 +226,8 @@ static struct target *hwthread_find_thread(struct target *target, int64_t thread
|
|||
if (!target)
|
||||
return NULL;
|
||||
if (target->smp) {
|
||||
for (struct target_list *head = target->head; head; head = head->next) {
|
||||
struct target_list *head;
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
if (thread_id == threadid_from_target(head->target))
|
||||
return head->target;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "rtos.h"
|
||||
#include "rtos_standard_stackings.h"
|
||||
#include <target/register.h>
|
||||
#include <target/smp.h>
|
||||
#include "server/gdb_server.h"
|
||||
|
||||
#define LINUX_USER_KERNEL_BORDER 0xc0000000
|
||||
|
@ -191,16 +192,14 @@ static int linux_os_thread_reg_list(struct rtos *rtos,
|
|||
/* search target to perform the access */
|
||||
struct reg **gdb_reg_list;
|
||||
struct target_list *head;
|
||||
head = target->head;
|
||||
found = 0;
|
||||
do {
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
if (head->target->coreid == next->core_id) {
|
||||
target = head->target;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
head = head->next;
|
||||
} while (head);
|
||||
}
|
||||
|
||||
if (found == 0) {
|
||||
LOG_ERROR
|
||||
|
@ -397,7 +396,6 @@ static int get_name(struct target *target, struct threads *t)
|
|||
static int get_current(struct target *target, int create)
|
||||
{
|
||||
struct target_list *head;
|
||||
head = target->head;
|
||||
uint8_t *buf;
|
||||
uint32_t val;
|
||||
uint32_t ti_addr;
|
||||
|
@ -413,7 +411,7 @@ static int get_current(struct target *target, int create)
|
|||
ctt = ctt->next;
|
||||
}
|
||||
|
||||
while (head) {
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct reg **reg_list;
|
||||
int reg_list_size;
|
||||
int retval;
|
||||
|
@ -474,7 +472,6 @@ static int get_current(struct target *target, int create)
|
|||
}
|
||||
|
||||
free(reg_list);
|
||||
head = head->next;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
@ -1394,9 +1391,8 @@ static int linux_os_smp_init(struct target *target)
|
|||
struct linux_os *os_linux =
|
||||
(struct linux_os *)rtos->rtos_specific_params;
|
||||
struct current_thread *ct;
|
||||
head = target->head;
|
||||
|
||||
while (head) {
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
if (head->target->rtos != rtos) {
|
||||
struct linux_os *smp_os_linux =
|
||||
(struct linux_os *)head->target->rtos->rtos_specific_params;
|
||||
|
@ -1413,8 +1409,6 @@ static int linux_os_smp_init(struct target *target)
|
|||
os_linux->nr_cpus++;
|
||||
free(smp_os_linux);
|
||||
}
|
||||
|
||||
head = head->next;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
|
|
|
@ -801,7 +801,7 @@ struct rtos *rtos_of_target(struct target *target)
|
|||
if ((target->rtos) && (target->rtos->type))
|
||||
return target->rtos;
|
||||
|
||||
foreach_smp_target(pos, target->head)
|
||||
foreach_smp_target(pos, target->smp_targets)
|
||||
if ((pos->target->rtos) && (pos->target->rtos->type))
|
||||
return pos->target->rtos;
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ noinst_LTLIBRARIES += %D%/libserver.la
|
|||
%D%/server.h \
|
||||
%D%/telnet_server.h \
|
||||
%D%/gdb_server.h \
|
||||
%D%/server_stubs.c \
|
||||
%D%/tcl_server.c \
|
||||
%D%/tcl_server.h \
|
||||
%D%/rtt_server.c \
|
||||
|
|
|
@ -2276,21 +2276,25 @@ static int smp_reg_list_noread(struct target *target,
|
|||
return target_get_gdb_reg_list_noread(target, combined_list,
|
||||
combined_list_size, REG_CLASS_ALL);
|
||||
|
||||
int combined_allocated = 256;
|
||||
*combined_list = malloc(combined_allocated * sizeof(struct reg *));
|
||||
if (*combined_list == NULL) {
|
||||
LOG_ERROR("malloc(%d) failed", (int) (combined_allocated * sizeof(struct reg *)));
|
||||
unsigned int combined_allocated = 256;
|
||||
struct reg **local_list = malloc(combined_allocated * sizeof(struct reg *));
|
||||
if (!local_list) {
|
||||
LOG_ERROR("malloc(%zu) failed", combined_allocated * sizeof(struct reg *));
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
*combined_list_size = 0;
|
||||
unsigned int local_list_size = 0;
|
||||
|
||||
struct target_list *head;
|
||||
foreach_smp_target(head, target->head) {
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
if (!target_was_examined(head->target))
|
||||
continue;
|
||||
|
||||
struct reg **reg_list = NULL;
|
||||
int reg_list_size;
|
||||
int result = target_get_gdb_reg_list_noread(head->target, ®_list,
|
||||
®_list_size, reg_class);
|
||||
if (result != ERROR_OK) {
|
||||
free(*combined_list);
|
||||
free(local_list);
|
||||
return result;
|
||||
}
|
||||
for (int i = 0; i < reg_list_size; i++) {
|
||||
|
@ -2300,8 +2304,8 @@ static int smp_reg_list_noread(struct target *target,
|
|||
/* Nested loop makes this O(n^2), but this entire function with
|
||||
* 5 RISC-V targets takes just 2ms on my computer. Fast enough
|
||||
* for me. */
|
||||
for (int j = 0; j < *combined_list_size; j++) {
|
||||
struct reg *b = (*combined_list)[j];
|
||||
for (unsigned int j = 0; j < local_list_size; j++) {
|
||||
struct reg *b = local_list[j];
|
||||
if (!strcmp(a->name, b->name)) {
|
||||
found = true;
|
||||
if (a->size != b->size) {
|
||||
|
@ -2309,7 +2313,7 @@ static int smp_reg_list_noread(struct target *target,
|
|||
"target, but %d bits on another target.",
|
||||
a->name, a->size, b->size);
|
||||
free(reg_list);
|
||||
free(*combined_list);
|
||||
free(local_list);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
break;
|
||||
|
@ -2317,22 +2321,62 @@ static int smp_reg_list_noread(struct target *target,
|
|||
}
|
||||
if (!found) {
|
||||
LOG_DEBUG("[%s] %s not found in combined list", target_name(target), a->name);
|
||||
if (*combined_list_size >= combined_allocated) {
|
||||
if (local_list_size >= combined_allocated) {
|
||||
combined_allocated *= 2;
|
||||
*combined_list = realloc(*combined_list, combined_allocated * sizeof(struct reg *));
|
||||
if (*combined_list == NULL) {
|
||||
LOG_ERROR("realloc(%d) failed", (int) (combined_allocated * sizeof(struct reg *)));
|
||||
local_list = realloc(local_list, combined_allocated * sizeof(struct reg *));
|
||||
if (!local_list) {
|
||||
LOG_ERROR("realloc(%zu) failed", combined_allocated * sizeof(struct reg *));
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
(*combined_list)[*combined_list_size] = a;
|
||||
(*combined_list_size)++;
|
||||
local_list[local_list_size] = a;
|
||||
local_list_size++;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(reg_list);
|
||||
}
|
||||
|
||||
if (local_list_size == 0) {
|
||||
LOG_ERROR("Unable to get register list");
|
||||
free(local_list);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* Now warn the user about any registers that weren't found in every target. */
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
if (!target_was_examined(head->target))
|
||||
continue;
|
||||
|
||||
struct reg **reg_list = NULL;
|
||||
int reg_list_size;
|
||||
int result = target_get_gdb_reg_list_noread(head->target, ®_list,
|
||||
®_list_size, reg_class);
|
||||
if (result != ERROR_OK) {
|
||||
free(local_list);
|
||||
return result;
|
||||
}
|
||||
for (unsigned int i = 0; i < local_list_size; i++) {
|
||||
bool found = false;
|
||||
struct reg *a = local_list[i];
|
||||
for (int j = 0; j < reg_list_size; j++) {
|
||||
struct reg *b = reg_list[j];
|
||||
if (b->exist && !strcmp(a->name, b->name)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
LOG_WARNING("Register %s does not exist in %s, which is part of an SMP group where "
|
||||
"this register does exist.",
|
||||
a->name, target_name(head->target));
|
||||
}
|
||||
}
|
||||
free(reg_list);
|
||||
}
|
||||
|
||||
*combined_list = local_list;
|
||||
*combined_list_size = local_list_size;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
@ -2595,8 +2639,14 @@ static int gdb_generate_thread_list(struct target *target, char **thread_list_ou
|
|||
if (!thread_detail->exists)
|
||||
continue;
|
||||
|
||||
xml_printf(&retval, &thread_list, &pos, &size,
|
||||
"<thread id=\"%" PRIx64 "\">", thread_detail->threadid);
|
||||
if (thread_detail->thread_name_str)
|
||||
xml_printf(&retval, &thread_list, &pos, &size,
|
||||
"<thread id=\"%" PRIx64 "\" name=\"%s\">",
|
||||
thread_detail->threadid,
|
||||
thread_detail->thread_name_str);
|
||||
else
|
||||
xml_printf(&retval, &thread_list, &pos, &size,
|
||||
"<thread id=\"%" PRIx64 "\">", thread_detail->threadid);
|
||||
|
||||
if (thread_detail->thread_name_str)
|
||||
xml_printf(&retval, &thread_list, &pos, &size,
|
||||
|
@ -3652,13 +3702,10 @@ static int gdb_target_start(struct target *target, const char *port)
|
|||
/* initialize all targets gdb service with the same pointer */
|
||||
{
|
||||
struct target_list *head;
|
||||
struct target *curr;
|
||||
head = target->head;
|
||||
while (head) {
|
||||
curr = head->target;
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
if (curr != target)
|
||||
curr->gdb_service = gdb_service;
|
||||
head = head->next;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
|
|
@ -487,10 +487,8 @@ int server_loop(struct command_context *command_context)
|
|||
timeout_ms = polling_period;
|
||||
tv.tv_usec = timeout_ms * 1000;
|
||||
/* Only while we're sleeping we'll let others run */
|
||||
openocd_sleep_prelude();
|
||||
kept_alive();
|
||||
retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv);
|
||||
openocd_sleep_postlude();
|
||||
}
|
||||
|
||||
if (retval == -1) {
|
||||
|
|
|
@ -97,15 +97,6 @@ int server_register_commands(struct command_context *context);
|
|||
int connection_write(struct connection *connection, const void *data, int len);
|
||||
int connection_read(struct connection *connection, void *data, int len);
|
||||
|
||||
/**
|
||||
* Used by server_loop(), defined in server_stubs.c
|
||||
*/
|
||||
void openocd_sleep_prelude(void);
|
||||
/**
|
||||
* Used by server_loop(), defined in server_stubs.c
|
||||
*/
|
||||
void openocd_sleep_postlude(void);
|
||||
|
||||
/**
|
||||
* Defines an extended command handler function declaration to enable
|
||||
* access to (and manipulation of) the server port number.
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include "server.h"
|
||||
|
||||
void openocd_sleep_prelude(void)
|
||||
{
|
||||
/* no-op */
|
||||
}
|
||||
void openocd_sleep_postlude(void)
|
||||
{
|
||||
/* no-op */
|
||||
}
|
|
@ -102,6 +102,7 @@ static int aarch64_restore_system_control_reg(struct target *target)
|
|||
case ARM_MODE_FIQ:
|
||||
case ARM_MODE_IRQ:
|
||||
case ARM_MODE_HYP:
|
||||
case ARM_MODE_UND:
|
||||
case ARM_MODE_SYS:
|
||||
instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0);
|
||||
break;
|
||||
|
@ -180,6 +181,7 @@ static int aarch64_mmu_modify(struct target *target, int enable)
|
|||
case ARM_MODE_FIQ:
|
||||
case ARM_MODE_IRQ:
|
||||
case ARM_MODE_HYP:
|
||||
case ARM_MODE_UND:
|
||||
case ARM_MODE_SYS:
|
||||
instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0);
|
||||
break;
|
||||
|
@ -331,15 +333,14 @@ static int aarch64_wait_halt_one(struct target *target)
|
|||
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_list *head;
|
||||
struct target *first = NULL;
|
||||
|
||||
LOG_DEBUG("target %s exc %i", target_name(target), exc_target);
|
||||
|
||||
while (head) {
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
struct armv8_common *armv8 = target_to_armv8(curr);
|
||||
head = head->next;
|
||||
|
||||
if (exc_target && curr == target)
|
||||
continue;
|
||||
|
@ -428,7 +429,7 @@ static int aarch64_halt_smp(struct target *target, bool exc_target)
|
|||
struct target_list *head;
|
||||
struct target *curr;
|
||||
|
||||
foreach_smp_target(head, target->head) {
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
int halted;
|
||||
|
||||
curr = head->target;
|
||||
|
@ -478,7 +479,7 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug
|
|||
}
|
||||
|
||||
/* poll all targets in the group, but skip the target that serves GDB */
|
||||
foreach_smp_target(head, target->head) {
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
curr = head->target;
|
||||
/* skip calling context */
|
||||
if (curr == target)
|
||||
|
@ -743,7 +744,7 @@ static int aarch64_prep_restart_smp(struct target *target, int handle_breakpoint
|
|||
struct target *first = NULL;
|
||||
uint64_t address;
|
||||
|
||||
foreach_smp_target(head, target->head) {
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
|
||||
/* skip calling target */
|
||||
|
@ -798,7 +799,7 @@ static int aarch64_step_restart_smp(struct target *target)
|
|||
struct target *curr = target;
|
||||
bool all_resumed = true;
|
||||
|
||||
foreach_smp_target(head, target->head) {
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
uint32_t prsr;
|
||||
int resumed;
|
||||
|
||||
|
@ -886,7 +887,7 @@ static int aarch64_resume(struct target *target, int current,
|
|||
struct target_list *head;
|
||||
bool all_resumed = true;
|
||||
|
||||
foreach_smp_target(head, target->head) {
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
uint32_t prsr;
|
||||
int resumed;
|
||||
|
||||
|
@ -1049,6 +1050,7 @@ static int aarch64_post_debug_entry(struct target *target)
|
|||
case ARM_MODE_FIQ:
|
||||
case ARM_MODE_IRQ:
|
||||
case ARM_MODE_HYP:
|
||||
case ARM_MODE_UND:
|
||||
case ARM_MODE_SYS:
|
||||
instr = ARMV4_5_MRC(15, 0, 0, 1, 0, 0);
|
||||
break;
|
||||
|
|
|
@ -367,10 +367,13 @@ int arm_semihosting(struct target *target, int *retval)
|
|||
}
|
||||
|
||||
/* Check for ARM operation numbers. */
|
||||
if (semihosting->op >= 0 && semihosting->op <= 0x31) {
|
||||
if ((semihosting->op >= 0 && semihosting->op <= 0x31) ||
|
||||
(semihosting->op >= 0x100 && semihosting->op <= 0x107)) {
|
||||
|
||||
*retval = semihosting_common(target);
|
||||
if (*retval != ERROR_OK) {
|
||||
LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op);
|
||||
LOG_ERROR("Failed semihosting operation (0x%02X)",
|
||||
semihosting->op);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "arm_opcodes.h"
|
||||
#include "target.h"
|
||||
#include "target_type.h"
|
||||
#include "smp.h"
|
||||
|
||||
static void armv7a_show_fault_registers(struct target *target)
|
||||
{
|
||||
|
@ -193,8 +194,7 @@ done:
|
|||
static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way)
|
||||
{
|
||||
struct armv7a_l2x_cache *l2x_cache;
|
||||
struct target_list *head = target->head;
|
||||
struct target *curr;
|
||||
struct target_list *head;
|
||||
|
||||
struct armv7a_common *armv7a = target_to_armv7a(target);
|
||||
l2x_cache = calloc(1, sizeof(struct armv7a_l2x_cache));
|
||||
|
@ -207,15 +207,14 @@ static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t
|
|||
armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache;
|
||||
/* initialize all target in this cluster (smp target)
|
||||
* l2 cache must be configured after smp declaration */
|
||||
while (head) {
|
||||
curr = head->target;
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
if (curr != target) {
|
||||
armv7a = target_to_armv7a(curr);
|
||||
if (armv7a->armv7a_mmu.armv7a_cache.outer_cache)
|
||||
LOG_ERROR("smp target : outer cache already initialized\n");
|
||||
armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache;
|
||||
}
|
||||
head = head->next;
|
||||
}
|
||||
return JIM_OK;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "armv7a_cache.h"
|
||||
#include <helper/time_support.h>
|
||||
#include "arm_opcodes.h"
|
||||
#include "smp.h"
|
||||
|
||||
static int armv7a_l1_d_cache_sanity_check(struct target *target)
|
||||
{
|
||||
|
@ -138,14 +139,10 @@ int armv7a_cache_auto_flush_all_data(struct target *target)
|
|||
|
||||
if (target->smp) {
|
||||
struct target_list *head;
|
||||
struct target *curr;
|
||||
head = target->head;
|
||||
while (head) {
|
||||
curr = head->target;
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
if (curr->state == TARGET_HALTED)
|
||||
retval = armv7a_l1_d_cache_clean_inval_all(curr);
|
||||
|
||||
head = head->next;
|
||||
}
|
||||
} else
|
||||
retval = armv7a_l1_d_cache_clean_inval_all(target);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <helper/time_support.h>
|
||||
#include "target.h"
|
||||
#include "target_type.h"
|
||||
#include "smp.h"
|
||||
|
||||
static int arm7a_l2x_sanity_check(struct target *target)
|
||||
{
|
||||
|
@ -194,8 +195,7 @@ static int arm7a_handle_l2x_cache_info_command(struct command_invocation *cmd,
|
|||
static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way)
|
||||
{
|
||||
struct armv7a_l2x_cache *l2x_cache;
|
||||
struct target_list *head = target->head;
|
||||
struct target *curr;
|
||||
struct target_list *head;
|
||||
|
||||
struct armv7a_common *armv7a = target_to_armv7a(target);
|
||||
if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) {
|
||||
|
@ -210,8 +210,8 @@ static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t
|
|||
|
||||
/* initialize all targets in this cluster (smp target)
|
||||
* l2 cache must be configured after smp declaration */
|
||||
while (head) {
|
||||
curr = head->target;
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
if (curr != target) {
|
||||
armv7a = target_to_armv7a(curr);
|
||||
if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) {
|
||||
|
@ -220,7 +220,6 @@ static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t
|
|||
}
|
||||
armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache;
|
||||
}
|
||||
head = head->next;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
|
|
@ -255,15 +255,48 @@ struct armv7m_common {
|
|||
void (*pre_restore_context)(struct target *target);
|
||||
};
|
||||
|
||||
static inline bool is_armv7m(const struct armv7m_common *armv7m)
|
||||
{
|
||||
return armv7m->common_magic == ARMV7M_COMMON_MAGIC;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the pointer to the target specific struct
|
||||
* without matching a magic number.
|
||||
* Use in target specific service routines, where the correct
|
||||
* type of arch_info is certain.
|
||||
*/
|
||||
static inline struct armv7m_common *
|
||||
target_to_armv7m(struct target *target)
|
||||
{
|
||||
return container_of(target->arch_info, struct armv7m_common, arm);
|
||||
}
|
||||
|
||||
static inline bool is_armv7m(const struct armv7m_common *armv7m)
|
||||
/**
|
||||
* @returns the pointer to the target specific struct
|
||||
* or NULL if the magic number does not match.
|
||||
* Use in a flash driver or any place where mismatch of the arch_info
|
||||
* type can happen.
|
||||
*/
|
||||
static inline struct armv7m_common *
|
||||
target_to_armv7m_safe(struct target *target)
|
||||
{
|
||||
return armv7m->common_magic == ARMV7M_COMMON_MAGIC;
|
||||
if (!target)
|
||||
return NULL;
|
||||
|
||||
if (!target->arch_info)
|
||||
return NULL;
|
||||
|
||||
/* Check the parent type first to prevent peeking memory too far
|
||||
* from arch_info pointer */
|
||||
if (!is_arm(target_to_arm(target)))
|
||||
return NULL;
|
||||
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
if (!is_armv7m(armv7m))
|
||||
return NULL;
|
||||
|
||||
return armv7m;
|
||||
}
|
||||
|
||||
struct armv7m_algorithm {
|
||||
|
|
|
@ -77,6 +77,10 @@ static const struct {
|
|||
.name = "HYP",
|
||||
.psr = ARM_MODE_HYP,
|
||||
},
|
||||
{
|
||||
.name = "UND",
|
||||
.psr = ARM_MODE_UND,
|
||||
},
|
||||
{
|
||||
.name = "SYS",
|
||||
.psr = ARM_MODE_SYS,
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "armv8_cache.h"
|
||||
#include "armv8_dpm.h"
|
||||
#include "armv8_opcodes.h"
|
||||
#include "smp.h"
|
||||
|
||||
/* CLIDR cache types */
|
||||
#define CACHE_LEVEL_HAS_UNIFIED_CACHE 0x4
|
||||
|
@ -250,15 +251,12 @@ static int armv8_flush_all_data(struct target *target)
|
|||
/* 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) {
|
||||
curr = head->target;
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *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);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <helper/log.h>
|
||||
#include "breakpoints.h"
|
||||
#include "rtos/rtos.h"
|
||||
#include "smp.h"
|
||||
|
||||
static const char * const breakpoint_type_strings[] = {
|
||||
"hardware",
|
||||
|
@ -217,24 +218,25 @@ int breakpoint_add(struct target *target,
|
|||
uint32_t length,
|
||||
enum breakpoint_type type)
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
if (target->smp) {
|
||||
struct target_list *head = target->head;
|
||||
struct target_list *head;
|
||||
|
||||
if (type == BKPT_SOFT) {
|
||||
head = list_first_entry(target->smp_targets, struct target_list, lh);
|
||||
struct target *curr = head->target;
|
||||
if (target->rtos)
|
||||
curr = rtos_swbp_target(target, address, length, type);
|
||||
return breakpoint_add_internal(curr, address, length, type);
|
||||
}
|
||||
|
||||
while (head) {
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
retval = breakpoint_add_internal(curr, address, length, type);
|
||||
int retval = breakpoint_add_internal(curr, address, length, type);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
head = head->next;
|
||||
}
|
||||
return retval;
|
||||
|
||||
return ERROR_OK;
|
||||
} else {
|
||||
return breakpoint_add_internal(target, address, length, type);
|
||||
}
|
||||
|
@ -245,19 +247,17 @@ int context_breakpoint_add(struct target *target,
|
|||
uint32_t length,
|
||||
enum breakpoint_type type)
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
if (target->smp) {
|
||||
struct target_list *head;
|
||||
struct target *curr;
|
||||
head = target->head;
|
||||
while (head) {
|
||||
curr = head->target;
|
||||
retval = context_breakpoint_add_internal(curr, asid, length, type);
|
||||
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
int retval = context_breakpoint_add_internal(curr, asid, length, type);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
head = head->next;
|
||||
}
|
||||
return retval;
|
||||
|
||||
return ERROR_OK;
|
||||
} else {
|
||||
return context_breakpoint_add_internal(target, asid, length, type);
|
||||
}
|
||||
|
@ -269,19 +269,17 @@ int hybrid_breakpoint_add(struct target *target,
|
|||
uint32_t length,
|
||||
enum breakpoint_type type)
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
if (target->smp) {
|
||||
struct target_list *head;
|
||||
struct target *curr;
|
||||
head = target->head;
|
||||
while (head) {
|
||||
curr = head->target;
|
||||
retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
|
||||
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
int retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
head = head->next;
|
||||
}
|
||||
return retval;
|
||||
|
||||
return ERROR_OK;
|
||||
} else
|
||||
return hybrid_breakpoint_add_internal(target, address, asid, length, type);
|
||||
}
|
||||
|
@ -348,12 +346,10 @@ void breakpoint_remove(struct target *target, target_addr_t address)
|
|||
if (target->smp) {
|
||||
unsigned int num_breakpoints = 0;
|
||||
struct target_list *head;
|
||||
struct target *curr;
|
||||
head = target->head;
|
||||
while (head) {
|
||||
curr = head->target;
|
||||
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
num_breakpoints += breakpoint_remove_internal(curr, address);
|
||||
head = head->next;
|
||||
}
|
||||
if (!num_breakpoints)
|
||||
LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address);
|
||||
|
@ -366,12 +362,10 @@ void breakpoint_remove_all(struct target *target)
|
|||
{
|
||||
if (target->smp) {
|
||||
struct target_list *head;
|
||||
struct target *curr;
|
||||
head = target->head;
|
||||
while (head) {
|
||||
curr = head->target;
|
||||
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
breakpoint_remove_all_internal(curr);
|
||||
head = head->next;
|
||||
}
|
||||
} else {
|
||||
breakpoint_remove_all_internal(target);
|
||||
|
@ -390,12 +384,10 @@ void breakpoint_clear_target(struct target *target)
|
|||
{
|
||||
if (target->smp) {
|
||||
struct target_list *head;
|
||||
struct target *curr;
|
||||
head = target->head;
|
||||
while (head) {
|
||||
curr = head->target;
|
||||
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
breakpoint_clear_target_internal(curr);
|
||||
head = head->next;
|
||||
}
|
||||
} else {
|
||||
breakpoint_clear_target_internal(target);
|
||||
|
@ -485,21 +477,17 @@ bye:
|
|||
int watchpoint_add(struct target *target, target_addr_t address,
|
||||
uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask)
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
if (target->smp) {
|
||||
struct target_list *head;
|
||||
struct target *curr;
|
||||
head = target->head;
|
||||
|
||||
while (head != (struct target_list *)NULL) {
|
||||
curr = head->target;
|
||||
retval = watchpoint_add_internal(curr, address, length, rw, value,
|
||||
mask);
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
int retval = watchpoint_add_internal(curr, address, length, rw, value, mask);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
head = head->next;
|
||||
}
|
||||
return retval;
|
||||
|
||||
return ERROR_OK;
|
||||
} else {
|
||||
return watchpoint_add_internal(target, address, length, rw, value,
|
||||
mask);
|
||||
|
@ -552,12 +540,10 @@ void watchpoint_remove(struct target *target, target_addr_t address)
|
|||
if (target->smp) {
|
||||
unsigned int num_watchpoints = 0;
|
||||
struct target_list *head;
|
||||
struct target *curr;
|
||||
head = target->head;
|
||||
while (head) {
|
||||
curr = head->target;
|
||||
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
num_watchpoints += watchpoint_remove_internal(curr, address);
|
||||
head = head->next;
|
||||
}
|
||||
if (num_watchpoints == 0)
|
||||
LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " num_watchpoints", address);
|
||||
|
|
|
@ -639,14 +639,11 @@ static int cortex_a_dpm_setup(struct cortex_a_common *a, uint32_t didr)
|
|||
static struct target *get_cortex_a(struct target *target, int32_t coreid)
|
||||
{
|
||||
struct target_list *head;
|
||||
struct target *curr;
|
||||
|
||||
head = target->head;
|
||||
while (head) {
|
||||
curr = head->target;
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED))
|
||||
return curr;
|
||||
head = head->next;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
@ -656,14 +653,12 @@ static int cortex_a_halt_smp(struct target *target)
|
|||
{
|
||||
int retval = 0;
|
||||
struct target_list *head;
|
||||
struct target *curr;
|
||||
head = target->head;
|
||||
while (head) {
|
||||
curr = head->target;
|
||||
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
if ((curr != target) && (curr->state != TARGET_HALTED)
|
||||
&& target_was_examined(curr))
|
||||
retval += cortex_a_halt(curr);
|
||||
head = head->next;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
@ -684,7 +679,7 @@ static int update_halt_gdb(struct target *target)
|
|||
if (target->gdb_service)
|
||||
gdb_target = target->gdb_service->target;
|
||||
|
||||
foreach_smp_target(head, target->head) {
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
curr = head->target;
|
||||
/* skip calling context */
|
||||
if (curr == target)
|
||||
|
@ -951,11 +946,10 @@ static int cortex_a_restore_smp(struct target *target, int handle_breakpoints)
|
|||
{
|
||||
int retval = 0;
|
||||
struct target_list *head;
|
||||
struct target *curr;
|
||||
target_addr_t address;
|
||||
head = target->head;
|
||||
while (head) {
|
||||
curr = head->target;
|
||||
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
if ((curr != target) && (curr->state != TARGET_RUNNING)
|
||||
&& target_was_examined(curr)) {
|
||||
/* resume current address , not in step mode */
|
||||
|
@ -963,8 +957,6 @@ static int cortex_a_restore_smp(struct target *target, int handle_breakpoints)
|
|||
handle_breakpoints, 0);
|
||||
retval += cortex_a_internal_restart(curr);
|
||||
}
|
||||
head = head->next;
|
||||
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#define ARM_CPUID_PARTNO_MASK (0xFFF << ARM_CPUID_PARTNO_POS)
|
||||
|
||||
enum cortex_m_partno {
|
||||
CORTEX_M_PARTNO_INVALID,
|
||||
CORTEX_M0_PARTNO = 0xC20,
|
||||
CORTEX_M1_PARTNO = 0xC21,
|
||||
CORTEX_M3_PARTNO = 0xC23,
|
||||
|
@ -247,13 +248,6 @@ struct cortex_m_common {
|
|||
bool maskints_erratum;
|
||||
};
|
||||
|
||||
static inline struct cortex_m_common *
|
||||
target_to_cm(struct target *target)
|
||||
{
|
||||
return container_of(target->arch_info,
|
||||
struct cortex_m_common, armv7m);
|
||||
}
|
||||
|
||||
static inline bool is_cortex_m_or_hla(const struct cortex_m_common *cortex_m)
|
||||
{
|
||||
return cortex_m->common_magic == CORTEX_M_COMMON_MAGIC;
|
||||
|
@ -267,6 +261,57 @@ static inline bool is_cortex_m_with_dap_access(const struct cortex_m_common *cor
|
|||
return !cortex_m->armv7m.is_hla_target;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the pointer to the target specific struct
|
||||
* without matching a magic number.
|
||||
* Use in target specific service routines, where the correct
|
||||
* type of arch_info is certain.
|
||||
*/
|
||||
static inline struct cortex_m_common *
|
||||
target_to_cm(struct target *target)
|
||||
{
|
||||
return container_of(target->arch_info,
|
||||
struct cortex_m_common, armv7m.arm);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the pointer to the target specific struct
|
||||
* or NULL if the magic number does not match.
|
||||
* Use in a flash driver or any place where mismatch of the arch_info
|
||||
* type can happen.
|
||||
*/
|
||||
static inline struct cortex_m_common *
|
||||
target_to_cortex_m_safe(struct target *target)
|
||||
{
|
||||
/* Check the parent types first to prevent peeking memory too far
|
||||
* from arch_info pointer */
|
||||
if (!target_to_armv7m_safe(target))
|
||||
return NULL;
|
||||
|
||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||
if (!is_cortex_m_or_hla(cortex_m))
|
||||
return NULL;
|
||||
|
||||
return cortex_m;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns cached value of Cortex-M part number
|
||||
* or CORTEX_M_PARTNO_INVALID if the magic number does not match
|
||||
* or core_info is not initialised.
|
||||
*/
|
||||
static inline enum cortex_m_partno cortex_m_get_partno_safe(struct target *target)
|
||||
{
|
||||
struct cortex_m_common *cortex_m = target_to_cortex_m_safe(target);
|
||||
if (!cortex_m)
|
||||
return CORTEX_M_PARTNO_INVALID;
|
||||
|
||||
if (!cortex_m->core_info)
|
||||
return CORTEX_M_PARTNO_INVALID;
|
||||
|
||||
return cortex_m->core_info->partno;
|
||||
}
|
||||
|
||||
int cortex_m_examine(struct target *target);
|
||||
int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint);
|
||||
int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoint);
|
||||
|
|
|
@ -128,14 +128,11 @@ static int mips_m4k_debug_entry(struct target *target)
|
|||
static struct target *get_mips_m4k(struct target *target, int32_t coreid)
|
||||
{
|
||||
struct target_list *head;
|
||||
struct target *curr;
|
||||
|
||||
head = target->head;
|
||||
while (head) {
|
||||
curr = head->target;
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
struct target *curr = head->target;
|
||||
if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED))
|
||||
return curr;
|
||||
head = head->next;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
@ -144,11 +141,10 @@ static int mips_m4k_halt_smp(struct target *target)
|
|||
{
|
||||
int retval = ERROR_OK;
|
||||
struct target_list *head;
|
||||
struct target *curr;
|
||||
head = target->head;
|
||||
while (head) {
|
||||
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
int ret = ERROR_OK;
|
||||
curr = head->target;
|
||||
struct target *curr = head->target;
|
||||
if ((curr != target) && (curr->state != TARGET_HALTED))
|
||||
ret = mips_m4k_halt(curr);
|
||||
|
||||
|
@ -156,7 +152,6 @@ static int mips_m4k_halt_smp(struct target *target)
|
|||
LOG_ERROR("halt failed target->coreid: %" PRId32, curr->coreid);
|
||||
retval = ret;
|
||||
}
|
||||
head = head->next;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
@ -414,12 +409,10 @@ static int mips_m4k_restore_smp(struct target *target, uint32_t address, int han
|
|||
{
|
||||
int retval = ERROR_OK;
|
||||
struct target_list *head;
|
||||
struct target *curr;
|
||||
|
||||
head = target->head;
|
||||
while (head) {
|
||||
foreach_smp_target(head, target->smp_targets) {
|
||||
int ret = ERROR_OK;
|
||||
curr = head->target;
|
||||
struct target *curr = head->target;
|
||||
if ((curr != target) && (curr->state != TARGET_RUNNING)) {
|
||||
/* resume current address , not in step mode */
|
||||
ret = mips_m4k_internal_restore(curr, 1, address,
|
||||
|
@ -431,7 +424,6 @@ static int mips_m4k_restore_smp(struct target *target, uint32_t address, int han
|
|||
retval = ret;
|
||||
}
|
||||
}
|
||||
head = head->next;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -2297,7 +2297,7 @@ static int init_target(struct command_context *cmd_ctx,
|
|||
generic_info->hart_count = &riscv013_hart_count;
|
||||
generic_info->data_bits = &riscv013_data_bits;
|
||||
generic_info->print_info = &riscv013_print_info;
|
||||
if (generic_info->version_specific == NULL) {
|
||||
if (!generic_info->version_specific) {
|
||||
generic_info->version_specific = calloc(1, sizeof(riscv013_info_t));
|
||||
if (!generic_info->version_specific)
|
||||
return ERROR_FAIL;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "target/target.h"
|
||||
#include "target/algorithm.h"
|
||||
#include "target/target_type.h"
|
||||
#include <target/smp.h>
|
||||
#include "jtag/jtag.h"
|
||||
#include "target/register.h"
|
||||
#include "target/breakpoints.h"
|
||||
|
@ -1296,13 +1297,14 @@ int riscv_halt(struct target *target)
|
|||
|
||||
int result = ERROR_OK;
|
||||
if (target->smp) {
|
||||
for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
|
||||
struct target_list *tlist;
|
||||
foreach_smp_target(tlist, target->smp_targets) {
|
||||
struct target *t = tlist->target;
|
||||
if (halt_prep(t) != ERROR_OK)
|
||||
result = ERROR_FAIL;
|
||||
}
|
||||
|
||||
for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
|
||||
foreach_smp_target(tlist, target->smp_targets) {
|
||||
struct target *t = tlist->target;
|
||||
riscv_info_t *i = riscv_info(t);
|
||||
if (i->prepped) {
|
||||
|
@ -1311,7 +1313,7 @@ int riscv_halt(struct target *target)
|
|||
}
|
||||
}
|
||||
|
||||
for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) {
|
||||
foreach_smp_target(tlist, target->smp_targets) {
|
||||
struct target *t = tlist->target;
|
||||
if (halt_finish(t) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
@ -1500,32 +1502,6 @@ static int resume_finish(struct target *target, int debug_execution)
|
|||
debug_execution ? TARGET_EVENT_DEBUG_RESUMED : TARGET_EVENT_RESUMED);
|
||||
}
|
||||
|
||||
/* Return a newly allocated target list, that contains the same targets as in
|
||||
* tlist bit in the opposite order. */
|
||||
static struct target_list *tlist_reverse(struct target_list *tlist)
|
||||
{
|
||||
struct target_list *previous = NULL;
|
||||
struct target_list *reversed = NULL;
|
||||
for (struct target_list *node = tlist; node; node = node->next) {
|
||||
reversed = calloc(1, sizeof(struct target_list));
|
||||
reversed->target = node->target;
|
||||
reversed->next = previous;
|
||||
previous = reversed;
|
||||
}
|
||||
return reversed;
|
||||
}
|
||||
|
||||
/* Free a target list, but not the targets that are referenced. */
|
||||
static void tlist_free(struct target_list *tlist)
|
||||
{
|
||||
struct target_list *node = tlist;
|
||||
while (node) {
|
||||
struct target_list *previous = node;
|
||||
node = node->next;
|
||||
free(previous);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @par single_hart When true, only resume a single hart even if SMP is
|
||||
* configured. This is used to run algorithms on just one hart.
|
||||
|
@ -1541,21 +1517,17 @@ int riscv_resume(
|
|||
LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints);
|
||||
int result = ERROR_OK;
|
||||
if (target->smp && !single_hart) {
|
||||
struct target_list *ordered_tlist;
|
||||
|
||||
if (resume_order == RO_REVERSED)
|
||||
ordered_tlist = tlist_reverse(target->head);
|
||||
else
|
||||
ordered_tlist = target->head;
|
||||
|
||||
for (struct target_list *tlist = ordered_tlist; tlist; tlist = tlist->next) {
|
||||
struct target_list *tlist;
|
||||
foreach_smp_target_direction(resume_order == RO_NORMAL,
|
||||
tlist, target->smp_targets) {
|
||||
struct target *t = tlist->target;
|
||||
if (resume_prep(t, current, address, handle_breakpoints,
|
||||
debug_execution) != ERROR_OK)
|
||||
result = ERROR_FAIL;
|
||||
}
|
||||
|
||||
for (struct target_list *tlist = ordered_tlist; tlist; tlist = tlist->next) {
|
||||
foreach_smp_target_direction(resume_order == RO_NORMAL,
|
||||
tlist, target->smp_targets) {
|
||||
struct target *t = tlist->target;
|
||||
riscv_info_t *i = riscv_info(t);
|
||||
if (i->prepped) {
|
||||
|
@ -1565,15 +1537,13 @@ int riscv_resume(
|
|||
}
|
||||
}
|
||||
|
||||
for (struct target_list *tlist = ordered_tlist; tlist; tlist = tlist->next) {
|
||||
foreach_smp_target_direction(resume_order == RO_NORMAL,
|
||||
tlist, target->smp_targets) {
|
||||
struct target *t = tlist->target;
|
||||
if (resume_finish(t, debug_execution) != ERROR_OK)
|
||||
result = ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (resume_order == RO_REVERSED)
|
||||
tlist_free(ordered_tlist);
|
||||
|
||||
} else {
|
||||
if (resume_prep(target, current, address, handle_breakpoints,
|
||||
debug_execution) != ERROR_OK)
|
||||
|
@ -2230,9 +2200,8 @@ int riscv_openocd_poll(struct target *target)
|
|||
unsigned halts_discovered = 0;
|
||||
unsigned should_remain_halted = 0;
|
||||
unsigned should_resume = 0;
|
||||
unsigned i = 0;
|
||||
for (struct target_list *list = target->head; list;
|
||||
list = list->next, i++) {
|
||||
struct target_list *list;
|
||||
foreach_smp_target(list, target->smp_targets) {
|
||||
struct target *t = list->target;
|
||||
if (!target_was_examined(t))
|
||||
continue;
|
||||
|
@ -2294,8 +2263,7 @@ int riscv_openocd_poll(struct target *target)
|
|||
}
|
||||
|
||||
/* Sample memory if any target is running. */
|
||||
for (struct target_list *list = target->head; list;
|
||||
list = list->next, i++) {
|
||||
foreach_smp_target(list, target->smp_targets) {
|
||||
struct target *t = list->target;
|
||||
if (t->state == TARGET_RUNNING) {
|
||||
sample_memory(target);
|
||||
|
|
|
@ -140,7 +140,9 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval)
|
|||
semihosting->word_size_bytes = riscv_xlen(target) / 8;
|
||||
|
||||
/* Check for ARM operation numbers. */
|
||||
if (semihosting->op >= 0 && semihosting->op <= 0x31) {
|
||||
if ((semihosting->op >= 0 && semihosting->op <= 0x31) ||
|
||||
(semihosting->op >= 0x100 && semihosting->op <= 0x107)) {
|
||||
|
||||
*retval = semihosting_common(target);
|
||||
if (*retval != ERROR_OK) {
|
||||
LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op);
|
||||
|
|
|
@ -52,19 +52,35 @@
|
|||
#include <helper/log.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/**
|
||||
* It is not possible to use O_... flags defined in sys/stat.h because they
|
||||
* are not guaranteed to match the values defined by the GDB Remote Protocol.
|
||||
* See https://sourceware.org/gdb/onlinedocs/gdb/Open-Flags.html#Open-Flags
|
||||
*/
|
||||
enum {
|
||||
TARGET_O_RDONLY = 0x000,
|
||||
TARGET_O_WRONLY = 0x001,
|
||||
TARGET_O_RDWR = 0x002,
|
||||
TARGET_O_APPEND = 0x008,
|
||||
TARGET_O_CREAT = 0x200,
|
||||
TARGET_O_TRUNC = 0x400,
|
||||
/* O_EXCL=0x800 is not required in this implementation. */
|
||||
};
|
||||
|
||||
/* GDB remote protocol does not differentiate between text and binary open modes. */
|
||||
static const int open_modeflags[12] = {
|
||||
O_RDONLY,
|
||||
O_RDONLY | O_BINARY,
|
||||
O_RDWR,
|
||||
O_RDWR | O_BINARY,
|
||||
O_WRONLY | O_CREAT | O_TRUNC,
|
||||
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
|
||||
O_RDWR | O_CREAT | O_TRUNC,
|
||||
O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
|
||||
O_WRONLY | O_CREAT | O_APPEND,
|
||||
O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
|
||||
O_RDWR | O_CREAT | O_APPEND,
|
||||
O_RDWR | O_CREAT | O_APPEND | O_BINARY
|
||||
TARGET_O_RDONLY,
|
||||
TARGET_O_RDONLY,
|
||||
TARGET_O_RDWR,
|
||||
TARGET_O_RDWR,
|
||||
TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC,
|
||||
TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC,
|
||||
TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC,
|
||||
TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC,
|
||||
TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND,
|
||||
TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND,
|
||||
TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND,
|
||||
TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND
|
||||
};
|
||||
|
||||
static int semihosting_common_fileio_info(struct target *target,
|
||||
|
@ -138,6 +154,12 @@ int semihosting_common_init(struct target *target, void *setup,
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* User operation parameter string storage buffer. Contains valid data when the
|
||||
* TARGET_EVENT_SEMIHOSTING_USER_CMD_xxxxx event callbacks are running.
|
||||
*/
|
||||
static char *semihosting_user_op_params;
|
||||
|
||||
/**
|
||||
* Portable implementation of ARM semihosting calls.
|
||||
* Performs the currently pending semihosting operation
|
||||
|
@ -167,7 +189,7 @@ int semihosting_common(struct target *target)
|
|||
/* Enough space to hold 4 long words. */
|
||||
uint8_t fields[4*8];
|
||||
|
||||
LOG_DEBUG("op=0x%x, param=0x%" PRIx64, (int)semihosting->op,
|
||||
LOG_DEBUG("op=0x%x, param=0x%" PRIx64, semihosting->op,
|
||||
semihosting->param);
|
||||
|
||||
switch (semihosting->op) {
|
||||
|
@ -1262,6 +1284,71 @@ int semihosting_common(struct target *target)
|
|||
}
|
||||
break;
|
||||
|
||||
case SEMIHOSTING_USER_CMD_0x100 ... SEMIHOSTING_USER_CMD_0x107:
|
||||
/**
|
||||
* This is a user defined operation (while user cmds 0x100-0x1ff
|
||||
* are possible, only 0x100-0x107 are currently implemented).
|
||||
*
|
||||
* Reads the user operation parameters from target, then fires the
|
||||
* corresponding target event. When the target callbacks returned,
|
||||
* cleans up the command parameter buffer.
|
||||
*
|
||||
* Entry
|
||||
* On entry, the PARAMETER REGISTER contains a pointer to a
|
||||
* two-field data block:
|
||||
* - field 1 Contains a pointer to the bound command parameter
|
||||
* string
|
||||
* - field 2 Contains the command parameter string length
|
||||
*
|
||||
* Return
|
||||
* On exit, the RETURN REGISTER contains the return status.
|
||||
*/
|
||||
{
|
||||
assert(!semihosting_user_op_params);
|
||||
|
||||
retval = semihosting_read_fields(target, 2, fields);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("Failed to read fields for user defined command"
|
||||
" op=0x%x", semihosting->op);
|
||||
return retval;
|
||||
}
|
||||
|
||||
uint64_t addr = semihosting_get_field(target, 0, fields);
|
||||
|
||||
size_t len = semihosting_get_field(target, 1, fields);
|
||||
if (len > SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH) {
|
||||
LOG_ERROR("The maximum length for user defined command "
|
||||
"parameter is %u, received length is %zu (op=0x%x)",
|
||||
SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH,
|
||||
len,
|
||||
semihosting->op);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
semihosting_user_op_params = malloc(len + 1);
|
||||
if (!semihosting_user_op_params)
|
||||
return ERROR_FAIL;
|
||||
semihosting_user_op_params[len] = 0;
|
||||
|
||||
retval = target_read_buffer(target, addr, len,
|
||||
(uint8_t *)(semihosting_user_op_params));
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("Failed to read from target, semihosting op=0x%x",
|
||||
semihosting->op);
|
||||
free(semihosting_user_op_params);
|
||||
semihosting_user_op_params = NULL;
|
||||
return retval;
|
||||
}
|
||||
|
||||
target_handle_event(target, semihosting->op);
|
||||
free(semihosting_user_op_params);
|
||||
semihosting_user_op_params = NULL;
|
||||
|
||||
semihosting->result = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case SEMIHOSTING_SYS_ELAPSED: /* 0x30 */
|
||||
/*
|
||||
* Returns the number of elapsed target ticks since execution
|
||||
|
@ -1608,6 +1695,30 @@ COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_common_semihosting_read_user_param_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
struct semihosting *semihosting = target->semihosting;
|
||||
|
||||
if (CMD_ARGC)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
if (!semihosting->is_active) {
|
||||
LOG_ERROR("semihosting not yet enabled for current target");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (!semihosting_user_op_params) {
|
||||
LOG_ERROR("This command is usable only from a registered user "
|
||||
"semihosting event callback.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
command_print_sameline(CMD, "%s", semihosting_user_op_params);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
const struct command_registration semihosting_common_handlers[] = {
|
||||
{
|
||||
"semihosting",
|
||||
|
@ -1637,5 +1748,12 @@ const struct command_registration semihosting_common_handlers[] = {
|
|||
.usage = "['enable'|'disable']",
|
||||
.help = "activate support for semihosting resumable exit",
|
||||
},
|
||||
{
|
||||
"semihosting_read_user_param",
|
||||
.handler = handle_common_semihosting_read_user_param_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "",
|
||||
.help = "read parameters in semihosting-user-cmd-0x10X callbacks",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
|
|
@ -75,8 +75,14 @@ enum semihosting_operation_numbers {
|
|||
SEMIHOSTING_SYS_WRITE = 0x05,
|
||||
SEMIHOSTING_SYS_WRITEC = 0x03,
|
||||
SEMIHOSTING_SYS_WRITE0 = 0x04,
|
||||
SEMIHOSTING_USER_CMD_0x100 = 0x100, /* First user cmd op code */
|
||||
SEMIHOSTING_USER_CMD_0x107 = 0x107, /* Last supported user cmd op code */
|
||||
SEMIHOSTING_USER_CMD_0x1FF = 0x1FF, /* Last user cmd op code */
|
||||
};
|
||||
|
||||
/** Maximum allowed Tcl command segment length in bytes*/
|
||||
#define SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH (1024 * 1024)
|
||||
|
||||
/*
|
||||
* Codes used by SEMIHOSTING_SYS_EXIT (formerly
|
||||
* SEMIHOSTING_REPORT_EXCEPTION).
|
||||
|
|
|
@ -111,18 +111,18 @@ COMMAND_HANDLER(default_handle_smp_command)
|
|||
}
|
||||
|
||||
if (!strcmp(CMD_ARGV[0], "on")) {
|
||||
foreach_smp_target(head, target->head)
|
||||
foreach_smp_target(head, target->smp_targets)
|
||||
head->target->smp = 1;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (!strcmp(CMD_ARGV[0], "off")) {
|
||||
foreach_smp_target(head, target->head)
|
||||
foreach_smp_target(head, target->smp_targets)
|
||||
head->target->smp = 0;
|
||||
|
||||
/* fixes the target display to the debugger */
|
||||
if (target->head)
|
||||
if (!list_empty(target->smp_targets))
|
||||
target->gdb_service->target = target;
|
||||
|
||||
return ERROR_OK;
|
||||
|
@ -135,9 +135,7 @@ COMMAND_HANDLER(handle_smp_gdb_command)
|
|||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
int retval = ERROR_OK;
|
||||
struct target_list *head;
|
||||
head = target->head;
|
||||
if (head) {
|
||||
if (!list_empty(target->smp_targets)) {
|
||||
if (CMD_ARGC == 1) {
|
||||
int coreid = 0;
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], coreid);
|
||||
|
|
|
@ -19,10 +19,14 @@
|
|||
#ifndef OPENOCD_TARGET_SMP_H
|
||||
#define OPENOCD_TARGET_SMP_H
|
||||
|
||||
#include <helper/list.h>
|
||||
#include "server/server.h"
|
||||
|
||||
#define foreach_smp_target(pos, head) \
|
||||
for (pos = head; (pos); pos = pos->next)
|
||||
list_for_each_entry(pos, head, lh)
|
||||
|
||||
#define foreach_smp_target_direction(forward, pos, head) \
|
||||
list_for_each_entry_direction(forward, pos, head, lh)
|
||||
|
||||
extern const struct command_registration smp_command_handlers[];
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "rtos/rtos.h"
|
||||
#include "transport/transport.h"
|
||||
#include "arm_cti.h"
|
||||
#include "smp.h"
|
||||
|
||||
/* default halt wait timeout (ms) */
|
||||
#define DEFAULT_HALT_TIMEOUT 5000
|
||||
|
@ -159,6 +160,7 @@ static int64_t target_timer_next_event_value;
|
|||
static LIST_HEAD(target_reset_callback_list);
|
||||
static LIST_HEAD(target_trace_callback_list);
|
||||
static const int polling_interval = TARGET_DEFAULT_POLLING_INTERVAL;
|
||||
static LIST_HEAD(empty_smp_targets);
|
||||
|
||||
static const struct jim_nvp nvp_assert[] = {
|
||||
{ .name = "assert", NVP_ASSERT },
|
||||
|
@ -236,6 +238,15 @@ static const struct jim_nvp nvp_target_event[] = {
|
|||
|
||||
{ .value = TARGET_EVENT_TRACE_CONFIG, .name = "trace-config" },
|
||||
|
||||
{ .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x100, .name = "semihosting-user-cmd-0x100" },
|
||||
{ .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x101, .name = "semihosting-user-cmd-0x101" },
|
||||
{ .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x102, .name = "semihosting-user-cmd-0x102" },
|
||||
{ .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x103, .name = "semihosting-user-cmd-0x103" },
|
||||
{ .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x104, .name = "semihosting-user-cmd-0x104" },
|
||||
{ .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x105, .name = "semihosting-user-cmd-0x105" },
|
||||
{ .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x106, .name = "semihosting-user-cmd-0x106" },
|
||||
{ .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x107, .name = "semihosting-user-cmd-0x107" },
|
||||
|
||||
{ .name = NULL, .value = -1 }
|
||||
};
|
||||
|
||||
|
@ -2272,13 +2283,15 @@ static void target_destroy(struct target *target)
|
|||
|
||||
/* release the targets SMP list */
|
||||
if (target->smp) {
|
||||
struct target_list *head = target->head;
|
||||
while (head) {
|
||||
struct target_list *pos = head->next;
|
||||
struct target_list *head, *tmp;
|
||||
|
||||
list_for_each_entry_safe(head, tmp, target->smp_targets, lh) {
|
||||
list_del(&head->lh);
|
||||
head->target->smp = 0;
|
||||
free(head);
|
||||
head = pos;
|
||||
}
|
||||
if (target->smp_targets != &empty_smp_targets)
|
||||
free(target->smp_targets);
|
||||
target->smp = 0;
|
||||
}
|
||||
|
||||
|
@ -5782,6 +5795,9 @@ static int target_create(struct jim_getopt_info *goi)
|
|||
return JIM_ERR;
|
||||
}
|
||||
|
||||
/* set empty smp cluster */
|
||||
target->smp_targets = &empty_smp_targets;
|
||||
|
||||
/* set target number */
|
||||
target->target_number = new_target_number();
|
||||
|
||||
|
@ -5995,9 +6011,7 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
|||
int retval, len;
|
||||
static int smp_group = 1;
|
||||
struct target *target = NULL;
|
||||
struct target_list *head, *curr, *new;
|
||||
curr = NULL;
|
||||
head = NULL;
|
||||
struct target_list *head, *new;
|
||||
|
||||
retval = 0;
|
||||
LOG_DEBUG("%d", argc);
|
||||
|
@ -6006,6 +6020,13 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
|||
* argv[3] ...
|
||||
*/
|
||||
|
||||
struct list_head *lh = malloc(sizeof(*lh));
|
||||
if (!lh) {
|
||||
LOG_ERROR("Out of memory");
|
||||
return JIM_ERR;
|
||||
}
|
||||
INIT_LIST_HEAD(lh);
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
|
||||
targetname = Jim_GetString(argv[i], &len);
|
||||
|
@ -6014,24 +6035,15 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
|||
if (target) {
|
||||
new = malloc(sizeof(struct target_list));
|
||||
new->target = target;
|
||||
new->next = NULL;
|
||||
if (!head) {
|
||||
head = new;
|
||||
curr = head;
|
||||
} else {
|
||||
curr->next = new;
|
||||
curr = new;
|
||||
}
|
||||
list_add_tail(&new->lh, lh);
|
||||
}
|
||||
}
|
||||
/* now parse the list of cpu and put the target in smp mode*/
|
||||
curr = head;
|
||||
|
||||
while (curr) {
|
||||
target = curr->target;
|
||||
foreach_smp_target(head, lh) {
|
||||
target = head->target;
|
||||
target->smp = smp_group;
|
||||
target->head = head;
|
||||
curr = curr->next;
|
||||
target->smp = 1;
|
||||
target->smp_targets = lh;
|
||||
}
|
||||
smp_group++;
|
||||
|
||||
|
|
|
@ -201,7 +201,9 @@ struct target {
|
|||
* and must be detected when symbols are offered */
|
||||
struct backoff_timer backoff;
|
||||
int smp; /* add some target attributes for smp support */
|
||||
struct target_list *head;
|
||||
struct list_head *smp_targets; /* list all targets in this smp group/cluster
|
||||
* The head of the list is shared between the
|
||||
* cluster, thus here there is a pointer */
|
||||
/* the gdb service is there in case of smp, we have only one gdb server
|
||||
* for all smp target
|
||||
* the target attached to the gdb is changing dynamically by changing
|
||||
|
@ -220,8 +222,8 @@ struct target {
|
|||
};
|
||||
|
||||
struct target_list {
|
||||
struct list_head lh;
|
||||
struct target *target;
|
||||
struct target_list *next;
|
||||
};
|
||||
|
||||
struct gdb_fileio_info {
|
||||
|
@ -294,6 +296,15 @@ enum target_event {
|
|||
TARGET_EVENT_GDB_FLASH_WRITE_END,
|
||||
|
||||
TARGET_EVENT_TRACE_CONFIG,
|
||||
|
||||
TARGET_EVENT_SEMIHOSTING_USER_CMD_0x100 = 0x100, /* semihosting allows user cmds from 0x100 to 0x1ff */
|
||||
TARGET_EVENT_SEMIHOSTING_USER_CMD_0x101 = 0x101,
|
||||
TARGET_EVENT_SEMIHOSTING_USER_CMD_0x102 = 0x102,
|
||||
TARGET_EVENT_SEMIHOSTING_USER_CMD_0x103 = 0x103,
|
||||
TARGET_EVENT_SEMIHOSTING_USER_CMD_0x104 = 0x104,
|
||||
TARGET_EVENT_SEMIHOSTING_USER_CMD_0x105 = 0x105,
|
||||
TARGET_EVENT_SEMIHOSTING_USER_CMD_0x106 = 0x106,
|
||||
TARGET_EVENT_SEMIHOSTING_USER_CMD_0x107 = 0x107,
|
||||
};
|
||||
|
||||
struct target_event_action {
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Microchip LAN9255 evaluation board
|
||||
# https://www.microchip.com/en-us/development-tool/EV25Y25A
|
||||
#
|
||||
|
||||
set CHIPNAME same53
|
||||
|
||||
source [find target/atsame5x.cfg]
|
||||
|
||||
reset_config srst_only
|
|
@ -0,0 +1,14 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# NXP LS1088ARDB (Reference Design Board)
|
||||
# This is for the "main" JTAG connector J55
|
||||
|
||||
transport select jtag
|
||||
reset_config srst_only
|
||||
|
||||
# To access the CPLD, populate J48 and add `-c 'set CWTAP 1'` to your command
|
||||
# line. At the time of this writing, programming is unsupported.
|
||||
if { [info exists CWTAP] } {
|
||||
source [find cpld/altera-epm240.cfg]
|
||||
} else {
|
||||
source [find target/ls1088a.cfg]
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Cadence virtual debug interface
|
||||
# Arm Cortex A53x2 through JTAG
|
||||
|
||||
source [find interface/vdebug.cfg]
|
||||
|
||||
set _CORES 2
|
||||
set _CHIPNAME a53
|
||||
set _MEMSTART 0x00000000
|
||||
set _MEMSIZE 0x1000000
|
||||
set _CPUTAPID 0x5ba00477
|
||||
|
||||
# vdebug select transport
|
||||
#transport select jtag
|
||||
|
||||
# JTAG reset config, frequency and reset delay
|
||||
reset_config trst_and_srst
|
||||
adapter speed 50000
|
||||
adapter srst delay 5
|
||||
|
||||
# BFM hierarchical path and input clk period
|
||||
vdebug bfm_path tbench.u_vd_jtag_bfm 10ns
|
||||
|
||||
# DMA Memories to access backdoor (up to 4)
|
||||
vdebug mem_path tbench.u_memory.mem_array $_MEMSTART $_MEMSIZE
|
||||
|
||||
jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
|
||||
|
||||
jtag arp_init-reset
|
||||
|
||||
source [find target/vd_aarch64.cfg]
|
|
@ -0,0 +1,30 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Cadence virtual debug interface
|
||||
# Arm Cortex m4 through JTAG
|
||||
|
||||
source [find interface/vdebug.cfg]
|
||||
|
||||
set _CHIPNAME m4
|
||||
set _MEMSTART 0x00000000
|
||||
set _MEMSIZE 0x10000
|
||||
set _CPUTAPID 0x4ba00477
|
||||
|
||||
# vdebug select transport
|
||||
#transport select jtag
|
||||
|
||||
# JTAG reset config, frequency and reset delay
|
||||
reset_config trst_and_srst
|
||||
adapter speed 25000
|
||||
adapter srst delay 5
|
||||
|
||||
# BFM hierarchical path and input clk period
|
||||
vdebug bfm_path tbench.u_vd_jtag_bfm 20ns
|
||||
|
||||
# DMA Memories to access backdoor (up to 4)
|
||||
vdebug mem_path tbench.u_mcu.u_sys.u_rom.rom $_MEMSTART $_MEMSIZE
|
||||
|
||||
jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
|
||||
|
||||
jtag arp_init-reset
|
||||
|
||||
source [find target/vd_cortex_m.cfg]
|
|
@ -0,0 +1,32 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Cadence virtual debug interface
|
||||
# RISCV Ibex core with Pulpissimo through JTAG
|
||||
|
||||
source [find interface/vdebug.cfg]
|
||||
|
||||
set _CHIPNAME ibex
|
||||
set _HARTID 0x20
|
||||
set _CPUTAPID 0x249511c3
|
||||
|
||||
# vdebug select transport
|
||||
#transport select jtag
|
||||
|
||||
# JTAG reset config, frequency and reset delay
|
||||
reset_config trst_and_srst
|
||||
adapter speed 12500
|
||||
adapter srst delay 10
|
||||
|
||||
# BFM hierarchical path and input clk period
|
||||
vdebug bfm_path tbench.u_vd_jtag_bfm 40ns
|
||||
|
||||
# DMA Memories to access backdoor (up to 4)
|
||||
vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[0\].sram_i.mem_array 0x1c000000 0x8000
|
||||
vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[1\].sram_i.mem_array 0x1c008000 0x8000
|
||||
vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2\[0\].sram_i.mem_array 0x1c010000 0x80000
|
||||
|
||||
# need to explicitly define riscv tap, autoprobing does not work for icapture != 0x01
|
||||
jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x05 -irmask 0x1f -expected-id $_CPUTAPID
|
||||
|
||||
jtag arp_init-reset
|
||||
|
||||
source [find target/vd_riscv.cfg]
|
|
@ -0,0 +1,32 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Cadence virtual debug interface
|
||||
# RISCV swerv core with Swerv through JTAG
|
||||
|
||||
source [find interface/vdebug.cfg]
|
||||
|
||||
set _CHIPNAME rv32
|
||||
set _HARTID 0x00
|
||||
set _CPUTAPID 0x1000008b
|
||||
set _MEMSTART 0x00000000
|
||||
set _MEMSIZE 0x10000
|
||||
|
||||
# vdebug select transport
|
||||
#transport select jtag
|
||||
|
||||
# JTAG reset config, frequency and reset delay
|
||||
reset_config trst_and_srst
|
||||
adapter speed 50000
|
||||
adapter srst delay 5
|
||||
|
||||
# BFM hierarchical path and input clk period
|
||||
vdebug bfm_path tbench.u_vd_jtag_bfm 10ns
|
||||
|
||||
# DMA Memories to access backdoor (up to 4)
|
||||
vdebug mem_path tbench.i_ahb_ic.mem $_MEMSTART $_MEMSIZE
|
||||
|
||||
# need to explicitly define riscv tap, autoprobing does not work for icapture != 0x01
|
||||
jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x01 -irmask 0x1f -expected-id $_CPUTAPID
|
||||
|
||||
jtag arp_init-reset
|
||||
|
||||
source [find target/vd_riscv.cfg]
|
|
@ -1,6 +1,23 @@
|
|||
# Altera MAXII EPM240T100C CPLD
|
||||
|
||||
if { [info exists CHIPNAME] } {
|
||||
set _CHIPNAME $CHIPNAME
|
||||
} else {
|
||||
set _CHIPNAME epm240
|
||||
}
|
||||
|
||||
# see MAX II Device Handbook
|
||||
# Table 3-3: 32-Bit MAX II Device IDCODE
|
||||
# Version Part Number Manuf. ID LSB
|
||||
# 0000 0010 0000 1010 0001 000 0110 1110 1
|
||||
jtag newtap epm240 tap -expected-id 0x020a10dd -irlen 10
|
||||
jtag newtap $_CHIPNAME tap -irlen 10 \
|
||||
-expected-id 0x020a10dd \
|
||||
-expected-id 0x020a20dd \
|
||||
-expected-id 0x020a30dd \
|
||||
-expected-id 0x020a40dd \
|
||||
-expected-id 0x020a50dd \
|
||||
-expected-id 0x020a60dd
|
||||
|
||||
# 200ns seems like a good speed
|
||||
# c.f. Table 5-34: MAX II JTAG Timing Parameters
|
||||
adapter speed 5000
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Cadence virtual debug interface
|
||||
|
||||
if { [info exists VDEBUGHOST] } {
|
||||
set _VDEBUGHOST $VDEBUGHOST
|
||||
} else {
|
||||
set _VDEBUGHOST localhost
|
||||
}
|
||||
if { [info exists VDEBUGPORT] } {
|
||||
set _VDEBUGPORT $VDEBUGPORT
|
||||
} else {
|
||||
set _VDEBUGPORT 8192
|
||||
}
|
||||
|
||||
adapter driver vdebug
|
||||
# vdebug server:port
|
||||
vdebug server $_VDEBUGHOST:$_VDEBUGPORT
|
||||
|
||||
# example config debug level and log
|
||||
#debug_level 3
|
||||
#log_output vd_ocd.log
|
||||
|
||||
# example config listen on all interfaces, disable tcl/telnet server
|
||||
bindto 0.0.0.0
|
||||
#gdb_port 3333
|
||||
#telnet_port disabled
|
||||
tcl_port disabled
|
||||
|
||||
# transaction batching: 0 - no batching, 1 - (default) wr, 2 - rw
|
||||
vdebug batching 1
|
||||
|
||||
# Polling values
|
||||
vdebug polling 100 1000
|
|
@ -0,0 +1,74 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# NXP LS1088A
|
||||
|
||||
if { [info exists CHIPNAME] } {
|
||||
set _CHIPNAME $CHIPNAME
|
||||
} else {
|
||||
set _CHIPNAME ls1088a
|
||||
}
|
||||
|
||||
if { [info exists DAP_TAPID] } {
|
||||
set _DAP_TAPID $DAP_TAPID
|
||||
} else {
|
||||
set _DAP_TAPID 0x5ba00477
|
||||
}
|
||||
|
||||
jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID
|
||||
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap
|
||||
|
||||
target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 1
|
||||
|
||||
set _CPU_BASE 0x81000000
|
||||
set _CPU_STRIDE 0x100000
|
||||
set _CPU_DBGOFF 0x10000
|
||||
set _CPU_CTIOFF 0x20000
|
||||
|
||||
set _TARGETS {}
|
||||
for {set i 0} {$i < 8} {incr i} {
|
||||
set _BASE [expr {$_CPU_BASE + $_CPU_STRIDE * $i}]
|
||||
cti create $_CHIPNAME.cti$i -dap $_CHIPNAME.dap -ap-num 0 \
|
||||
-baseaddr [expr {$_BASE + $_CPU_CTIOFF}]
|
||||
target create $_CHIPNAME.cpu$i aarch64 -dap $_CHIPNAME.dap \
|
||||
-cti $_CHIPNAME.cti$i -dbgbase [expr {$_BASE + $_CPU_DBGOFF}] \
|
||||
{*}[expr {$i ? "-coreid $i" : "-rtos hwthread" }]
|
||||
lappend _TARGETS $_CHIPNAME.cpu$i
|
||||
}
|
||||
|
||||
target smp {*}$_TARGETS
|
||||
|
||||
# Service processor
|
||||
target create $_CHIPNAME.sp cortex_a -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80138000
|
||||
|
||||
# Normally you will not need to call this, but if you are using the hard-coded
|
||||
# Reset Configuration Word (RCW) you will need to call this manually. The CPU's
|
||||
# reset vector is 0, and the boot ROM at that location contains ARMv7-A 32-bit
|
||||
# instructions. This will cause the CPU to almost immediately execute an
|
||||
# illegal instruction.
|
||||
#
|
||||
# This code is idempotent; releasing a released CPU has no effect, although it
|
||||
# will halt/resume the service processor.
|
||||
add_help_text release_cpu "Release a cpu which is held off"
|
||||
proc release_cpu {cpu} {
|
||||
set RST_BRRL 0x1e60060
|
||||
|
||||
set old [target current]
|
||||
targets $::_CHIPNAME.sp
|
||||
set not_halted [string compare halted [$::_CHIPNAME.sp curstate]]
|
||||
if {$not_halted} {
|
||||
halt
|
||||
}
|
||||
|
||||
# Release the cpu; it will start executing something bogus
|
||||
mem2array regs 32 $RST_BRRL 1
|
||||
mww $RST_BRRL [expr {$regs(0) | 1 << $cpu}]
|
||||
|
||||
if {$not_halted} {
|
||||
resume
|
||||
}
|
||||
targets $old
|
||||
}
|
||||
|
||||
targets $_CHIPNAME.cpu0
|
||||
|
||||
# Seems to work OK in testing
|
||||
adapter speed 10000
|
|
@ -0,0 +1,37 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Cadence virtual debug interface
|
||||
# Arm v8 64b Cortex A
|
||||
|
||||
if {![info exists _CORES]} {
|
||||
set _CORES 1
|
||||
}
|
||||
if {![info exists _CHIPNAME]} {
|
||||
set _CHIPNAME aarch64
|
||||
}
|
||||
set _TARGETNAME $_CHIPNAME.cpu
|
||||
set _CTINAME $_CHIPNAME.cti
|
||||
|
||||
set DBGBASE {0x80810000 0x80910000}
|
||||
set CTIBASE {0x80820000 0x80920000}
|
||||
|
||||
dap create $_CHIPNAME.dap -chain-position $_TARGETNAME
|
||||
$_CHIPNAME.dap apsel 1
|
||||
|
||||
for { set _core 0 } { $_core < $_CORES } { incr _core } \
|
||||
{
|
||||
cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 -baseaddr [lindex $CTIBASE $_core]
|
||||
set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \
|
||||
-dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core -coreid $_core"
|
||||
if { $_core != 0 } {
|
||||
# non-boot core examination may fail
|
||||
set _command "$_command -defer-examine"
|
||||
set _smp_command "$_smp_command $_TARGETNAME.$_core"
|
||||
} else {
|
||||
set _smp_command "target smp $_TARGETNAME.$_core"
|
||||
}
|
||||
eval $_command
|
||||
}
|
||||
eval $_smp_command
|
||||
|
||||
# default target is core 0
|
||||
targets $_TARGETNAME.0
|
|
@ -0,0 +1,12 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Cadence virtual debug interface
|
||||
# ARM Cortex M
|
||||
|
||||
if {![info exists _CHIPNAME]} {
|
||||
set _CHIPNAME cortex_m
|
||||
}
|
||||
set _TARGETNAME $_CHIPNAME.cpu
|
||||
|
||||
dap create $_CHIPNAME.dap -chain-position $_TARGETNAME
|
||||
|
||||
target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap
|
|
@ -0,0 +1,18 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Cadence virtual debug interface
|
||||
# RISCV core
|
||||
|
||||
if {![info exists _HARTID]} {
|
||||
set _HARTID 0x00
|
||||
}
|
||||
if {![info exists _CHIPNAME]} {
|
||||
set _CHIPNAME riscv
|
||||
}
|
||||
set _TARGETNAME $_CHIPNAME.cpu
|
||||
|
||||
target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid $_HARTID
|
||||
|
||||
riscv set_reset_timeout_sec 120
|
||||
riscv set_command_timeout_sec 120
|
||||
# prefer to use sba for system bus access
|
||||
riscv set_prefer_sba on
|
Loading…
Reference in New Issue